KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > alfresco > service > cmr > repository > Path


1 /*
2  * Copyright (C) 2005 Alfresco, Inc.
3  *
4  * Licensed under the Mozilla Public License version 1.1
5  * with a permitted attribution clause. You may obtain a
6  * copy of the License at
7  *
8  * http://www.alfresco.org/legal/license.txt
9  *
10  * Unless required by applicable law or agreed to in writing,
11  * software distributed under the License is distributed on an
12  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13  * either express or implied. See the License for the specific
14  * language governing permissions and limitations under the
15  * License.
16  */

17 package org.alfresco.service.cmr.repository;
18
19 import java.io.Serializable JavaDoc;
20 import java.util.Iterator JavaDoc;
21 import java.util.LinkedList JavaDoc;
22
23 import org.alfresco.model.ContentModel;
24 import org.alfresco.repo.security.permissions.AccessDeniedException;
25 import org.alfresco.service.namespace.NamespacePrefixResolver;
26 import org.alfresco.service.namespace.QName;
27 import org.alfresco.util.ISO9075;
28
29 /**
30  * Representation of a simple path e.g.
31  * <b><pre>
32  * /x/y/z
33  * </pre></b>
34  * In the above example, there will be <b>4</b> elements, the first being a reference
35  * to the root node, followed by qname elements for <b>x</b>, <b>x</b> and <b>z</b>.
36  * <p>
37  * Methods and constructors are available to construct a <code>Path</code> instance
38  * from a path string or by building the path incrementally, including the ability to
39  * append and prepend path elements.
40  * <p>
41  * Path elements supported:
42  * <ul>
43  * <li><b>/{namespace}name</b> fully qualified element</li>
44  * <li><b>/name</b> element using default namespace</li>
45  * <li><b>/{namespace}name[n]</b> nth sibling</li>
46  * <li><b>/name[n]</b> nth sibling using default namespace</li>
47  * <li><b>/descendant-or-self::node()</b> descendent or self</li>
48  * <li><b>/.</b> self</li>
49  * <li><b>/..</b> parent</li>
50  * </ul>
51  *
52  * @author Derek Hulley
53  */

54 public final class Path implements Iterable JavaDoc<Path.Element>, Serializable JavaDoc
55 {
56     private static final long serialVersionUID = 3905520514524328247L;
57     private LinkedList JavaDoc<Element> elements;
58     
59     public Path()
60     {
61         // use linked list so as random access is not required, but both prepending and appending is
62
elements = new LinkedList JavaDoc<Element>();
63     }
64     
65     /**
66      * @return Returns a typed iterator over the path elements
67      */

68     public Iterator JavaDoc<Path.Element> iterator()
69     {
70        return elements.iterator();
71     }
72     
73     /**
74      * Add a path element to the beginning of the path. This operation is useful in cases where
75      * a path is built by traversing up a hierarchy.
76      *
77      * @param pathElement
78      * @return Returns this instance of the path
79      */

80     public Path prepend(Path.Element pathElement)
81     {
82         elements.addFirst(pathElement);
83         return this;
84     }
85     
86     /**
87      * Merge the given path into the beginning of this path.
88      *
89      * @param path
90      * @return Returns this instance of the path
91      */

92     public Path prepend(Path path)
93     {
94        elements.addAll(0, path.elements);
95        return this;
96     }
97     
98     /**
99      * Appends a path element to the end of the path
100      *
101      * @param pathElement
102      * @return Returns this instance of the path
103      */

104     public Path append(Path.Element pathElement)
105     {
106         elements.addLast(pathElement);
107         return this;
108     }
109     
110     /**
111      * Append the given path of this path.
112      *
113      * @param path
114      * @return Returns this instance of the path
115      */

116     public Path append(Path path)
117     {
118        elements.addAll(path.elements);
119        return this;
120     }
121     
122     /**
123      * @return Returns the first element in the path or null if the path is empty
124      */

125     public Element first()
126     {
127         return elements.getFirst();
128     }
129     
130     /**
131      * @return Returns the last element in the path or null if the path is empty
132      */

133     public Element last()
134     {
135         return elements.getLast();
136     }
137     
138     public int size()
139     {
140         return elements.size();
141     }
142     
143     public Element get(int n)
144     {
145         return elements.get(n);
146     }
147     
148     /**
149      * @return Returns a string path made up of the component elements of this instance
150      */

151     public String JavaDoc toString()
152     {
153         StringBuilder JavaDoc sb = new StringBuilder JavaDoc(128);
154         for (Element element : elements)
155         {
156             if((sb.length() > 1) || ((sb.length() == 1) && (sb.charAt(0) != '/')))
157             {
158                 sb.append("/");
159             }
160             sb.append(element.getElementString());
161         }
162         return sb.toString();
163     }
164
165     /**
166      * @return Returns a string path made up of the component elements of this instance (prefixed where appropriate)
167      */

168     public String JavaDoc toPrefixString(NamespacePrefixResolver resolver)
169     {
170         StringBuilder JavaDoc sb = new StringBuilder JavaDoc(128);
171         for (Element element : elements)
172         {
173             if((sb.length() > 1) || ((sb.length() == 1) && (sb.charAt(0) != '/')))
174             {
175                 sb.append("/");
176             }
177             sb.append(element.getPrefixedString(resolver));
178         }
179         return sb.toString();
180     }
181     
182     /**
183      * Return the human readable form of the specified node Path. Slow version of the method
184      * that extracts the name of each node in the Path from the supplied NodeService.
185      *
186      * @return human readable form of the Path excluding the final element
187      */

188     public String JavaDoc toDisplayPath(NodeService nodeService)
189     {
190         StringBuilder JavaDoc buf = new StringBuilder JavaDoc(64);
191         
192         for (int i=0; i<elements.size()-1; i++)
193         {
194             String JavaDoc elementString = null;
195             Element element = elements.get(i);
196             if (element instanceof ChildAssocElement)
197             {
198                 ChildAssociationRef elementRef = ((ChildAssocElement)element).getRef();
199                 if (elementRef.getParentRef() != null)
200                 {
201                     Serializable JavaDoc nameProp = null;
202                     try
203                     {
204                         nameProp = nodeService.getProperty(elementRef.getChildRef(), ContentModel.PROP_NAME);
205                     }
206                     catch (AccessDeniedException err)
207                     {
208                         // unable to access this property on the path - so we cannot display it's name
209
}
210                     if (nameProp != null)
211                     {
212                         // use the name property if we find it
213
elementString = nameProp.toString();
214                     }
215                     else
216                     {
217                         // revert to using QName if not found
218
elementString = elementRef.getQName().getLocalName();
219                     }
220                 }
221             }
222             else
223             {
224                 elementString = element.getElementString();
225             }
226             
227             if (elementString != null)
228             {
229                 buf.append("/");
230                 buf.append(elementString);
231             }
232         }
233         
234         return buf.toString();
235     }
236     
237     /**
238      * Return a new Path representing this path to the specified depth
239      *
240      * @param depth the path depth (0 based)
241      * @return the sub-path
242      */

243     public Path subPath(int depth)
244     {
245         return subPath(0, depth);
246     }
247
248     /**
249      * Return a new Path representing this path to the specified depth
250      *
251      * @param depth the path depth (0 based)
252      * @return the sub-path
253      */

254     public Path subPath(int start, int end)
255     {
256         if (start < 0 || start > (elements.size() -1))
257         {
258             throw new IndexOutOfBoundsException JavaDoc("Start index " + start + " must be between 0 and " + (elements.size() -1));
259         }
260         if (end < 0 || end > (elements.size() -1))
261         {
262             throw new IndexOutOfBoundsException JavaDoc("End index " + end + " must be between 0 and " + (elements.size() -1));
263         }
264         if (end < start)
265         {
266             throw new IndexOutOfBoundsException JavaDoc("End index " + end + " cannot be before start index " + start);
267         }
268         Path subPath = new Path();
269         for (int i = start; i <= end; i++)
270         {
271             subPath.append(this.get(i));
272         }
273         return subPath;
274     }
275     
276     /**
277      * Override equals to check equality of Path instances
278      */

279     public boolean equals(Object JavaDoc o)
280     {
281         if(o == this)
282         {
283             return true;
284         }
285         if(!(o instanceof Path))
286         {
287             return false;
288         }
289         Path other = (Path)o;
290         return this.elements.equals(other.elements);
291     }
292
293     /**
294      * Override hashCode to check hash equality of Path instances
295      */

296     public int hashCode()
297     {
298         return elements.hashCode();
299     }
300     
301     /**
302      * Represents a path element.
303      * <p>
304      * In <b>/x/y/z</b>, elements are <b>x</b>, <b>y</b> and <b>z</b>.
305      */

306     public abstract static class Element implements Serializable JavaDoc
307     {
308         /**
309          * @return Returns the path element portion including leading '/' and never null
310          */

311         public abstract String JavaDoc getElementString();
312
313         /**
314          * @param resolver namespace prefix resolver
315          * @return the path element portion (with namespaces converted to prefixes)
316          */

317         public String JavaDoc getPrefixedString(NamespacePrefixResolver resolver)
318         {
319             return getElementString();
320         }
321         
322         /**
323          * @see #getElementString()
324          */

325         public String JavaDoc toString()
326         {
327             return getElementString();
328         }
329     }
330     
331     /**
332      * Represents a qualified path between a parent and a child node,
333      * including the sibling to retrieve e.g. <b>/{namespace}name[5]</b>
334      */

335     public static class ChildAssocElement extends Element
336     {
337         private static final long serialVersionUID = 3689352104636790840L;
338
339         private ChildAssociationRef ref;
340         
341         /**
342          * @param ref a reference to the specific parent-child association
343          */

344         public ChildAssocElement(ChildAssociationRef ref)
345         {
346             this.ref = ref;
347         }
348
349         @Override JavaDoc
350         public String JavaDoc getElementString()
351         {
352             return createElementString(null);
353         }
354
355         @Override JavaDoc
356         public String JavaDoc getPrefixedString(NamespacePrefixResolver resolver)
357         {
358             return createElementString(resolver);
359         }
360
361         public ChildAssociationRef getRef()
362         {
363             return ref;
364         }
365         
366         @Override JavaDoc
367         public boolean equals(Object JavaDoc o)
368         {
369             if(o == this)
370             {
371                 return true;
372             }
373             if(!(o instanceof ChildAssocElement))
374             {
375                 return false;
376             }
377             ChildAssocElement other = (ChildAssocElement)o;
378             return this.ref.equals(other.ref);
379         }
380
381         @Override JavaDoc
382         public int hashCode()
383         {
384             return ref.hashCode();
385         }
386         
387         private String JavaDoc createElementString(NamespacePrefixResolver resolver)
388         {
389             StringBuilder JavaDoc sb = new StringBuilder JavaDoc(32);
390             if (ref.getParentRef() == null)
391             {
392                 sb.append("/");
393             }
394             else
395             {
396                 // a parent is present
397
sb.append(resolver == null ? ISO9075.getXPathName(ref.getQName()) : ISO9075.getXPathName(ref.getQName(), resolver));
398             }
399             if (ref.getNthSibling() > -1)
400             {
401                 sb.append("[").append(ref.getNthSibling()).append("]");
402             }
403             return sb.toString();
404         }
405     }
406
407     /**
408      * Represents a qualified path to an attribute,
409      * including the sibling for repeated properties/attributes to retrieve e.g. <b>/@{namespace}name[5]</b>
410      */

411     public static class AttributeElement extends Element
412     {
413         private static final long serialVersionUID = 3256727281668863544L;
414
415         private QName attribute;
416         private int position = -1;
417         
418         /**
419          * @param ref a reference to the specific parent-child association
420          */

421         public AttributeElement(QName attribute)
422         {
423             this.attribute = attribute;
424         }
425         
426         public AttributeElement(QName attribute, int position)
427         {
428             this(attribute);
429             this.position = position;
430         }
431
432         @Override JavaDoc
433         public String JavaDoc getElementString()
434         {
435             return createElementString(null);
436         }
437         
438         @Override JavaDoc
439         public String JavaDoc getPrefixedString(NamespacePrefixResolver resolver)
440         {
441             return createElementString(resolver);
442         }
443         
444         private String JavaDoc createElementString(NamespacePrefixResolver resolver)
445         {
446             StringBuilder JavaDoc sb = new StringBuilder JavaDoc(32);
447             sb.append("@").append(resolver == null ? ISO9075.getXPathName(attribute) : ISO9075.getXPathName(attribute, resolver));
448             
449             if (position > -1)
450             {
451                 sb.append("[").append(position).append("]");
452             }
453             return sb.toString();
454         }
455         
456         public QName getQName()
457         {
458             return attribute;
459         }
460         
461         public int position()
462         {
463             return position;
464         }
465         
466         public boolean equals(Object JavaDoc o)
467         {
468             if(o == this)
469             {
470                 return true;
471             }
472             if(!(o instanceof AttributeElement))
473             {
474                 return false;
475             }
476             AttributeElement other = (AttributeElement)o;
477             return this.getQName().equals(other.getQName()) && (this.position() == other.position());
478         }
479         
480         public int hashCode()
481         {
482             return getQName().hashCode()*32 + position();
483         }
484
485     }
486
487     /**
488      * Represents the <b>//</b> or <b>/descendant-or-self::node()</b> xpath element
489      */

490     public static class DescendentOrSelfElement extends Element
491     {
492         private static final long serialVersionUID = 3258410616875005237L;
493
494         public String JavaDoc getElementString()
495         {
496             return "descendant-or-self::node()";
497         }
498         
499         public boolean equals(Object JavaDoc o)
500         {
501             if(o == this)
502             {
503                 return true;
504             }
505             if(!(o instanceof DescendentOrSelfElement))
506             {
507                 return false;
508             }
509             return true;
510         }
511         
512         public int hashCode()
513         {
514             return "descendant-or-self::node()".hashCode();
515         }
516
517     }
518     
519     /**
520      * Represents the <b>/.</b> xpath element
521      */

522     public static class SelfElement extends Element
523     {
524         private static final long serialVersionUID = 3834311739151300406L;
525
526         public String JavaDoc getElementString()
527         {
528             return ".";
529         }
530         
531         public boolean equals(Object JavaDoc o)
532         {
533             if(o == this)
534             {
535                 return true;
536             }
537             if(!(o instanceof SelfElement))
538             {
539                 return false;
540             }
541             return true;
542         }
543         
544         public int hashCode()
545         {
546             return ".".hashCode();
547         }
548     }
549     
550     /**
551      * Represents the <b>/..</b> xpath element
552      */

553     public static class ParentElement extends Element
554     {
555         private static final long serialVersionUID = 3689915080477456179L;
556
557         public String JavaDoc getElementString()
558         {
559             return "..";
560         }
561         
562         public boolean equals(Object JavaDoc o)
563         {
564             if(o == this)
565             {
566                 return true;
567             }
568             if(!(o instanceof ParentElement))
569             {
570                 return false;
571             }
572             return true;
573         }
574         
575         public int hashCode()
576         {
577             return "..".hashCode();
578         }
579     }
580 }
581
Popular Tags