]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.jcr/src/org/argeo/jcr/fs/JcrPath.java
Improve localization framework.
[lgpl/argeo-commons.git] / org.argeo.jcr / src / org / argeo / jcr / fs / JcrPath.java
1 package org.argeo.jcr.fs;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.net.URI;
6 import java.net.URISyntaxException;
7 import java.nio.file.FileSystem;
8 import java.nio.file.LinkOption;
9 import java.nio.file.Path;
10 import java.nio.file.WatchEvent.Kind;
11 import java.nio.file.WatchEvent.Modifier;
12 import java.nio.file.WatchKey;
13 import java.nio.file.WatchService;
14 import java.util.Arrays;
15 import java.util.Iterator;
16 import java.util.NoSuchElementException;
17
18 import javax.jcr.Node;
19 import javax.jcr.RepositoryException;
20
21 /** A {@link Path} which contains a reference to a JCR {@link Node}. */
22 public class JcrPath implements Path {
23 final static String separator = "/";
24 final static char separatorChar = '/';
25
26 private final JcrFileSystem fs;
27 /** null for non absolute paths */
28 private final WorkspaceFileStore fileStore;
29 private final String[] path;// null means root
30 private final boolean absolute;
31
32 // optim
33 private final int hashCode;
34
35 public JcrPath(JcrFileSystem filesSystem, String path) {
36 this.fs = filesSystem;
37 if (path == null)
38 throw new JcrFsException("Path cannot be null");
39 if (path.equals(separator)) {// root
40 this.path = null;
41 this.absolute = true;
42 this.hashCode = 0;
43 this.fileStore = fs.getBaseFileStore();
44 return;
45 } else if (path.equals("")) {// empty path
46 this.path = new String[] { "" };
47 this.absolute = false;
48 this.fileStore = null;
49 this.hashCode = "".hashCode();
50 return;
51 }
52
53 if (path.equals("~")) {// home
54 path = filesSystem.getUserHomePath();
55 if (path == null)
56 throw new JcrFsException("No home directory available");
57 }
58
59 this.absolute = path.charAt(0) == separatorChar ? true : false;
60
61 this.fileStore = absolute ? fs.getFileStore(path) : null;
62
63 String trimmedPath = path.substring(absolute ? 1 : 0,
64 path.charAt(path.length() - 1) == separatorChar ? path.length() - 1 : path.length());
65 this.path = trimmedPath.split(separator);
66 for (int i = 0; i < this.path.length; i++) {
67 this.path[i] = Text.unescapeIllegalJcrChars(this.path[i]);
68 }
69 this.hashCode = this.path[this.path.length - 1].hashCode();
70 assert !(absolute && fileStore == null);
71 }
72
73 public JcrPath(JcrFileSystem filesSystem, Node node) throws RepositoryException {
74 this(filesSystem, filesSystem.getFileStore(node).toFsPath(node));
75 }
76
77 /** Internal optimisation */
78 private JcrPath(JcrFileSystem filesSystem, WorkspaceFileStore fileStore, String[] path, boolean absolute) {
79 this.fs = filesSystem;
80 this.path = path;
81 this.absolute = path == null ? true : absolute;
82 if (this.absolute && fileStore == null)
83 throw new IllegalArgumentException("Absolute path requires a file store");
84 if (!this.absolute && fileStore != null)
85 throw new IllegalArgumentException("A file store should not be provided for a relative path");
86 this.fileStore = fileStore;
87 this.hashCode = path == null ? 0 : path[path.length - 1].hashCode();
88 assert !(absolute && fileStore == null);
89 }
90
91 @Override
92 public FileSystem getFileSystem() {
93 return fs;
94 }
95
96 @Override
97 public boolean isAbsolute() {
98 return absolute;
99 }
100
101 @Override
102 public Path getRoot() {
103 if (path == null)
104 return this;
105 return new JcrPath(fs, separator);
106 }
107
108 @Override
109 public String toString() {
110 return toFsPath(path);
111 }
112
113 private String toFsPath(String[] path) {
114 if (path == null)
115 return "/";
116 StringBuilder sb = new StringBuilder();
117 if (isAbsolute())
118 sb.append('/');
119 for (int i = 0; i < path.length; i++) {
120 if (i != 0)
121 sb.append('/');
122 sb.append(path[i]);
123 }
124 return sb.toString();
125 }
126
127 // @Deprecated
128 // private String toJcrPath() {
129 // return toJcrPath(path);
130 // }
131 //
132 // @Deprecated
133 // private String toJcrPath(String[] path) {
134 // if (path == null)
135 // return "/";
136 // StringBuilder sb = new StringBuilder();
137 // if (isAbsolute())
138 // sb.append('/');
139 // for (int i = 0; i < path.length; i++) {
140 // if (i != 0)
141 // sb.append('/');
142 // sb.append(Text.escapeIllegalJcrChars(path[i]));
143 // }
144 // return sb.toString();
145 // }
146
147 @Override
148 public Path getFileName() {
149 if (path == null)
150 return null;
151 return new JcrPath(fs, path[path.length - 1]);
152 }
153
154 @Override
155 public Path getParent() {
156 if (path == null)
157 return null;
158 if (path.length == 1)// root
159 return new JcrPath(fs, separator);
160 String[] parentPath = Arrays.copyOfRange(path, 0, path.length - 1);
161 if (!absolute)
162 return new JcrPath(fs, null, parentPath, absolute);
163 else
164 return new JcrPath(fs, toFsPath(parentPath));
165 }
166
167 @Override
168 public int getNameCount() {
169 if (path == null)
170 return 0;
171 return path.length;
172 }
173
174 @Override
175 public Path getName(int index) {
176 if (path == null)
177 return null;
178 return new JcrPath(fs, path[index]);
179 }
180
181 @Override
182 public Path subpath(int beginIndex, int endIndex) {
183 if (path == null)
184 return null;
185 String[] parentPath = Arrays.copyOfRange(path, beginIndex, endIndex);
186 return new JcrPath(fs, null, parentPath, false);
187 }
188
189 @Override
190 public boolean startsWith(Path other) {
191 return toString().startsWith(other.toString());
192 }
193
194 @Override
195 public boolean startsWith(String other) {
196 return toString().startsWith(other);
197 }
198
199 @Override
200 public boolean endsWith(Path other) {
201 return toString().endsWith(other.toString());
202 }
203
204 @Override
205 public boolean endsWith(String other) {
206 return toString().endsWith(other);
207 }
208
209 @Override
210 public Path normalize() {
211 // always normalized
212 return this;
213 }
214
215 @Override
216 public Path resolve(Path other) {
217 JcrPath otherPath = (JcrPath) other;
218 if (otherPath.isAbsolute())
219 return other;
220 String[] newPath;
221 if (path == null) {
222 newPath = new String[otherPath.path.length];
223 System.arraycopy(otherPath.path, 0, newPath, 0, otherPath.path.length);
224 } else {
225 newPath = new String[path.length + otherPath.path.length];
226 System.arraycopy(path, 0, newPath, 0, path.length);
227 System.arraycopy(otherPath.path, 0, newPath, path.length, otherPath.path.length);
228 }
229 if (!absolute)
230 return new JcrPath(fs, null, newPath, absolute);
231 else {
232 return new JcrPath(fs, toFsPath(newPath));
233 }
234 }
235
236 @Override
237 public final Path resolve(String other) {
238 return resolve(getFileSystem().getPath(other));
239 }
240
241 @Override
242 public final Path resolveSibling(Path other) {
243 if (other == null)
244 throw new NullPointerException();
245 Path parent = getParent();
246 return (parent == null) ? other : parent.resolve(other);
247 }
248
249 @Override
250 public final Path resolveSibling(String other) {
251 return resolveSibling(getFileSystem().getPath(other));
252 }
253
254 @Override
255 public final Iterator<Path> iterator() {
256 return new Iterator<Path>() {
257 private int i = 0;
258
259 @Override
260 public boolean hasNext() {
261 return (i < getNameCount());
262 }
263
264 @Override
265 public Path next() {
266 if (i < getNameCount()) {
267 Path result = getName(i);
268 i++;
269 return result;
270 } else {
271 throw new NoSuchElementException();
272 }
273 }
274
275 @Override
276 public void remove() {
277 throw new UnsupportedOperationException();
278 }
279 };
280 }
281
282 @Override
283 public Path relativize(Path other) {
284 if (equals(other))
285 return new JcrPath(fs, "");
286 if (other.startsWith(this)) {
287 String p1 = toString();
288 String p2 = other.toString();
289 String relative = p2.substring(p1.length(), p2.length());
290 if (relative.charAt(0) == '/')
291 relative = relative.substring(1);
292 return new JcrPath(fs, relative);
293 }
294 throw new IllegalArgumentException(other + " cannot be relativized against " + this);
295 }
296
297 @Override
298 public URI toUri() {
299 try {
300 return new URI(fs.provider().getScheme(), toString(), null);
301 } catch (URISyntaxException e) {
302 throw new JcrFsException("Cannot create URI for " + toString(), e);
303 }
304 }
305
306 @Override
307 public Path toAbsolutePath() {
308 if (isAbsolute())
309 return this;
310 return new JcrPath(fs, fileStore, path, true);
311 }
312
313 @Override
314 public Path toRealPath(LinkOption... options) throws IOException {
315 return this;
316 }
317
318 @Override
319 public File toFile() {
320 throw new UnsupportedOperationException();
321 }
322
323 @Override
324 public WatchKey register(WatchService watcher, Kind<?>[] events, Modifier... modifiers) throws IOException {
325 // TODO Auto-generated method stub
326 return null;
327 }
328
329 @Override
330 public WatchKey register(WatchService watcher, Kind<?>... events) throws IOException {
331 // TODO Auto-generated method stub
332 return null;
333 }
334
335 @Override
336 public int compareTo(Path other) {
337 return toString().compareTo(other.toString());
338 }
339
340 public Node getNode() throws RepositoryException {
341 if (!isAbsolute())// TODO default dir
342 throw new JcrFsException("Cannot get a JCR node from a relative path");
343 assert fileStore != null;
344 return fileStore.toNode(path);
345 // String pathStr = toJcrPath();
346 // Session session = fs.getSession();
347 // // TODO synchronize on the session ?
348 // if (!session.itemExists(pathStr))
349 // return null;
350 // return session.getNode(pathStr);
351 }
352
353 @Override
354 public boolean equals(Object obj) {
355 if (!(obj instanceof JcrPath))
356 return false;
357 JcrPath other = (JcrPath) obj;
358
359 if (path == null) {// root
360 if (other.path == null)// root
361 return true;
362 else
363 return false;
364 } else {
365 if (other.path == null)// root
366 return false;
367 }
368 // non root
369 if (path.length != other.path.length)
370 return false;
371 for (int i = 0; i < path.length; i++) {
372 if (!path[i].equals(other.path[i]))
373 return false;
374 }
375 return true;
376 }
377
378 @Override
379 public int hashCode() {
380 return hashCode;
381 }
382
383 @Override
384 protected Object clone() throws CloneNotSupportedException {
385 return new JcrPath(fs, toString());
386 }
387
388 @Override
389 protected void finalize() throws Throwable {
390 Arrays.fill(path, null);
391 }
392
393 }