1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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
38
39
40 @Immutable
41 public class ChildPath extends AbstractPath {
42
43
44
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
64
65
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
76
77
78
79 @Override
80 protected Iterator<Segment> getSegmentsOfParent() {
81 return parent.iterator();
82 }
83
84
85
86
87
88
89 @Override
90 public Segment getLastSegment() {
91 return child;
92 }
93
94
95
96
97
98
99 @Override
100 public Path getParent() {
101 return parent;
102 }
103
104
105
106
107
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
117
118
119
120 public List<Segment> getSegmentsList() {
121 if (cachedSegmentList == null) {
122
123 List<Segment> segments = null;
124 if (parent.isRoot()) {
125 segments = Collections.singletonList(child);
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
143
144
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
155
156
157
158 public boolean isAbsolute() {
159 return parent.isAbsolute();
160 }
161
162
163
164
165
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
175
176
177
178 @Override
179 public boolean isDecendantOf( Path ancestor ) {
180 if (parent == ancestor) return true;
181 return parent.isAtOrBelow(ancestor);
182 }
183
184
185
186
187
188
189 public boolean isNormalized() {
190 if (child.isSelfReference()) return false;
191 if (!parent.isNormalized()) return false;
192
193 if (!child.isParentReference()) return true;
194
195 for (Path.Segment segment : parent) {
196 if (!segment.isParentReference()) return false;
197 }
198 return true;
199 }
200
201
202
203
204
205
206 public boolean isRoot() {
207 if (child.isParentReference()) return parent.isRoot();
208 return false;
209 }
210
211
212
213
214
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
261
262
263
264 public int size() {
265 return size;
266 }
267
268
269
270
271
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 }