1 package org.apache.maven.shared.dependency.tree;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.StringWriter;
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.Iterator;
26 import java.util.List;
27
28 import org.apache.maven.artifact.Artifact;
29 import org.apache.maven.artifact.versioning.ArtifactVersion;
30 import org.apache.maven.artifact.versioning.VersionRange;
31 import org.apache.maven.shared.dependency.tree.traversal.DependencyNodeVisitor;
32 import org.apache.maven.shared.dependency.tree.traversal.SerializingDependencyNodeVisitor;
33
34
35
36
37
38
39
40
41 public class DependencyNode
42 {
43
44
45
46
47
48
49
50 public static final int INCLUDED = 0;
51
52
53
54
55
56
57 public static final int OMITTED_FOR_DUPLICATE = 1;
58
59
60
61
62
63
64 public static final int OMITTED_FOR_CONFLICT = 2;
65
66
67
68
69
70
71 public static final int OMITTED_FOR_CYCLE = 3;
72
73
74
75
76
77
78 private static class ItemAppender
79 {
80 private StringBuffer buffer;
81
82 private String startToken;
83
84 private String separatorToken;
85
86 private String endToken;
87
88 private boolean appended;
89
90 public ItemAppender( StringBuffer buffer, String startToken, String separatorToken, String endToken )
91 {
92 this.buffer = buffer;
93 this.startToken = startToken;
94 this.separatorToken = separatorToken;
95 this.endToken = endToken;
96
97 appended = false;
98 }
99
100 public ItemAppender append( String item )
101 {
102 appendToken();
103
104 buffer.append( item );
105
106 return this;
107 }
108
109 public ItemAppender append( String item1, String item2 )
110 {
111 appendToken();
112
113 buffer.append( item1 ).append( item2 );
114
115 return this;
116 }
117
118 public void flush()
119 {
120 if ( appended )
121 {
122 buffer.append( endToken );
123
124 appended = false;
125 }
126 }
127
128 private void appendToken()
129 {
130 buffer.append( appended ? separatorToken : startToken );
131
132 appended = true;
133 }
134 }
135
136
137
138
139
140
141 private final Artifact artifact;
142
143
144
145
146 private final List<DependencyNode> children;
147
148
149
150
151 private DependencyNode parent;
152
153
154
155
156
157
158
159
160
161
162 private int state;
163
164
165
166
167
168
169 private Artifact relatedArtifact;
170
171
172
173
174
175 private String originalScope;
176
177
178
179
180
181 private String failedUpdateScope;
182
183
184
185
186
187 private String premanagedVersion;
188
189
190
191
192
193 private String premanagedScope;
194
195 private VersionRange versionSelectedFromRange;
196
197 private List<ArtifactVersion> availableVersions;
198
199
200
201
202
203
204
205
206
207
208
209
210 public DependencyNode( Artifact artifact )
211 {
212 this( artifact, INCLUDED );
213 }
214
215
216
217
218
219
220
221
222
223
224
225
226
227 public DependencyNode( Artifact artifact, int state )
228 {
229 this( artifact, state, null );
230 }
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250 public DependencyNode( Artifact artifact, int state, Artifact relatedArtifact )
251 {
252 if ( artifact == null )
253 {
254 throw new IllegalArgumentException( "artifact cannot be null" );
255 }
256
257 if ( state < INCLUDED || state > OMITTED_FOR_CYCLE )
258 {
259 throw new IllegalArgumentException( "Unknown state: " + state );
260 }
261
262 boolean requiresRelatedArtifact = ( state == OMITTED_FOR_DUPLICATE || state == OMITTED_FOR_CONFLICT );
263
264 if ( requiresRelatedArtifact && relatedArtifact == null )
265 {
266 throw new IllegalArgumentException( "Related artifact is required for states "
267 + "OMITTED_FOR_DUPLICATE and OMITTED_FOR_CONFLICT" );
268 }
269
270 if ( !requiresRelatedArtifact && relatedArtifact != null )
271 {
272 throw new IllegalArgumentException( "Related artifact is only required for states "
273 + "OMITTED_FOR_DUPLICATE and OMITTED_FOR_CONFLICT" );
274 }
275
276 this.artifact = artifact;
277 this.state = state;
278 this.relatedArtifact = relatedArtifact;
279
280 children = new ArrayList<DependencyNode>();
281 }
282
283
284
285
286
287
288 DependencyNode()
289 {
290 artifact = null;
291 children = new ArrayList<DependencyNode>();
292 }
293
294
295
296
297
298
299
300
301
302
303
304 public boolean accept( DependencyNodeVisitor visitor )
305 {
306 if ( visitor.visit( this ) )
307 {
308 for ( DependencyNode child : getChildren() )
309 {
310 if ( !child.accept( visitor ) )
311 {
312 break;
313 }
314 }
315 }
316
317 return visitor.endVisit( this );
318 }
319
320
321
322
323
324
325
326
327 public void addChild( DependencyNode child )
328 {
329 children.add( child );
330 child.parent = this;
331 }
332
333
334
335
336
337
338
339
340 public void removeChild( DependencyNode child )
341 {
342 children.remove( child );
343 child.parent = null;
344 }
345
346
347
348
349
350
351 public DependencyNode getParent()
352 {
353 return parent;
354 }
355
356
357
358
359
360
361 public Artifact getArtifact()
362 {
363 return artifact;
364 }
365
366
367
368
369
370
371
372
373
374
375
376 public int getDepth()
377 {
378 int depth = 0;
379
380 DependencyNode node = getParent();
381
382 while ( node != null )
383 {
384 depth++;
385
386 node = node.getParent();
387 }
388
389 return depth;
390 }
391
392
393
394
395
396
397 public List<DependencyNode> getChildren()
398 {
399 return Collections.unmodifiableList( children );
400 }
401
402 public boolean hasChildren()
403 {
404 return children.size() > 0;
405 }
406
407
408
409
410
411
412
413
414 public int getState()
415 {
416 return state;
417 }
418
419
420
421
422
423
424
425
426
427 public Artifact getRelatedArtifact()
428 {
429 return relatedArtifact;
430 }
431
432
433
434
435
436
437
438 public String getOriginalScope()
439 {
440 return originalScope;
441 }
442
443
444
445
446
447
448
449
450 public void setOriginalScope( String originalScope )
451 {
452 this.originalScope = originalScope;
453 }
454
455
456
457
458
459
460
461 public String getFailedUpdateScope()
462 {
463 return failedUpdateScope;
464 }
465
466
467
468
469
470
471
472
473 public void setFailedUpdateScope( String failedUpdateScope )
474 {
475 this.failedUpdateScope = failedUpdateScope;
476 }
477
478
479
480
481
482
483
484 public String getPremanagedVersion()
485 {
486 return premanagedVersion;
487 }
488
489
490
491
492
493
494
495
496 public void setPremanagedVersion( String premanagedVersion )
497 {
498 this.premanagedVersion = premanagedVersion;
499 }
500
501
502
503
504
505
506
507 public String getPremanagedScope()
508 {
509 return premanagedScope;
510 }
511
512
513
514
515
516
517
518
519 public void setPremanagedScope( String premanagedScope )
520 {
521 this.premanagedScope = premanagedScope;
522 }
523
524
525
526
527
528
529
530
531 public VersionRange getVersionSelectedFromRange()
532 {
533 return versionSelectedFromRange;
534 }
535
536 public void setVersionSelectedFromRange( VersionRange versionSelectedFromRange )
537 {
538 this.versionSelectedFromRange = versionSelectedFromRange;
539 }
540
541
542
543
544
545
546
547
548 public List<ArtifactVersion> getAvailableVersions()
549 {
550 return availableVersions;
551 }
552
553 public void setAvailableVersions( List<ArtifactVersion> availableVersions )
554 {
555 this.availableVersions = availableVersions;
556 }
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579 public void omitForConflict( Artifact relatedArtifact )
580 {
581 if ( getState() != INCLUDED )
582 {
583 throw new IllegalStateException( "Only INCLUDED dependency nodes can be omitted for conflict" );
584 }
585
586 if ( relatedArtifact == null )
587 {
588 throw new IllegalArgumentException( "Related artifact cannot be null" );
589 }
590
591 if ( !relatedArtifact.getDependencyConflictId().equals( getArtifact().getDependencyConflictId() ) )
592 {
593 throw new IllegalArgumentException( "Related artifact has a different dependency conflict id" );
594 }
595
596 this.relatedArtifact = relatedArtifact;
597
598 boolean duplicate = false;
599 if ( getArtifact().getVersion() != null )
600 {
601 duplicate = getArtifact().getVersion().equals( relatedArtifact.getVersion() );
602 }
603 else if ( getArtifact().getVersionRange() != null )
604 {
605 duplicate = getArtifact().getVersionRange().equals( relatedArtifact.getVersionRange() );
606 }
607 else
608 {
609 throw new RuntimeException( "Artifact version and version range is null: " + getArtifact() );
610 }
611
612 state = duplicate ? OMITTED_FOR_DUPLICATE : OMITTED_FOR_CONFLICT;
613
614 removeAllChildren();
615 }
616
617
618
619
620
621
622
623
624
625
626
627
628
629 public void omitForCycle()
630 {
631 if ( getState() != INCLUDED )
632 {
633 throw new IllegalStateException( "Only INCLUDED dependency nodes can be omitted for cycle" );
634 }
635
636 state = OMITTED_FOR_CYCLE;
637
638 removeAllChildren();
639 }
640
641
642
643
644
645
646
647 public Iterator<DependencyNode> iterator()
648 {
649 return preorderIterator();
650 }
651
652
653
654
655
656
657
658 public Iterator<DependencyNode> preorderIterator()
659 {
660 return new DependencyTreePreorderIterator( this );
661 }
662
663
664
665
666
667
668
669 public Iterator<DependencyNode> inverseIterator()
670 {
671 return new DependencyTreeInverseIterator( this );
672 }
673
674
675
676
677
678
679
680
681 public String toNodeString()
682 {
683 StringBuffer buffer = new StringBuffer();
684
685 boolean included = ( getState() == INCLUDED );
686
687 if ( !included )
688 {
689 buffer.append( '(' );
690 }
691
692 buffer.append( artifact );
693
694 ItemAppender appender = new ItemAppender( buffer, included ? " (" : " - ", "; ", included ? ")" : "" );
695
696 if ( getPremanagedVersion() != null )
697 {
698 appender.append( "version managed from ", getPremanagedVersion() );
699 }
700
701 if ( getPremanagedScope() != null )
702 {
703 appender.append( "scope managed from ", getPremanagedScope() );
704 }
705
706 if ( getOriginalScope() != null )
707 {
708 appender.append( "scope updated from ", getOriginalScope() );
709 }
710
711 if ( getFailedUpdateScope() != null )
712 {
713 appender.append( "scope not updated to ", getFailedUpdateScope() );
714 }
715
716 if ( getVersionSelectedFromRange() != null )
717 {
718 appender.append( "version selected from range ", getVersionSelectedFromRange().toString() );
719 appender.append( "available versions ", getAvailableVersions().toString() );
720 }
721
722 switch ( state )
723 {
724 case INCLUDED:
725 break;
726
727 case OMITTED_FOR_DUPLICATE:
728 appender.append( "omitted for duplicate" );
729 break;
730
731 case OMITTED_FOR_CONFLICT:
732 appender.append( "omitted for conflict with ", relatedArtifact.getVersion() );
733 break;
734
735 case OMITTED_FOR_CYCLE:
736 appender.append( "omitted for cycle" );
737 break;
738 }
739
740 appender.flush();
741
742 if ( !included )
743 {
744 buffer.append( ')' );
745 }
746
747 return buffer.toString();
748 }
749
750
751
752
753
754
755
756
757
758
759
760
761
762 public String toString( int indentDepth )
763 {
764 return toString();
765 }
766
767
768
769
770
771
772 public int hashCode()
773 {
774
775
776 int hashCode = 1;
777
778 hashCode = hashCode * 31 + getArtifact().hashCode();
779
780 hashCode = hashCode * 31 + nullHashCode( getArtifact().getScope() );
781
782
783 hashCode = hashCode * 31 + nullHashCode( nullGetArtifact( getParent() ) );
784
785 hashCode = hashCode * 31 + getChildren().hashCode();
786 hashCode = hashCode * 31 + getState();
787 hashCode = hashCode * 31 + nullHashCode( getRelatedArtifact() );
788 hashCode = hashCode * 31 + nullHashCode( getPremanagedVersion() );
789 hashCode = hashCode * 31 + nullHashCode( getPremanagedScope() );
790 hashCode = hashCode * 31 + nullHashCode( getOriginalScope() );
791 hashCode = hashCode * 31 + nullHashCode( getFailedUpdateScope() );
792 hashCode = hashCode * 31 + nullHashCode( getVersionSelectedFromRange() );
793 hashCode = hashCode * 31 + nullHashCode( getAvailableVersions() );
794
795 return hashCode;
796 }
797
798 @Override
799 public boolean equals( Object object )
800 {
801
802
803 boolean equal;
804
805 if ( object instanceof DependencyNode )
806 {
807 DependencyNode node = (DependencyNode) object;
808
809 equal = getArtifact().equals( node.getArtifact() );
810
811 equal &= nullEquals( getArtifact().getScope(), node.getArtifact().getScope() );
812
813
814 equal &= nullEquals( nullGetArtifact( getParent() ), nullGetArtifact( node.getParent() ) );
815
816 equal &= getChildren().equals( node.getChildren() );
817 equal &= getState() == node.getState();
818 equal &= nullEquals( getRelatedArtifact(), node.getRelatedArtifact() );
819 equal &= nullEquals( getPremanagedVersion(), node.getPremanagedVersion() );
820 equal &= nullEquals( getPremanagedScope(), node.getPremanagedScope() );
821 equal &= nullEquals( getOriginalScope(), node.getOriginalScope() );
822 equal &= nullEquals( getFailedUpdateScope(), node.getFailedUpdateScope() );
823 equal &= nullEquals( getVersionSelectedFromRange(), node.getVersionSelectedFromRange() );
824 equal &= nullEquals( getAvailableVersions(), node.getAvailableVersions() );
825 }
826 else
827 {
828 equal = false;
829 }
830
831 return equal;
832 }
833
834
835
836
837
838
839
840
841 public String toString()
842 {
843 StringWriter writer = new StringWriter();
844 accept( new SerializingDependencyNodeVisitor( writer ) );
845 return writer.toString();
846 }
847
848
849
850
851
852
853 private void removeAllChildren()
854 {
855 for ( DependencyNode child : children )
856 {
857 child.parent = null;
858 }
859
860 children.clear();
861 }
862
863
864
865
866
867
868
869
870 private int nullHashCode( Object a )
871 {
872 return ( a == null ) ? 0 : a.hashCode();
873 }
874
875
876
877
878
879
880
881
882
883
884 private boolean nullEquals( Object a, Object b )
885 {
886 return ( a == null ? b == null : a.equals( b ) );
887 }
888
889
890
891
892
893
894
895
896 private static Artifact nullGetArtifact( DependencyNode node )
897 {
898 return ( node != null ) ? node.getArtifact() : null;
899 }
900 }