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