1 package org
.argeo
.api
.acr
.fs
;
4 import java
.io
.IOException
;
6 import java
.net
.URISyntaxException
;
7 import java
.nio
.file
.LinkOption
;
8 import java
.nio
.file
.Path
;
9 import java
.nio
.file
.WatchEvent
.Kind
;
10 import java
.nio
.file
.WatchEvent
.Modifier
;
11 import java
.nio
.file
.WatchKey
;
12 import java
.nio
.file
.WatchService
;
13 import java
.util
.Arrays
;
14 import java
.util
.Iterator
;
15 import java
.util
.NoSuchElementException
;
17 public abstract class AbstractFsPath
<FS
extends AbstractFsSystem
<ST
>, ST
extends AbstractFsStore
> implements Path
{
19 /** null for non absolute paths */
20 private final ST fileStore
;
22 private final String
[] segments
;// null means root
23 private final boolean absolute
;
25 private final String separator
;
28 private final int hashCode
;
30 public AbstractFsPath(FS filesSystem
, String path
) {
32 throw new IllegalArgumentException("Path cannot be null");
33 this.fs
= filesSystem
;
34 this.separator
= fs
.getSeparator();
35 // TODO deal with both path and separator being empty strings
36 if (path
.equals(separator
)) {// root
40 this.fileStore
= fs
.getBaseFileStore();
42 } else if (path
.equals("")) {// empty path
43 this.segments
= new String
[] { "" };
44 this.absolute
= false;
45 this.hashCode
= "".hashCode();
46 this.fileStore
= null;
50 this.absolute
= path
.startsWith(toStringRoot());
52 String trimmedPath
= path
.substring(absolute ?
toStringRoot().length() : 0,
53 path
.endsWith(separator
) ? path
.length() - separator
.length() : path
.length());
54 this.segments
= trimmedPath
.split(separator
);
56 for (int i
= 0; i
< this.segments
.length
; i
++) {
57 this.segments
[i
] = cleanUpSegment(this.segments
[i
]);
59 this.hashCode
= this.segments
[this.segments
.length
- 1].hashCode();
61 this.fileStore
= isAbsolute() ? fs
.getFileStore(path
) : null;
64 protected AbstractFsPath(FS filesSystem
, ST fileStore
, String
[] segments
, boolean absolute
) {
65 this.segments
= segments
;
66 this.absolute
= absolute
;
67 this.hashCode
= segments
== null ?
0 : segments
[segments
.length
- 1].hashCode();
68 this.separator
= filesSystem
.getSeparator();
69 // super(path, path == null ? true : absolute, filesSystem.getSeparator());
70 // assert path == null ? absolute == true : true;
71 this.fs
= filesSystem
;
73 // this.absolute = path == null ? true : absolute;
74 if (isAbsolute() && fileStore
== null)
75 throw new IllegalArgumentException("Absolute path requires a file store");
76 if (!isAbsolute() && fileStore
!= null)
77 throw new IllegalArgumentException("A file store should not be provided for a relative path");
78 this.fileStore
= fileStore
;
79 assert !(absolute
&& fileStore
== null);
82 protected Path
retrieve(String path
) {
83 return getFileSystem().getPath(path
);
87 public FS
getFileSystem() {
91 public ST
getFileStore() {
96 public boolean isAbsolute() {
103 return new URI(fs
.provider().getScheme(), toString(), null);
104 } catch (URISyntaxException e
) {
105 throw new IllegalStateException("Cannot create URI for " + toString(), e
);
110 public Path
toAbsolutePath() {
113 // FIXME it doesn't seem right
114 return newInstance(getSegments(), true);
118 public Path
toRealPath(LinkOption
... options
) throws IOException
{
123 public File
toFile() {
124 throw new UnsupportedOperationException();
130 public final Path
resolveSibling(Path other
) {
132 throw new NullPointerException();
133 Path parent
= getParent();
134 return (parent
== null) ? other
: parent
.resolve(other
);
138 public final Path
resolveSibling(String other
) {
139 return resolveSibling(getFileSystem().getPath(other
));
142 public final Path
resolve(String other
) {
143 return resolve(retrieve(other
));
146 public boolean startsWith(Path other
) {
147 return toString().startsWith(other
.toString());
150 public boolean endsWith(Path other
) {
151 return toString().endsWith(other
.toString());
155 public Path
normalize() {
161 public final Iterator
<Path
> iterator() {
162 return new Iterator
<Path
>() {
166 public boolean hasNext() {
167 return (i
< getNameCount());
172 if (i
< getNameCount()) {
173 Path result
= getName(i
);
177 throw new NoSuchElementException();
182 public void remove() {
183 throw new UnsupportedOperationException();
189 public int compareTo(Path other
) {
190 return toString().compareTo(other
.toString());
193 public Path
resolve(Path other
) {
194 AbstractFsPath
<?
, ?
> otherPath
= (AbstractFsPath
<?
, ?
>) other
;
195 if (otherPath
.isAbsolute())
199 newPath
= new String
[otherPath
.segments
.length
];
200 System
.arraycopy(otherPath
.segments
, 0, newPath
, 0, otherPath
.segments
.length
);
202 newPath
= new String
[segments
.length
+ otherPath
.segments
.length
];
203 System
.arraycopy(segments
, 0, newPath
, 0, segments
.length
);
204 System
.arraycopy(otherPath
.segments
, 0, newPath
, segments
.length
, otherPath
.segments
.length
);
207 return newInstance(newPath
, absolute
);
209 return newInstance(toString(newPath
));
213 public Path
relativize(Path other
) {
215 return newInstance("");
216 if (other
.toString().startsWith(this.toString())) {
217 String p1
= toString();
218 String p2
= other
.toString();
219 String relative
= p2
.substring(p1
.length(), p2
.length());
220 if (relative
.charAt(0) == '/')
221 relative
= relative
.substring(1);
222 return newInstance(relative
);
224 throw new IllegalArgumentException(other
+ " cannot be relativized against " + this);
230 protected abstract AbstractFsPath
<FS
, ST
> newInstance(String path
);
232 protected abstract AbstractFsPath
<FS
, ST
> newInstance(String
[] segments
, boolean absolute
);
237 protected String
toStringRoot() {
241 protected String
cleanUpSegment(String segment
) {
245 protected boolean isRoot() {
246 return segments
== null;
249 protected boolean isEmpty() {
250 return segments
.length
== 1 && "".equals(segments
[0]);
256 public AbstractFsPath
<FS
, ST
> getRoot() {
257 return newInstance(toStringRoot());
260 public AbstractFsPath
<FS
, ST
> getParent() {
264 if (segments
.length
== 1)// first level
265 return newInstance(toStringRoot());
266 String
[] parentPath
= Arrays
.copyOfRange(segments
, 0, segments
.length
- 1);
268 return newInstance(parentPath
, absolute
);
270 return newInstance(toString(parentPath
));
273 public AbstractFsPath
<FS
, ST
> getFileName() {
276 return newInstance(segments
[segments
.length
- 1]);
279 public int getNameCount() {
282 return segments
.length
;
285 public AbstractFsPath
<FS
, ST
> getName(int index
) {
288 return newInstance(segments
[index
]);
291 public AbstractFsPath
<FS
, ST
> subpath(int beginIndex
, int endIndex
) {
294 String
[] parentPath
= Arrays
.copyOfRange(segments
, beginIndex
, endIndex
);
295 return newInstance(parentPath
, false);
298 public boolean startsWith(String other
) {
299 return toString().startsWith(other
);
302 public boolean endsWith(String other
) {
303 return toString().endsWith(other
);
309 protected String
toString(String
[] path
) {
311 return toStringRoot();
312 StringBuilder sb
= new StringBuilder();
314 sb
.append(separator
);
315 for (int i
= 0; i
< path
.length
; i
++) {
317 sb
.append(separator
);
320 return sb
.toString();
324 public String
toString() {
325 return toString(segments
);
329 public int hashCode() {
334 public boolean equals(Object obj
) {
335 if (!(obj
instanceof AbstractFsPath
))
337 AbstractFsPath
<?
, ?
> other
= (AbstractFsPath
<?
, ?
>) obj
;
339 if (isRoot()) {// root
340 if (other
.isRoot())// root
345 if (other
.isRoot())// root
349 if (segments
.length
!= other
.segments
.length
)
351 for (int i
= 0; i
< segments
.length
; i
++) {
352 if (!segments
[i
].equals(other
.segments
[i
]))
359 protected Object
clone() throws CloneNotSupportedException
{
360 return newInstance(toString());
366 protected String
[] getSegments() {
370 protected String
getSeparator() {
378 public WatchKey
register(WatchService watcher
, Kind
<?
>[] events
, Modifier
... modifiers
) throws IOException
{
379 throw new UnsupportedOperationException();
383 public WatchKey
register(WatchService watcher
, Kind
<?
>... events
) throws IOException
{
384 throw new UnsupportedOperationException();