PageRenderTime 62ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/common/src/java/org/apache/hadoop/fs/Path.java

https://github.com/hyunjung/hadoop-common
Java | 350 lines | 260 code | 41 blank | 49 comment | 37 complexity | 8edb5243ef9902f24935ce05b2d56279 MD5 | raw file
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. package org.apache.hadoop.fs;
  19. import java.net.*;
  20. import java.io.*;
  21. import org.apache.avro.reflect.Stringable;
  22. import org.apache.hadoop.classification.InterfaceAudience;
  23. import org.apache.hadoop.classification.InterfaceStability;
  24. import org.apache.hadoop.conf.Configuration;
  25. /** Names a file or directory in a {@link FileSystem}.
  26. * Path strings use slash as the directory separator. A path string is
  27. * absolute if it begins with a slash.
  28. */
  29. @Stringable
  30. @InterfaceAudience.Public
  31. @InterfaceStability.Stable
  32. public class Path implements Comparable {
  33. /** The directory separator, a slash. */
  34. public static final String SEPARATOR = "/";
  35. public static final char SEPARATOR_CHAR = '/';
  36. public static final String CUR_DIR = ".";
  37. static final boolean WINDOWS
  38. = System.getProperty("os.name").startsWith("Windows");
  39. private URI uri; // a hierarchical uri
  40. /** Resolve a child path against a parent path. */
  41. public Path(String parent, String child) {
  42. this(new Path(parent), new Path(child));
  43. }
  44. /** Resolve a child path against a parent path. */
  45. public Path(Path parent, String child) {
  46. this(parent, new Path(child));
  47. }
  48. /** Resolve a child path against a parent path. */
  49. public Path(String parent, Path child) {
  50. this(new Path(parent), child);
  51. }
  52. /** Resolve a child path against a parent path. */
  53. public Path(Path parent, Path child) {
  54. // Add a slash to parent's path so resolution is compatible with URI's
  55. URI parentUri = parent.uri;
  56. String parentPath = parentUri.getPath();
  57. if (!(parentPath.equals("/") || parentPath.equals("")))
  58. try {
  59. parentUri = new URI(parentUri.getScheme(), parentUri.getAuthority(),
  60. parentUri.getPath()+"/", null, parentUri.getFragment());
  61. } catch (URISyntaxException e) {
  62. throw new IllegalArgumentException(e);
  63. }
  64. URI resolved = parentUri.resolve(child.uri);
  65. initialize(resolved.getScheme(), resolved.getAuthority(),
  66. normalizePath(resolved.getPath()), resolved.getFragment());
  67. }
  68. private void checkPathArg( String path ) {
  69. // disallow construction of a Path from an empty string
  70. if ( path == null ) {
  71. throw new IllegalArgumentException(
  72. "Can not create a Path from a null string");
  73. }
  74. if( path.length() == 0 ) {
  75. throw new IllegalArgumentException(
  76. "Can not create a Path from an empty string");
  77. }
  78. }
  79. /** Construct a path from a String. Path strings are URIs, but with
  80. * unescaped elements and some additional normalization. */
  81. public Path(String pathString) {
  82. checkPathArg( pathString );
  83. // We can't use 'new URI(String)' directly, since it assumes things are
  84. // escaped, which we don't require of Paths.
  85. // add a slash in front of paths with Windows drive letters
  86. if (hasWindowsDrive(pathString, false))
  87. pathString = "/"+pathString;
  88. // parse uri components
  89. String scheme = null;
  90. String authority = null;
  91. int start = 0;
  92. // parse uri scheme, if any
  93. int colon = pathString.indexOf(':');
  94. int slash = pathString.indexOf('/');
  95. if ((colon != -1) &&
  96. ((slash == -1) || (colon < slash))) { // has a scheme
  97. scheme = pathString.substring(0, colon);
  98. start = colon+1;
  99. }
  100. // parse uri authority, if any
  101. if (pathString.startsWith("//", start) &&
  102. (pathString.length()-start > 2)) { // has authority
  103. int nextSlash = pathString.indexOf('/', start+2);
  104. int authEnd = nextSlash > 0 ? nextSlash : pathString.length();
  105. authority = pathString.substring(start+2, authEnd);
  106. start = authEnd;
  107. }
  108. // uri path is the rest of the string -- query & fragment not supported
  109. String path = pathString.substring(start, pathString.length());
  110. initialize(scheme, authority, path, null);
  111. }
  112. /**
  113. * Construct a path from a URI
  114. */
  115. public Path(URI aUri) {
  116. uri = aUri;
  117. }
  118. /** Construct a Path from components. */
  119. public Path(String scheme, String authority, String path) {
  120. checkPathArg( path );
  121. initialize(scheme, authority, path, null);
  122. }
  123. private void initialize(String scheme, String authority, String path,
  124. String fragment) {
  125. try {
  126. this.uri = new URI(scheme, authority, normalizePath(path), null, fragment)
  127. .normalize();
  128. } catch (URISyntaxException e) {
  129. throw new IllegalArgumentException(e);
  130. }
  131. }
  132. private String normalizePath(String path) {
  133. // remove double slashes & backslashes
  134. path = path.replace("//", "/");
  135. path = path.replace("\\", "/");
  136. // trim trailing slash from non-root path (ignoring windows drive)
  137. int minLength = hasWindowsDrive(path, true) ? 4 : 1;
  138. if (path.length() > minLength && path.endsWith("/")) {
  139. path = path.substring(0, path.length()-1);
  140. }
  141. return path;
  142. }
  143. private boolean hasWindowsDrive(String path, boolean slashed) {
  144. if (!WINDOWS) return false;
  145. int start = slashed ? 1 : 0;
  146. return
  147. path.length() >= start+2 &&
  148. (slashed ? path.charAt(0) == '/' : true) &&
  149. path.charAt(start+1) == ':' &&
  150. ((path.charAt(start) >= 'A' && path.charAt(start) <= 'Z') ||
  151. (path.charAt(start) >= 'a' && path.charAt(start) <= 'z'));
  152. }
  153. /** Convert this to a URI. */
  154. public URI toUri() { return uri; }
  155. /** Return the FileSystem that owns this Path. */
  156. public FileSystem getFileSystem(Configuration conf) throws IOException {
  157. return FileSystem.get(this.toUri(), conf);
  158. }
  159. /**
  160. * True if the path component (i.e. directory) of this URI is absolute.
  161. */
  162. public boolean isUriPathAbsolute() {
  163. int start = hasWindowsDrive(uri.getPath(), true) ? 3 : 0;
  164. return uri.getPath().startsWith(SEPARATOR, start);
  165. }
  166. /** True if the path component of this URI is absolute. */
  167. /**
  168. * There is some ambiguity here. An absolute path is a slash
  169. * relative name without a scheme or an authority.
  170. * So either this method was incorrectly named or its
  171. * implementation is incorrect.
  172. */
  173. public boolean isAbsolute() {
  174. return isUriPathAbsolute();
  175. }
  176. /** Returns the final component of this path.*/
  177. public String getName() {
  178. String path = uri.getPath();
  179. int slash = path.lastIndexOf(SEPARATOR);
  180. return path.substring(slash+1);
  181. }
  182. /** Returns the parent of a path or null if at root. */
  183. public Path getParent() {
  184. String path = uri.getPath();
  185. int lastSlash = path.lastIndexOf('/');
  186. int start = hasWindowsDrive(path, true) ? 3 : 0;
  187. if ((path.length() == start) || // empty path
  188. (lastSlash == start && path.length() == start+1)) { // at root
  189. return null;
  190. }
  191. String parent;
  192. if (lastSlash==-1) {
  193. parent = CUR_DIR;
  194. } else {
  195. int end = hasWindowsDrive(path, true) ? 3 : 0;
  196. parent = path.substring(0, lastSlash==end?end+1:lastSlash);
  197. }
  198. return new Path(uri.getScheme(), uri.getAuthority(), parent);
  199. }
  200. /** Adds a suffix to the final name in the path.*/
  201. public Path suffix(String suffix) {
  202. return new Path(getParent(), getName()+suffix);
  203. }
  204. public String toString() {
  205. // we can't use uri.toString(), which escapes everything, because we want
  206. // illegal characters unescaped in the string, for glob processing, etc.
  207. StringBuilder buffer = new StringBuilder();
  208. if (uri.getScheme() != null) {
  209. buffer.append(uri.getScheme());
  210. buffer.append(":");
  211. }
  212. if (uri.getAuthority() != null) {
  213. buffer.append("//");
  214. buffer.append(uri.getAuthority());
  215. }
  216. if (uri.getPath() != null) {
  217. String path = uri.getPath();
  218. if (path.indexOf('/')==0 &&
  219. hasWindowsDrive(path, true) && // has windows drive
  220. uri.getScheme() == null && // but no scheme
  221. uri.getAuthority() == null) // or authority
  222. path = path.substring(1); // remove slash before drive
  223. buffer.append(path);
  224. }
  225. if (uri.getFragment() != null) {
  226. buffer.append("#");
  227. buffer.append(uri.getFragment());
  228. }
  229. return buffer.toString();
  230. }
  231. public boolean equals(Object o) {
  232. if (!(o instanceof Path)) {
  233. return false;
  234. }
  235. Path that = (Path)o;
  236. return this.uri.equals(that.uri);
  237. }
  238. public int hashCode() {
  239. return uri.hashCode();
  240. }
  241. public int compareTo(Object o) {
  242. Path that = (Path)o;
  243. return this.uri.compareTo(that.uri);
  244. }
  245. /** Return the number of elements in this path. */
  246. public int depth() {
  247. String path = uri.getPath();
  248. int depth = 0;
  249. int slash = path.length()==1 && path.charAt(0)=='/' ? -1 : 0;
  250. while (slash != -1) {
  251. depth++;
  252. slash = path.indexOf(SEPARATOR, slash+1);
  253. }
  254. return depth;
  255. }
  256. /**
  257. * Returns a qualified path object.
  258. *
  259. * Deprecated - use {@link #makeQualified(URI, Path)}
  260. */
  261. @Deprecated
  262. public Path makeQualified(FileSystem fs) {
  263. return makeQualified(fs.getUri(), fs.getWorkingDirectory());
  264. }
  265. /** Returns a qualified path object. */
  266. @InterfaceAudience.LimitedPrivate({"HDFS", "MapReduce"})
  267. public Path makeQualified(URI defaultUri, Path workingDir ) {
  268. Path path = this;
  269. if (!isAbsolute()) {
  270. path = new Path(workingDir, this);
  271. }
  272. URI pathUri = path.toUri();
  273. String scheme = pathUri.getScheme();
  274. String authority = pathUri.getAuthority();
  275. String fragment = pathUri.getFragment();
  276. if (scheme != null &&
  277. (authority != null || defaultUri.getAuthority() == null))
  278. return path;
  279. if (scheme == null) {
  280. scheme = defaultUri.getScheme();
  281. }
  282. if (authority == null) {
  283. authority = defaultUri.getAuthority();
  284. if (authority == null) {
  285. authority = "";
  286. }
  287. }
  288. URI newUri = null;
  289. try {
  290. newUri = new URI(scheme, authority ,
  291. normalizePath(pathUri.getPath()), null, fragment);
  292. } catch (URISyntaxException e) {
  293. throw new IllegalArgumentException(e);
  294. }
  295. return new Path(newUri);
  296. }
  297. }