eu.stratosphere.core.fs.Path Maven / Gradle / Ivy
/***********************************************************************************************************************
* Copyright (C) 2010-2013 by the Stratosphere project (http://stratosphere.eu)
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
**********************************************************************************************************************/
/**
* This file is based on source code from the Hadoop Project (http://hadoop.apache.org/), licensed by the Apache
* Software Foundation (ASF) under the Apache License, Version 2.0. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*/
package eu.stratosphere.core.fs;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.net.URI;
import java.net.URISyntaxException;
import eu.stratosphere.core.io.IOReadableWritable;
import eu.stratosphere.core.io.StringRecord;
import eu.stratosphere.util.OperatingSystem;
import eu.stratosphere.util.StringUtils;
/**
* Names a file or directory in a {@link FileSystem}. Path strings use slash as
* the directory separator. A path string is absolute if it begins with a slash.
*/
public class Path implements IOReadableWritable, Serializable {
private static final long serialVersionUID = 1L;
/**
* The directory separator, a slash.
*/
public static final String SEPARATOR = "/";
/**
* The directory separator, a slash (character).
*/
public static final char SEPARATOR_CHAR = '/';
/**
* Character denoting the current directory.
*/
public static final String CUR_DIR = ".";
/**
* The internal representation of the path, a hierarchical URI.
*/
private URI uri;
/**
* Constructs a new (empty) path object (used to reconstruct path object after RPC call).
*/
public Path() {}
/**
* Constructs a path object from a given URI.
*
* @param uri
* the URI to contruct the path object from
*/
public Path(URI uri) {
this.uri = uri;
}
/**
* Resolve a child path against a parent path.
*
* @param parent
* the parent path
* @param child
* the child path
*/
public Path(String parent, String child) {
this(new Path(parent), new Path(child));
}
/**
* Resolve a child path against a parent path.
*
* @param parent
* the parent path
* @param child
* the child path
*/
public Path(Path parent, String child) {
this(parent, new Path(child));
}
/**
* Resolve a child path against a parent path.
*
* @param parent
* the parent path
* @param child
* the child path
*/
public Path(String parent, Path child) {
this(new Path(parent), child);
}
/**
* Resolve a child path against a parent path.
*
* @param parent
* the parent path
* @param child
* the child path
*/
public Path(Path parent, Path child) {
// Add a slash to parent's path so resolution is compatible with URI's
URI parentUri = parent.uri;
final String parentPath = parentUri.getPath();
if (!(parentPath.equals("/") || parentPath.equals(""))) {
try {
parentUri = new URI(parentUri.getScheme(), parentUri.getAuthority(), parentUri.getPath() + "/", null,
null);
} catch (URISyntaxException e) {
throw new IllegalArgumentException(e);
}
}
if (child.uri.getPath().startsWith(Path.SEPARATOR)) {
child = new Path(child.uri.getScheme(), child.uri.getAuthority(), child.uri.getPath().substring(1));
}
final URI resolved = parentUri.resolve(child.uri);
initialize(resolved.getScheme(), resolved.getAuthority(), normalizePath(resolved.getPath()));
}
/**
* Checks if the provided path string is either null or has zero length and throws
* a {@link IllegalArgumentException} if any of the two conditions apply.
*
* @param path
* the path string to be checked
*/
private void checkPathArg(String path) {
// disallow construction of a Path from an empty string
if (path == null) {
throw new IllegalArgumentException("Can not create a Path from a null string");
}
if (path.length() == 0) {
throw new IllegalArgumentException("Can not create a Path from an empty string");
}
}
/**
* Construct a path from a String. Path strings are URIs, but with unescaped
* elements and some additional normalization.
*
* @param pathString
* the string to construct a path from
*/
public Path(String pathString) {
checkPathArg(pathString);
// We can't use 'new URI(String)' directly, since it assumes things are
// escaped, which we don't require of Paths.
// add a slash in front of paths with Windows drive letters
if (hasWindowsDrive(pathString, false)) {
pathString = "/" + pathString;
}
// parse uri components
String scheme = null;
String authority = null;
int start = 0;
// parse uri scheme, if any
final int colon = pathString.indexOf(':');
final int slash = pathString.indexOf('/');
if ((colon != -1) && ((slash == -1) || (colon < slash))) { // has a
// scheme
scheme = pathString.substring(0, colon);
start = colon + 1;
}
// parse uri authority, if any
if (pathString.startsWith("//", start) && (pathString.length() - start > 2)) { // has authority
final int nextSlash = pathString.indexOf('/', start + 2);
final int authEnd = nextSlash > 0 ? nextSlash : pathString.length();
authority = pathString.substring(start + 2, authEnd);
start = authEnd;
}
// uri path is the rest of the string -- query & fragment not supported
final String path = pathString.substring(start, pathString.length());
initialize(scheme, authority, path);
}
/**
* Construct a Path from a scheme, an authority and a path string.
*
* @param scheme
* the scheme string
* @param authority
* the authority string
* @param path
* the path string
*/
public Path(String scheme, String authority, String path) {
checkPathArg(path);
initialize(scheme, authority, path);
}
/**
* Initializes a path object given the scheme, authority and path string.
*
* @param scheme
* the scheme string.
* @param authority
* the authority string.
* @param path
* the path string.
*/
private void initialize(String scheme, String authority, String path) {
try {
this.uri = new URI(scheme, authority, normalizePath(path), null, null).normalize();
} catch (URISyntaxException e) {
throw new IllegalArgumentException(e);
}
}
/**
* Normalizes a path string.
*
* @param path
* the path string to normalize
* @return the normalized path string
*/
private String normalizePath(String path) {
// remove double slashes & backslashes
path = path.replace("//", "/");
path = path.replace("\\", "/");
return path;
}
/**
* Checks if the provided path string contains a windows drive letter.
*
* @param path
* the path to check
* @param slashed
* true
to indicate the first character of the string is a slash, false
otherwise
* @return true
if the path string contains a windows drive letter, false
otherwise
*/
private boolean hasWindowsDrive(String path, boolean slashed) {
if (!OperatingSystem.isWindows()) {
return false;
}
final int start = slashed ? 1 : 0;
return path.length() >= start + 2
&& (slashed ? path.charAt(0) == '/' : true)
&& path.charAt(start + 1) == ':'
&& ((path.charAt(start) >= 'A' && path.charAt(start) <= 'Z') || (path.charAt(start) >= 'a' && path
.charAt(start) <= 'z'));
}
/**
* Converts the path object to a {@link URI}.
*
* @return the {@link URI} object converted from the path object
*/
public URI toUri() {
return uri;
}
/**
* Returns the FileSystem that owns this Path.
*
* @return the FileSystem that owns this Path
* @throws IOException
* thrown if the file system could not be retrieved
*/
public FileSystem getFileSystem() throws IOException {
return FileSystem.get(this.toUri());
}
/**
* Checks if the directory of this path is absolute.
*
* @return true
if the directory of this path is absolute, false
otherwise
*/
public boolean isAbsolute() {
final int start = hasWindowsDrive(uri.getPath(), true) ? 3 : 0;
return uri.getPath().startsWith(SEPARATOR, start);
}
/**
* Returns the final component of this path.
*
* @return the final component of the path
*/
public String getName() {
final String path = uri.getPath();
final int slash = path.lastIndexOf(SEPARATOR);
return path.substring(slash + 1);
}
/**
* Returns the parent of a path or null
if at root.
*
* @return the parent of a path or null
if at root.
*/
public Path getParent() {
final String path = uri.getPath();
final int lastSlash = path.lastIndexOf('/');
final int start = hasWindowsDrive(path, true) ? 3 : 0;
if ((path.length() == start) || // empty path
(lastSlash == start && path.length() == start + 1)) { // at root
return null;
}
String parent;
if (lastSlash == -1) {
parent = CUR_DIR;
} else {
final int end = hasWindowsDrive(path, true) ? 3 : 0;
parent = path.substring(0, lastSlash == end ? end + 1 : lastSlash);
}
return new Path(uri.getScheme(), uri.getAuthority(), parent);
}
/**
* Adds a suffix to the final name in the path.
*
* @param suffix The suffix to be added
* @return the new path including the suffix
*/
public Path suffix(String suffix) {
return new Path(getParent(), getName() + suffix);
}
@Override
public String toString() {
// we can't use uri.toString(), which escapes everything, because we
// want
// illegal characters unescaped in the string, for glob processing, etc.
final StringBuffer buffer = new StringBuffer();
if (uri.getScheme() != null) {
buffer.append(uri.getScheme());
buffer.append(":");
}
if (uri.getAuthority() != null) {
buffer.append("//");
buffer.append(uri.getAuthority());
}
if (uri.getPath() != null) {
String path = uri.getPath();
if (path.indexOf('/') == 0 && hasWindowsDrive(path, true) && // has
// windows
// drive
uri.getScheme() == null && // but no scheme
uri.getAuthority() == null) { // or authority
path = path.substring(1); // remove slash before drive
}
buffer.append(path);
}
return buffer.toString();
}
@Override
public boolean equals(Object o) {
if (!(o instanceof Path)) {
return false;
}
Path that = (Path) o;
return this.uri.equals(that.uri);
}
@Override
public int hashCode() {
return uri.hashCode();
}
public int compareTo(Object o) {
Path that = (Path) o;
return this.uri.compareTo(that.uri);
}
/**
* Returns the number of elements in this path.
*
* @return the number of elements in this path
*/
public int depth() {
String path = uri.getPath();
int depth = 0;
int slash = path.length() == 1 && path.charAt(0) == '/' ? -1 : 0;
while (slash != -1) {
depth++;
slash = path.indexOf(SEPARATOR, slash + 1);
}
return depth;
}
/**
* Returns a qualified path object.
*
* @param fs
* the FileSystem that should be used to obtain the current working directory
* @return the qualified path object
*/
public Path makeQualified(FileSystem fs) {
Path path = this;
if (!isAbsolute()) {
path = new Path(fs.getWorkingDirectory(), this);
}
final URI pathUri = path.toUri();
final URI fsUri = fs.getUri();
String scheme = pathUri.getScheme();
String authority = pathUri.getAuthority();
if (scheme != null && (authority != null || fsUri.getAuthority() == null)) {
return path;
}
if (scheme == null) {
scheme = fsUri.getScheme();
}
if (authority == null) {
authority = fsUri.getAuthority();
if (authority == null) {
authority = "";
}
}
return new Path(scheme + ":" + "//" + authority + pathUri.getPath());
}
@Override
public void read(DataInput in) throws IOException {
final boolean isNotNull = in.readBoolean();
if (isNotNull) {
final String scheme = StringRecord.readString(in);
final String userInfo = StringRecord.readString(in);
final String host = StringRecord.readString(in);
final int port = in.readInt();
final String path = StringRecord.readString(in);
final String query = StringRecord.readString(in);
final String fragment = StringRecord.readString(in);
try {
uri = new URI(scheme, userInfo, host, port, path, query, fragment);
} catch (URISyntaxException e) {
throw new IOException("Error reconstructing URI: " + StringUtils.stringifyException(e));
}
}
}
@Override
public void write(DataOutput out) throws IOException {
if (uri == null) {
out.writeBoolean(false);
} else {
out.writeBoolean(true);
StringRecord.writeString(out, uri.getScheme());
StringRecord.writeString(out, uri.getUserInfo());
StringRecord.writeString(out, uri.getHost());
out.writeInt(uri.getPort());
StringRecord.writeString(out, uri.getPath());
StringRecord.writeString(out, uri.getQuery());
StringRecord.writeString(out, uri.getFragment());
}
}
public static String constructTestPath(String folder) {
String path = System.getProperty("java.io.tmpdir");
if (!(path.endsWith("/") || path.endsWith("\\")) ) {
path += System.getProperty("file.separator");
}
path += folder;
return path;
}
public static String constructTestURI(String folder) {
return new File(constructTestPath(folder)).toURI().toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy