View Javadoc

1   /*
2    * ModeShape (http://www.modeshape.org)
3    * See the COPYRIGHT.txt file distributed with this work for information
4    * regarding copyright ownership.  Some portions may be licensed
5    * to Red Hat, Inc. under one or more contributor license agreements.
6    * See the AUTHORS.txt file in the distribution for a full listing of 
7    * individual contributors. 
8    *
9    * ModeShape is free software. Unless otherwise indicated, all code in ModeShape
10   * is licensed to you under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation; either version 2.1 of
12   * the License, or (at your option) any later version.
13   *
14   * ModeShape is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this software; if not, write to the Free
21   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
23   */
24  package org.modeshape.graph.property.basic;
25  
26  import java.util.ArrayList;
27  import java.util.Collections;
28  import java.util.Iterator;
29  import java.util.List;
30  import java.util.NoSuchElementException;
31  import net.jcip.annotations.Immutable;
32  import org.modeshape.common.collection.ImmutableAppendedList;
33  import org.modeshape.common.util.CheckArg;
34  import org.modeshape.graph.property.Path;
35  
36  /**
37   * Implementation of a {@link Path} that has the information for the last segment but that points to another Path for the parent
38   * information.
39   */
40  @Immutable
41  public class ChildPath extends AbstractPath {
42  
43      /**
44       * The serializable version. Version {@value}
45       */
46      private static final long serialVersionUID = 1L;
47  
48      private final Path parent;
49      private final Path.Segment child;
50      private final int size;
51      private transient List<Segment> cachedSegmentList;
52  
53      public ChildPath( Path parent,
54                        Path.Segment child ) {
55          assert parent != null;
56          assert child != null;
57          this.parent = parent;
58          this.child = child;
59          this.size = this.parent.size() + 1;
60      }
61  
62      /**
63       * {@inheritDoc}
64       * 
65       * @see org.modeshape.graph.property.Path#getAncestor(int)
66       */
67      public Path getAncestor( int degree ) {
68          CheckArg.isNonNegative(degree, "degree");
69          if (degree == 0) return this;
70          if (degree == 1) return parent;
71          return parent.getAncestor(degree - 1);
72      }
73  
74      /**
75       * {@inheritDoc}
76       * 
77       * @see org.modeshape.graph.property.basic.AbstractPath#getSegmentsOfParent()
78       */
79      @Override
80      protected Iterator<Segment> getSegmentsOfParent() {
81          return parent.iterator();
82      }
83  
84      /**
85       * {@inheritDoc}
86       * 
87       * @see org.modeshape.graph.property.Path#getLastSegment()
88       */
89      @Override
90      public Segment getLastSegment() {
91          return child;
92      }
93  
94      /**
95       * {@inheritDoc}
96       * 
97       * @see org.modeshape.graph.property.Path#getParent()
98       */
99      @Override
100     public Path getParent() {
101         return parent;
102     }
103 
104     /**
105      * {@inheritDoc}
106      * 
107      * @see org.modeshape.graph.property.Path#getSegment(int)
108      */
109     @Override
110     public Segment getSegment( int index ) {
111         if (index == (size - 1)) return child;
112         return parent.getSegment(index);
113     }
114 
115     /**
116      * {@inheritDoc}
117      * 
118      * @see org.modeshape.graph.property.Path#getSegmentsList()
119      */
120     public List<Segment> getSegmentsList() {
121         if (cachedSegmentList == null) {
122             // No need to synchronize, since this is idempotent and thus the list will be as well
123             List<Segment> segments = null;
124             if (parent.isRoot()) {
125                 segments = Collections.singletonList(child); // already immutable
126             } else if (size < 4) {
127                 segments = new ArrayList<Segment>(size);
128                 for (Segment segment : parent) {
129                     segments.add(segment);
130                 }
131                 segments.add(child);
132                 segments = Collections.unmodifiableList(segments);
133             } else {
134                 segments = new ImmutableAppendedList<Segment>(parent.getSegmentsList(), child);
135             }
136             cachedSegmentList = segments;
137         }
138         return cachedSegmentList;
139     }
140 
141     /**
142      * {@inheritDoc}
143      * 
144      * @see org.modeshape.graph.property.Path#hasSameAncestor(org.modeshape.graph.property.Path)
145      */
146     @Override
147     public boolean hasSameAncestor( Path that ) {
148         CheckArg.isNotNull(that, "that");
149         if (parent.equals(that.getParent())) return true;
150         return super.hasSameAncestor(that);
151     }
152 
153     /**
154      * {@inheritDoc}
155      * 
156      * @see org.modeshape.graph.property.Path#isAbsolute()
157      */
158     public boolean isAbsolute() {
159         return parent.isAbsolute();
160     }
161 
162     /**
163      * {@inheritDoc}
164      * 
165      * @see org.modeshape.graph.property.Path#isAtOrBelow(org.modeshape.graph.property.Path)
166      */
167     @Override
168     public boolean isAtOrBelow( Path other ) {
169         if (this == other || parent == other) return true;
170         return super.isAtOrBelow(other);
171     }
172 
173     /**
174      * {@inheritDoc}
175      * 
176      * @see org.modeshape.graph.property.Path#isDecendantOf(org.modeshape.graph.property.Path)
177      */
178     @Override
179     public boolean isDecendantOf( Path ancestor ) {
180         if (parent == ancestor) return true; // same instance
181         return parent.isAtOrBelow(ancestor);
182     }
183 
184     /**
185      * {@inheritDoc}
186      * 
187      * @see org.modeshape.graph.property.Path#isNormalized()
188      */
189     public boolean isNormalized() {
190         if (child.isSelfReference()) return false;
191         if (!parent.isNormalized()) return false;
192         // Otherwise, the parent is normalized, so this child will be normalized if this child is not a parent reference ...
193         if (!child.isParentReference()) return true;
194         // The path ends with a parent reference. It is normalized only if all other path segments are parent references ...
195         for (Path.Segment segment : parent) {
196             if (!segment.isParentReference()) return false;
197         }
198         return true;
199     }
200 
201     /**
202      * {@inheritDoc}
203      * 
204      * @see org.modeshape.graph.property.Path#isRoot()
205      */
206     public boolean isRoot() {
207         if (child.isParentReference()) return parent.isRoot();
208         return false;
209     }
210 
211     /**
212      * {@inheritDoc}
213      * 
214      * @see org.modeshape.graph.property.Path#iterator()
215      */
216     @Override
217     @SuppressWarnings( "synthetic-access" )
218     public Iterator<Segment> iterator() {
219         if (parent.isRoot()) {
220             return new Iterator<Segment>() {
221                 boolean finished = false;
222 
223                 public boolean hasNext() {
224                     return !finished;
225                 }
226 
227                 public Segment next() {
228                     if (finished) throw new NoSuchElementException();
229                     finished = true;
230                     return ChildPath.this.child;
231                 }
232 
233                 public void remove() {
234                     throw new UnsupportedOperationException();
235                 }
236             };
237         }
238         final Iterator<Segment> parentIterator = parent.iterator();
239         return new Iterator<Segment>() {
240             boolean finished = false;
241 
242             public boolean hasNext() {
243                 return parentIterator.hasNext() || !finished;
244             }
245 
246             public Segment next() {
247                 if (parentIterator.hasNext()) return parentIterator.next();
248                 if (finished) throw new NoSuchElementException();
249                 finished = true;
250                 return ChildPath.this.child;
251             }
252 
253             public void remove() {
254                 throw new UnsupportedOperationException();
255             }
256         };
257     }
258 
259     /**
260      * {@inheritDoc}
261      * 
262      * @see org.modeshape.graph.property.Path#size()
263      */
264     public int size() {
265         return size;
266     }
267 
268     /**
269      * {@inheritDoc}
270      * 
271      * @see org.modeshape.graph.property.Path#subpath(int, int)
272      */
273     @Override
274     public Path subpath( int beginIndex,
275                          int endIndex ) {
276         if (beginIndex == 0 && endIndex == (size - 1)) return parent;
277         return super.subpath(beginIndex, endIndex);
278     }
279 
280 }