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