001    /*
002     * JBoss DNA (http://www.jboss.org/dna)
003     * See the COPYRIGHT.txt file distributed with this work for information
004     * regarding copyright ownership.  Some portions may be licensed
005     * to Red Hat, Inc. under one or more contributor license agreements.
006     * See the AUTHORS.txt file in the distribution for a full listing of 
007     * individual contributors. 
008     *
009     * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
010     * is licensed to you under the terms of the GNU Lesser General Public License as
011     * published by the Free Software Foundation; either version 2.1 of
012     * the License, or (at your option) any later version.
013     *
014     * JBoss DNA is distributed in the hope that it will be useful,
015     * but WITHOUT ANY WARRANTY; without even the implied warranty of
016     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017     * Lesser General Public License for more details.
018     *
019     * You should have received a copy of the GNU Lesser General Public
020     * License along with this software; if not, write to the Free
021     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
022     * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
023     */
024    package org.jboss.dna.graph.property.basic;
025    
026    import java.util.Collections;
027    import java.util.Iterator;
028    import java.util.List;
029    import net.jcip.annotations.Immutable;
030    import org.jboss.dna.common.text.Inflector;
031    import org.jboss.dna.common.text.TextEncoder;
032    import org.jboss.dna.common.util.CheckArg;
033    import org.jboss.dna.graph.GraphI18n;
034    import org.jboss.dna.graph.property.InvalidPathException;
035    import org.jboss.dna.graph.property.NamespaceRegistry;
036    import org.jboss.dna.graph.property.Path;
037    
038    /**
039     * Optimized implementation of {@link Path} that serves as the root path.
040     * 
041     * @author Randall Hauch
042     */
043    @Immutable
044    public class RootPath extends AbstractPath {
045    
046        /**
047         * The serializable version. Version {@value}
048         */
049        private static final long serialVersionUID = 1L;
050    
051        public static final Path INSTANCE = new RootPath();
052    
053        private static final Path.Segment[] EMPTY_SEGMENT_ARRAY = new Path.Segment[] {};
054        private static final List<Path.Segment> EMPTY_SEGMENT_LIST = Collections.emptyList();
055    
056        private RootPath() {
057        }
058    
059        /**
060         * {@inheritDoc}
061         * 
062         * @see org.jboss.dna.graph.property.Path#getAncestor(int)
063         */
064        public Path getAncestor( int degree ) {
065            CheckArg.isNonNegative(degree, "degree");
066            if (degree == 0) {
067                return this;
068            }
069            String msg = GraphI18n.pathAncestorDegreeIsInvalid.text(this.getString(), Inflector.getInstance().ordinalize(degree));
070            throw new InvalidPathException(msg);
071        }
072    
073        /**
074         * {@inheritDoc}
075         * 
076         * @see org.jboss.dna.graph.property.basic.AbstractPath#getSegmentsOfParent()
077         */
078        @Override
079        protected Iterator<Segment> getSegmentsOfParent() {
080            return EMPTY_PATH_ITERATOR;
081        }
082    
083        /**
084         * {@inheritDoc}
085         * 
086         * @see org.jboss.dna.graph.property.Path#getCanonicalPath()
087         */
088        @Override
089        public Path getCanonicalPath() {
090            return this;
091        }
092    
093        /**
094         * {@inheritDoc}
095         * 
096         * @see org.jboss.dna.graph.property.Path#getCommonAncestor(org.jboss.dna.graph.property.Path)
097         */
098        @Override
099        public Path getCommonAncestor( Path that ) {
100            CheckArg.isNotNull(that, "that");
101            return this;
102        }
103    
104        /**
105         * {@inheritDoc}
106         * 
107         * @see org.jboss.dna.graph.property.Path#getLastSegment()
108         */
109        @Override
110        public Segment getLastSegment() {
111            return null;
112        }
113    
114        /**
115         * {@inheritDoc}
116         * 
117         * @see org.jboss.dna.graph.property.Path#getNormalizedPath()
118         */
119        @Override
120        public Path getNormalizedPath() {
121            return this;
122        }
123    
124        /**
125         * {@inheritDoc}
126         * 
127         * @see org.jboss.dna.graph.property.basic.AbstractPath#resolve(org.jboss.dna.graph.property.Path)
128         */
129        @Override
130        public Path resolve( Path relativePath ) {
131            CheckArg.isNotNull(relativePath, "relative path");
132            if (relativePath.isAbsolute()) {
133                String msg = GraphI18n.pathIsNotRelative.text(relativePath);
134                throw new InvalidPathException(msg);
135            }
136            // Make an absolute path out of the supplied relative path ...
137            return new BasicPath(relativePath.getSegmentsList(), true).getNormalizedPath();
138        }
139    
140        /**
141         * {@inheritDoc}
142         * 
143         * @see org.jboss.dna.graph.property.Path#getParent()
144         */
145        @Override
146        public Path getParent() {
147            return null;
148        }
149    
150        /**
151         * {@inheritDoc}
152         * 
153         * @see org.jboss.dna.graph.property.Path#getSegment(int)
154         */
155        @Override
156        public Segment getSegment( int index ) {
157            CheckArg.isNonNegative(index, "index");
158            EMPTY_SEGMENT_LIST.get(index); // throws IndexOutOfBoundsException
159            return null;
160        }
161    
162        /**
163         * {@inheritDoc}
164         * 
165         * @see org.jboss.dna.graph.property.Path#getSegmentsArray()
166         */
167        @Override
168        public Segment[] getSegmentsArray() {
169            // Can return the same array every time, since it's empty ...
170            return EMPTY_SEGMENT_ARRAY;
171        }
172    
173        /**
174         * {@inheritDoc}
175         * 
176         * @see org.jboss.dna.graph.property.Path#getSegmentsList()
177         */
178        public List<Segment> getSegmentsList() {
179            return EMPTY_SEGMENT_LIST;
180        }
181    
182        /**
183         * {@inheritDoc}
184         * 
185         * @see org.jboss.dna.graph.property.Path#getString()
186         */
187        @Override
188        public String getString() {
189            return Path.DELIMITER_STR;
190        }
191    
192        /**
193         * {@inheritDoc}
194         * 
195         * @see org.jboss.dna.graph.property.Path#getString(org.jboss.dna.common.text.TextEncoder)
196         */
197        @Override
198        public String getString( TextEncoder encoder ) {
199            return Path.DELIMITER_STR;
200        }
201    
202        /**
203         * {@inheritDoc}
204         * 
205         * @see org.jboss.dna.graph.property.Path#getString(org.jboss.dna.graph.property.NamespaceRegistry)
206         */
207        @Override
208        public String getString( NamespaceRegistry namespaceRegistry ) {
209            CheckArg.isNotNull(namespaceRegistry, "namespaceRegistry");
210            return Path.DELIMITER_STR;
211        }
212    
213        /**
214         * {@inheritDoc}
215         * 
216         * @see org.jboss.dna.graph.property.Path#getString(org.jboss.dna.graph.property.NamespaceRegistry,
217         *      org.jboss.dna.common.text.TextEncoder)
218         */
219        @Override
220        public String getString( NamespaceRegistry namespaceRegistry,
221                                 TextEncoder encoder ) {
222            CheckArg.isNotNull(namespaceRegistry, "namespaceRegistry");
223            return Path.DELIMITER_STR;
224        }
225    
226        /**
227         * {@inheritDoc}
228         * 
229         * @see org.jboss.dna.graph.property.Path#getString(org.jboss.dna.graph.property.NamespaceRegistry,
230         *      org.jboss.dna.common.text.TextEncoder, org.jboss.dna.common.text.TextEncoder)
231         */
232        @Override
233        public String getString( NamespaceRegistry namespaceRegistry,
234                                 TextEncoder encoder,
235                                 TextEncoder delimiterEncoder ) {
236            return (delimiterEncoder == null) ? DELIMITER_STR : delimiterEncoder.encode(DELIMITER_STR);
237        }
238    
239        /**
240         * {@inheritDoc}
241         * 
242         * @see org.jboss.dna.graph.property.Path#hasSameAncestor(org.jboss.dna.graph.property.Path)
243         */
244        @Override
245        public boolean hasSameAncestor( Path that ) {
246            CheckArg.isNotNull(that, "that");
247            return true;
248        }
249    
250        /**
251         * {@inheritDoc}
252         * 
253         * @see org.jboss.dna.graph.property.Path#isAbsolute()
254         */
255        public boolean isAbsolute() {
256            return true;
257        }
258    
259        /**
260         * {@inheritDoc}
261         * 
262         * @see org.jboss.dna.graph.property.Path#isAncestorOf(org.jboss.dna.graph.property.Path)
263         */
264        @Override
265        public boolean isAncestorOf( Path decendant ) {
266            CheckArg.isNotNull(decendant, "decendant");
267            return !decendant.isRoot();
268        }
269    
270        /**
271         * {@inheritDoc}
272         * 
273         * @see org.jboss.dna.graph.property.Path#isAtOrAbove(org.jboss.dna.graph.property.Path)
274         */
275        @Override
276        public boolean isAtOrAbove( Path other ) {
277            CheckArg.isNotNull(other, "other");
278            return true;
279        }
280    
281        /**
282         * {@inheritDoc}
283         * 
284         * @see org.jboss.dna.graph.property.Path#isAtOrBelow(org.jboss.dna.graph.property.Path)
285         */
286        @Override
287        public boolean isAtOrBelow( Path other ) {
288            CheckArg.isNotNull(other, "other");
289            return other.isRoot();
290        }
291    
292        /**
293         * {@inheritDoc}
294         * 
295         * @see org.jboss.dna.graph.property.Path#isDecendantOf(org.jboss.dna.graph.property.Path)
296         */
297        @Override
298        public boolean isDecendantOf( Path ancestor ) {
299            CheckArg.isNotNull(ancestor, "ancestor");
300            return false;
301        }
302    
303        /**
304         * {@inheritDoc}
305         * 
306         * @see org.jboss.dna.graph.property.Path#isNormalized()
307         */
308        public boolean isNormalized() {
309            return true;
310        }
311    
312        /**
313         * {@inheritDoc}
314         * 
315         * @see org.jboss.dna.graph.property.Path#isRoot()
316         */
317        public boolean isRoot() {
318            return true;
319        }
320    
321        /**
322         * {@inheritDoc}
323         * 
324         * @see org.jboss.dna.graph.property.Path#isSameAs(org.jboss.dna.graph.property.Path)
325         */
326        @Override
327        public boolean isSameAs( Path other ) {
328            CheckArg.isNotNull(other, "other");
329            return other.isRoot();
330        }
331    
332        /**
333         * {@inheritDoc}
334         * 
335         * @see org.jboss.dna.graph.property.Path#iterator()
336         */
337        @Override
338        public Iterator<Segment> iterator() {
339            return EMPTY_SEGMENT_LIST.iterator();
340        }
341    
342        /**
343         * {@inheritDoc}
344         * 
345         * @see org.jboss.dna.graph.property.Path#pathsFromRoot()
346         */
347        @Override
348        public Iterator<Path> pathsFromRoot() {
349            return new SingleIterator<Path>(this);
350        }
351    
352        /**
353         * {@inheritDoc}
354         * 
355         * @see org.jboss.dna.graph.property.Path#size()
356         */
357        public int size() {
358            return 0;
359        }
360    
361        /**
362         * {@inheritDoc}
363         * 
364         * @see org.jboss.dna.graph.property.Path#subpath(int)
365         */
366        @Override
367        public Path subpath( int beginIndex ) {
368            CheckArg.isNonNegative(beginIndex, "beginIndex");
369            if (beginIndex == 0) return this;
370            EMPTY_SEGMENT_LIST.get(1); // throws IndexOutOfBoundsException
371            return null;
372        }
373    
374        /**
375         * {@inheritDoc}
376         * 
377         * @see org.jboss.dna.graph.property.Path#subpath(int, int)
378         */
379        @Override
380        public Path subpath( int beginIndex,
381                             int endIndex ) {
382            CheckArg.isNonNegative(beginIndex, "beginIndex");
383            CheckArg.isNonNegative(endIndex, "endIndex");
384            if (endIndex >= 1) {
385                EMPTY_SEGMENT_LIST.get(endIndex); // throws IndexOutOfBoundsException
386            }
387            return this;
388        }
389    
390        /**
391         * {@inheritDoc}
392         * 
393         * @see java.lang.Comparable#compareTo(java.lang.Object)
394         */
395        @Override
396        public int compareTo( Path other ) {
397            return other.isRoot() ? 0 : -1;
398        }
399    
400        /**
401         * {@inheritDoc}
402         * 
403         * @see java.lang.Object#equals(java.lang.Object)
404         */
405        @Override
406        public boolean equals( Object obj ) {
407            if (obj == this) return true;
408            if (obj instanceof Path) {
409                Path that = (Path)obj;
410                return that.isRoot();
411            }
412            return false;
413        }
414    
415    }