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.connector.base;
25
26 import java.io.Serializable;
27 import java.util.ArrayList;
28 import java.util.Collections;
29 import java.util.HashMap;
30 import java.util.LinkedList;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.UUID;
34 import org.modeshape.graph.property.Name;
35 import org.modeshape.graph.property.Path;
36 import org.modeshape.graph.property.Property;
37 import org.modeshape.graph.property.Path.Segment;
38
39
40
41
42
43
44
45
46
47
48
49
50 public class PathNode implements Node, Serializable, Cloneable {
51
52 private static final long serialVersionUID = 1L;
53
54
55 private
56 private
57 private
58 private
59 private
60 private
61
62
63 protected transient Changes changes;
64
65
66
67
68
69
70
71
72
73
74 public PathNode( UUID uuid,
75 Path parent,
76 Segment name,
77 Map<Name, Property> properties,
78 List<Segment> children ) {
79 this.uuid = uuid;
80 this.parent = parent;
81 this.name = name;
82 this.properties = properties != null ? properties : Collections.<Name, Property>emptyMap();
83 this.children = children != null ? children : Collections.<Segment>emptyList();
84 assert this.properties != null;
85 assert this.children != null;
86 assert this.name != null ? this.parent != null : this.parent == null;
87 }
88
89
90
91
92
93
94
95
96
97
98
99 protected PathNode( UUID uuid,
100 Path parent,
101 Segment name,
102 Map<Name, Property> properties,
103 List<Segment> children,
104 int version ) {
105 this.uuid = uuid;
106 this.parent = parent;
107 this.name = name;
108 this.properties = properties != null ? properties : Collections.<Name, Property>emptyMap();
109 this.children = children != null ? children : Collections.<Segment>emptyList();
110 this.version = version;
111 assert this.properties != null;
112 assert this.children != null;
113 assert this.name != null ? this.parent != null : this.parent == null;
114 }
115
116
117
118
119
120
121
122
123
124
125 public PathNode( UUID uuid,
126 Path parent,
127 Segment name,
128 Iterable<Property> properties,
129 List<Segment> children ) {
130 this.uuid = uuid;
131 this.parent = parent;
132 this.name = name;
133 if (properties != null) {
134 Map<Name, Property> props = new HashMap<Name, Property>();
135 for (Property prop : properties) {
136 props.put(prop.getName(), prop);
137 }
138 this.properties = props.isEmpty() ? Collections.<Name, Property>emptyMap() : Collections.unmodifiableMap(props);
139 } else {
140 this.properties = Collections.emptyMap();
141 }
142 this.children = children != null ? children : Collections.<Segment>emptyList();
143 assert this.properties != null;
144 assert this.children != null;
145 assert this.name != null ? this.parent != null : this.parent == null;
146 }
147
148
149
150
151
152
153 public PathNode( UUID uuid ) {
154 this.uuid = uuid;
155 this.parent = null;
156 this.name = null;
157 this.properties = Collections.emptyMap();
158 this.children = Collections.emptyList();
159 assert this.uuid != null;
160 assert this.properties != null;
161 assert this.children != null;
162 }
163
164
165
166
167
168
169 public int getVersion() {
170 return version;
171 }
172
173
174
175
176
177
178 public UUID getUuid() {
179 return uuid;
180 }
181
182
183
184
185
186
187 public Segment getName() {
188 return changes != null ? changes.getName() : name;
189 }
190
191
192
193
194 public Path getParent() {
195 return changes != null ? changes.getParent() : parent;
196 }
197
198
199
200
201
202
203 public Map<Name, Property> getProperties() {
204 return changes != null ? changes.getProperties(false) : properties;
205 }
206
207
208
209
210
211
212 public Property getProperty( Name name ) {
213 return getProperties().get(name);
214 }
215
216
217
218
219 public List<Segment> getChildren() {
220 return changes != null ? changes.getChildren(false) : children;
221 }
222
223 @Override
224 public int hashCode() {
225 final int prime = 31;
226 int result = 1;
227 result = prime * result + ((children == null) ? 0 : children.hashCode());
228 result = prime * result + ((name == null) ? 0 : name.hashCode());
229 result = prime * result + ((parent == null) ? 0 : parent.hashCode());
230 return result;
231 }
232
233 @Override
234 public boolean equals( Object obj ) {
235 if (this == obj) return true;
236 if (obj == null) return false;
237 if (getClass() != obj.getClass()) return false;
238 PathNode other = (PathNode)obj;
239 if (name == null) {
240 if (other.name != null) return false;
241 } else if (!name.equals(other.name)) return false;
242 if (parent == null) {
243 if (other.parent != null) return false;
244 } else if (!parent.equals(other.parent)) return false;
245 return true;
246 }
247
248
249
250
251
252
253 @Override
254 public String toString() {
255 StringBuilder sb = new StringBuilder();
256 if (this.parent == null) {
257 sb.append("/");
258 } else {
259 sb.append(this.getParent()).append("/").append(this.getName());
260 }
261 sb.append(" (");
262 sb.append(this.getUuid()).append(")");
263 return sb.toString();
264 }
265
266
267
268
269
270
271
272
273
274 @Override
275 public PathNode clone() {
276 return new PathNode(uuid, parent, name, new HashMap<Name, Property>(properties), new ArrayList<Segment>(children));
277 }
278
279
280
281
282
283
284 protected boolean hasChanges() {
285 return changes != null;
286 }
287
288
289
290
291
292
293
294 protected Changes newChanges() {
295 return new Changes();
296 }
297
298
299
300
301
302
303
304
305 public PathNode freeze() {
306 if (!hasChanges()) return this;
307 return new PathNode(uuid, changes.getParent(), changes.getName(), changes.getUnmodifiableProperties(),
308 changes.getUnmodifiableChildren(), version + 1);
309 }
310
311
312
313
314
315
316
317 public PathNode withParent( Path parent ) {
318 if (changes == null) {
319 PathNode copy = clone();
320 copy.changes = newChanges();
321 copy.changes.setParent(parent);
322 return copy;
323 }
324 changes.setParent(parent);
325 return this;
326 }
327
328
329
330
331
332
333
334 public PathNode withName( Segment name ) {
335 if (changes == null) {
336 PathNode copy = clone();
337 copy.changes = newChanges();
338 copy.changes.setName(name);
339 return copy;
340 }
341 changes.setName(name);
342 return this;
343 }
344
345
346
347
348
349
350
351 public PathNode withChild( Segment child ) {
352 assert child != null;
353 if (getChildren().indexOf(child) != -1) return this;
354 if (changes == null) {
355 PathNode copy = clone();
356 List<Segment> children = new LinkedList<Segment>(getChildren());
357 assert !children.contains(child);
358 children.add(child);
359 copy.changes = newChanges();
360 copy.changes.setChildren(children);
361 return copy;
362 }
363 changes.getChildren(true).add(child);
364 return this;
365 }
366
367
368
369
370
371
372
373
374 public PathNode withChild( int index,
375 Segment child ) {
376 assert child != null;
377 assert index >= 0;
378 int existingIndex = getChildren().indexOf(child);
379 if (existingIndex == index) {
380
381 return this;
382 }
383 if (changes == null) {
384 PathNode copy = clone();
385 List<Segment> children = new LinkedList<Segment>(getChildren());
386 if (existingIndex >= 0) {
387
388 children.remove(existingIndex);
389 if (existingIndex < index) --index;
390 }
391 children.add(index, child);
392 copy.changes = newChanges();
393 copy.changes.setChildren(children);
394 return copy;
395 }
396 List<Segment> children = changes.getChildren(true);
397 if (existingIndex >= 0) {
398
399 children.remove(existingIndex);
400 if (existingIndex < index) --index;
401 }
402 children.add(index, child);
403 return this;
404 }
405
406
407
408
409
410
411
412 public PathNode withoutChild( Segment child ) {
413 assert child != null;
414 if (changes == null) {
415 PathNode copy = clone();
416 List<Segment> children = new LinkedList<Segment>(getChildren());
417 children.remove(child);
418 copy.changes = newChanges();
419 copy.changes.setChildren(children);
420 return copy;
421 }
422 changes.getChildren(true).remove(child);
423 return this;
424 }
425
426
427
428
429
430
431 public PathNode withoutChildren() {
432 if (getChildren().isEmpty()) return this;
433 if (changes == null) {
434 PathNode copy = clone();
435 copy.changes = newChanges();
436 copy.changes.setChildren(new LinkedList<Segment>());
437 return copy;
438 }
439 changes.getChildren(true).clear();
440 return this;
441 }
442
443
444
445
446
447
448
449
450
451
452 public PathNode withProperties( Iterable<Property> propertiesToSet,
453 Iterable<Name> propertiesToRemove,
454 boolean removeAllExisting ) {
455 if (propertiesToSet == null && propertiesToRemove == null && !removeAllExisting) {
456
457 return this;
458 }
459 Map<Name, Property> newProperties = null;
460 PathNode result = this;
461 if (changes == null) {
462 PathNode copy = clone();
463 copy.changes = newChanges();
464 copy.changes.setProperties(new HashMap<Name, Property>(this.properties));
465 newProperties = copy.changes.getProperties(true);
466 result = copy;
467 } else {
468 newProperties = changes.getProperties(true);
469 }
470 if (removeAllExisting) {
471 newProperties.clear();
472 } else {
473 if (propertiesToRemove != null) {
474 for (Name name : propertiesToRemove) {
475 newProperties.remove(name);
476 }
477 } else if (propertiesToSet == null) {
478 return this;
479 }
480 }
481 if (propertiesToSet != null) {
482 for (Property property : propertiesToSet) {
483 newProperties.put(property.getName(), property);
484 }
485 }
486 return result;
487 }
488
489
490
491
492
493
494
495 public PathNode withProperty( Property property ) {
496 if (property == null) return this;
497 if (changes == null) {
498 PathNode copy = clone();
499 copy.changes = newChanges();
500 Map<Name, Property> newProps = new HashMap<Name, Property>(this.properties);
501 newProps.put(property.getName(), property);
502 copy.changes.setProperties(newProps);
503 return copy;
504 }
505 changes.getProperties(true).put(property.getName(), property);
506 return this;
507 }
508
509
510
511
512
513
514
515 public PathNode withoutProperty( Name propertyName ) {
516 if (propertyName == null || !getProperties().containsKey(propertyName)) return this;
517 if (changes == null) {
518 PathNode copy = clone();
519 copy.changes = newChanges();
520 copy.changes.setProperties(new HashMap<Name, Property>(this.properties));
521 return copy;
522 }
523 changes.getProperties(true).remove(propertyName);
524 return this;
525 }
526
527
528
529
530
531
532 public PathNode withoutProperties() {
533 if (getProperties().isEmpty()) return this;
534 if (changes == null) {
535 PathNode copy = clone();
536 copy.changes = newChanges();
537 copy.changes.setProperties(new HashMap<Name, Property>());
538 return copy;
539 }
540 changes.getProperties(true).clear();
541 return this;
542
543 }
544
545 @SuppressWarnings( "synthetic-access" )
546 protected class Changes {
547 private Path parent;
548 private Segment name;
549 private Map<Name, Property> properties;
550 private List<Segment> children;
551
552 public Path getParent() {
553 return parent != null ? parent : PathNode.this.parent;
554 }
555
556 public void setParent( Path parent ) {
557 this.parent = parent;
558 }
559
560 public Segment getName() {
561 return name != null ? name : PathNode.this.name;
562 }
563
564 public void setName( Segment name ) {
565 this.name = name;
566 }
567
568 public Map<Name, Property> getProperties( boolean createIfMissing ) {
569 if (properties == null) {
570 if (createIfMissing) {
571 properties = new HashMap<Name, Property>(PathNode.this.properties);
572 return properties;
573 }
574 return PathNode.this.properties;
575 }
576 return properties;
577 }
578
579 public Map<Name, Property> getUnmodifiableProperties() {
580 return properties != null ? Collections.unmodifiableMap(properties) : PathNode.this.properties;
581 }
582
583 public void setProperties( Map<Name, Property> properties ) {
584 this.properties = properties;
585 }
586
587 public List<Segment> getChildren( boolean createIfMissing ) {
588 if (children == null) {
589 if (createIfMissing) {
590 children = new LinkedList<Segment>();
591 return children;
592 }
593 return PathNode.this.children;
594 }
595 return children;
596 }
597
598 public List<Segment> getUnmodifiableChildren() {
599 return children != null ? Collections.unmodifiableList(children) : PathNode.this.children;
600 }
601
602 public void setChildren( List<Segment> children ) {
603 this.children = children;
604 }
605 }
606
607 }