Merge pull request #64 in ITERATE/cyberduck from feature/windows/9074 to master
[cyberduck.git] / source / ch / cyberduck / core / Path.java
blob008e9328b73965a621730e206bbaaa03b6819b1d
1 package ch.cyberduck.core;
3 /*
4 * Copyright (c) 2005 David Kocher. All rights reserved.
5 * http://cyberduck.ch/
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * Bug fixes, suggestions and comments should be sent to:
18 * dkocher@cyberduck.ch
21 import ch.cyberduck.core.serializer.Serializer;
23 import java.util.EnumSet;
24 import java.util.Objects;
26 /**
27 * @version $Id$
29 public class Path extends AbstractPath implements Referenceable, Serializable {
31 /**
32 * The path delimiter for remote paths
34 public static final char DELIMITER = '/';
35 /**
36 * Reference to the parent
38 protected Path parent;
39 /**
40 * The absolute remote path
42 private String path;
43 /**
44 * An absolute reference here the symbolic link is pointing to
46 private Path symlink;
47 /**
48 * The file type
50 private EnumSet<Type> type
51 = EnumSet.noneOf(Type.class);
53 /**
54 * Attributes denoting this path
56 private PathAttributes attributes;
58 /**
59 * @param parent the absolute directory
60 * @param name the file relative to param path
61 * @param type File type
63 public Path(final Path parent, final String name, final EnumSet<Type> type) {
64 this.type = type;
65 this.attributes = new PathAttributes();
66 this.attributes.setRegion(parent.attributes.getRegion());
67 this._setPath(parent, name);
70 /**
71 * @param absolute The absolute path of the remote file
72 * @param type File type
74 public Path(final String absolute, final EnumSet<Type> type) {
75 this.type = type;
76 this.attributes = new PathAttributes();
77 this.setPath(absolute);
80 /**
81 * @param absolute The absolute path of the remote file
82 * @param attributes File type
84 public Path(final String absolute, final EnumSet<Type> type, final PathAttributes attributes) {
85 this.type = type;
86 this.attributes = attributes;
87 this.setPath(absolute);
90 /**
91 * @param parent Parent path reference
92 * @param name Filename
93 * @param attributes Attributes
95 public Path(final Path parent, final String name, final EnumSet<Type> type, final PathAttributes attributes) {
96 this.type = type;
97 this.attributes = attributes;
98 this._setPath(parent, name);
101 @Override
102 public <T> T serialize(final Serializer dict) {
103 dict.setStringForKey(String.valueOf(type), "Type");
104 dict.setStringForKey(this.getAbsolute(), "Remote");
105 if(symlink != null) {
106 dict.setObjectForKey(symlink, "Symbolic Link");
108 dict.setObjectForKey(attributes, "Attributes");
109 return dict.getSerialized();
112 private void setPath(final String absolute) {
113 if(absolute.equals(String.valueOf(Path.DELIMITER))) {
114 this._setPath(null, PathNormalizer.name(absolute));
116 else {
117 final Path parent = new Path(PathNormalizer.parent(PathNormalizer.normalize(absolute, true), Path.DELIMITER),
118 EnumSet.of(Type.directory));
119 parent.attributes().setRegion(attributes.getRegion());
120 if(parent.isRoot()) {
121 parent.setType(EnumSet.of(Type.volume, Type.directory));
123 this._setPath(parent, PathNormalizer.name(absolute));
127 private void _setPath(final Path parent, final String name) {
128 this.parent = parent;
129 if(null == parent) {
130 this.path = name;
132 else {
133 if(parent.isRoot()) {
134 this.path = parent.getAbsolute() + name;
136 else {
137 if(name.startsWith(String.valueOf(DELIMITER))) {
138 this.path = parent.getAbsolute() + name;
140 else {
141 this.path = parent.getAbsolute() + Path.DELIMITER + name;
147 @Override
148 public EnumSet<Type> getType() {
149 return type;
152 public void setType(final EnumSet<Type> type) {
153 this.type = type;
156 public boolean isVolume() {
157 return type.contains(Type.volume);
160 public boolean isDirectory() {
161 return type.contains(Type.directory);
164 public boolean isPlaceholder() {
165 return type.contains(Type.placeholder);
168 public boolean isFile() {
169 return type.contains(Type.file);
172 public boolean isSymbolicLink() {
173 return type.contains(Type.symboliclink);
176 @Override
177 public char getDelimiter() {
178 return String.valueOf(DELIMITER).charAt(0);
181 public Path getParent() {
182 if(this.isRoot()) {
183 return this;
185 return parent;
188 public PathAttributes attributes() {
189 return attributes;
193 * @return the path relative to its parent directory
195 @Override
196 public String getName() {
197 if(this.isRoot()) {
198 return String.valueOf(DELIMITER);
200 final String abs = this.getAbsolute();
201 int index = abs.lastIndexOf(DELIMITER);
202 return abs.substring(index + 1);
206 * @return the absolute path name, e.g. /home/user/filename
208 @Override
209 public String getAbsolute() {
210 return path;
214 * @return The target of the symbolic link if this path denotes a symbolic link
215 * @see #isSymbolicLink
217 public Path getSymlinkTarget() {
218 return symlink;
221 public void setSymlinkTarget(final Path target) {
222 this.symlink = target;
226 * @return The hashcode of #getAbsolute()
227 * @see #getAbsolute()
229 @Override
230 public int hashCode() {
231 return new DefaultPathReference(this).hashCode();
235 * @param other Path to compare with
236 * @return true if the other path has the same absolute path name
238 @Override
239 public boolean equals(Object other) {
240 if(null == other) {
241 return false;
243 if(other instanceof Path) {
244 return new DefaultPathReference(this).equals(new DefaultPathReference((Path) other));
246 return false;
250 * @return The absolute path name
252 @Override
253 public String toString() {
254 final StringBuilder sb = new StringBuilder("Path{");
255 sb.append("path='").append(path).append('\'');
256 sb.append(", type=").append(type);
257 sb.append('}');
258 return sb.toString();
262 * @param directory Parent directory
263 * @return True if this is a child in the path hierarchy of the argument passed
265 public boolean isChild(final Path directory) {
266 if(directory.isFile()) {
267 // If a file we don't have any children at all
268 return false;
270 if(this.isRoot()) {
271 // Root cannot be a child of any other path
272 return false;
274 if(directory.isRoot()) {
275 // Any other path is a child
276 return true;
278 if(Objects.equals(this.getParent(), directory.getParent())) {
279 // Cannot be a child if the same parent
280 return false;
282 for(Path parent = this.getParent(); !parent.isRoot(); parent = parent.getParent()) {
283 if(parent.equals(directory)) {
284 return true;
287 return false;