1 package org.apache.maven.plugins.shade.mojo;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.artifact.Artifact;
23 import org.apache.maven.artifact.factory.ArtifactFactory;
24 import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
25 import org.apache.maven.artifact.repository.ArtifactRepository;
26 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
27 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
28 import org.apache.maven.artifact.resolver.ArtifactResolver;
29 import org.apache.maven.execution.MavenSession;
30 import org.apache.maven.model.Dependency;
31 import org.apache.maven.model.Exclusion;
32 import org.apache.maven.model.Model;
33 import org.apache.maven.plugin.AbstractMojo;
34 import org.apache.maven.plugin.MojoExecutionException;
35 import org.apache.maven.plugins.annotations.Component;
36 import org.apache.maven.plugins.annotations.LifecyclePhase;
37 import org.apache.maven.plugins.annotations.Mojo;
38 import org.apache.maven.plugins.annotations.Parameter;
39 import org.apache.maven.plugins.annotations.ResolutionScope;
40 import org.apache.maven.plugins.shade.ShadeRequest;
41 import org.apache.maven.plugins.shade.Shader;
42 import org.apache.maven.plugins.shade.filter.Filter;
43 import org.apache.maven.plugins.shade.filter.MinijarFilter;
44 import org.apache.maven.plugins.shade.filter.SimpleFilter;
45 import org.apache.maven.plugins.shade.pom.PomWriter;
46 import org.apache.maven.plugins.shade.relocation.Relocator;
47 import org.apache.maven.plugins.shade.relocation.SimpleRelocator;
48 import org.apache.maven.plugins.shade.resource.ResourceTransformer;
49 import org.apache.maven.project.DefaultProjectBuildingRequest;
50 import org.apache.maven.project.MavenProject;
51 import org.apache.maven.project.MavenProjectHelper;
52 import org.apache.maven.project.ProjectBuilder;
53 import org.apache.maven.project.ProjectBuildingException;
54 import org.apache.maven.project.ProjectBuildingRequest;
55 import org.apache.maven.project.ProjectBuildingResult;
56 import org.apache.maven.shared.dependency.graph.DependencyNode;
57 import org.apache.maven.shared.dependency.graph.DependencyGraphBuilder;
58 import org.apache.maven.shared.dependency.graph.DependencyGraphBuilderException;
59 import org.codehaus.plexus.PlexusConstants;
60 import org.codehaus.plexus.PlexusContainer;
61 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
62 import org.codehaus.plexus.context.Context;
63 import org.codehaus.plexus.context.ContextException;
64 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
65 import org.codehaus.plexus.util.IOUtil;
66 import org.codehaus.plexus.util.WriterFactory;
67
68 import java.io.File;
69 import java.io.FileInputStream;
70 import java.io.FileOutputStream;
71 import java.io.IOException;
72 import java.io.Writer;
73 import java.util.ArrayList;
74 import java.util.Arrays;
75 import java.util.Collections;
76 import java.util.HashMap;
77 import java.util.HashSet;
78 import java.util.LinkedHashSet;
79 import java.util.List;
80 import java.util.Map;
81 import java.util.Set;
82
83
84
85
86
87
88
89
90
91 @Mojo( name = "shade", defaultPhase = LifecyclePhase.PACKAGE, threadSafe = true,
92 requiresDependencyResolution = ResolutionScope.RUNTIME )
93 public class ShadeMojo
94 extends AbstractMojo
95 implements Contextualizable
96 {
97
98
99
100 @Component
101 private MavenSession session;
102
103
104
105
106 @Component
107 private MavenProject project;
108
109 @Component
110 private MavenProjectHelper projectHelper;
111
112 @Component( hint = "default", role = org.apache.maven.plugins.shade.Shader.class )
113 private Shader shader;
114
115
116
117
118 @Component
119 private DependencyGraphBuilder dependencyGraphBuilder;
120
121
122
123
124 @Component
125 private ProjectBuilder projectBuilder;
126
127
128
129
130 @Component
131 private ArtifactMetadataSource artifactMetadataSource;
132
133
134
135
136 @Parameter( readonly = true, required = true, defaultValue = "${project.remoteArtifactRepositories}" )
137 protected List<ArtifactRepository> remoteArtifactRepositories;
138
139
140
141
142 @Parameter( readonly = true, required = true, defaultValue = "${localRepository}" )
143 protected ArtifactRepository localRepository;
144
145
146
147
148 @Component
149 protected ArtifactFactory artifactFactory;
150
151
152
153
154 @Component
155 protected ArtifactResolver artifactResolver;
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175 @Parameter
176 private ArtifactSet artifactSet;
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196 @Parameter
197 private PackageRelocation[] relocations;
198
199
200
201
202
203 @Parameter
204 private ResourceTransformer[] transformers;
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227 @Parameter
228 private ArchiveFilter[] filters;
229
230
231
232
233 @Parameter( defaultValue = "${project.build.directory}" )
234 private File outputDirectory;
235
236
237
238
239
240
241
242
243 @Parameter
244 private String finalName;
245
246
247
248
249
250
251
252 @Parameter( defaultValue = "${project.artifactId}" )
253 private String shadedArtifactId;
254
255
256
257
258
259 @Parameter
260 private String shadedGroupFilter;
261
262
263
264
265
266
267 @Parameter
268 private boolean shadedArtifactAttached;
269
270
271
272
273
274
275
276
277 @Parameter( defaultValue = "true" )
278 private boolean createDependencyReducedPom;
279
280
281
282
283
284
285
286
287
288
289 @Parameter( defaultValue = "${basedir}/dependency-reduced-pom.xml" )
290 private File dependencyReducedPomLocation;
291
292
293
294
295
296
297
298
299 @Parameter( defaultValue = "false" )
300 private boolean generateUniqueDependencyReducedPom;
301
302
303
304
305
306 @Parameter
307 private boolean keepDependenciesWithProvidedScope;
308
309
310
311
312
313
314 @Parameter
315 private boolean promoteTransitiveDependencies;
316
317
318
319
320 @Parameter( defaultValue = "shaded" )
321 private String shadedClassifierName;
322
323
324
325
326 @Parameter
327 private boolean createSourcesJar;
328
329
330
331
332
333
334
335 @Parameter( property = "shadeSourcesContent", defaultValue = "false" )
336 private boolean shadeSourcesContent;
337
338
339
340
341
342
343
344 @Parameter
345 private boolean minimizeJar;
346
347
348
349
350
351
352
353
354
355 @Parameter
356 private File outputFile;
357
358
359
360
361
362
363 @Parameter
364 private String shaderHint;
365
366
367
368
369
370
371
372
373
374
375 @Parameter( defaultValue = "false" )
376 private boolean useBaseVersion;
377
378
379
380
381 private PlexusContainer plexusContainer;
382
383 public void contextualize( Context context )
384 throws ContextException
385 {
386 plexusContainer = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
387 }
388
389
390
391
392 public void execute()
393 throws MojoExecutionException
394 {
395
396 if ( shaderHint != null )
397 {
398 try
399 {
400 shader = (Shader) plexusContainer.lookup( Shader.ROLE, shaderHint );
401 }
402 catch ( ComponentLookupException e )
403 {
404 throw new MojoExecutionException(
405 "unable to lookup own Shader implementation with hint:'" + shaderHint + "'", e );
406 }
407 }
408
409 Set<File> artifacts = new LinkedHashSet<File>();
410 Set<String> artifactIds = new LinkedHashSet<String>();
411 Set<File> sourceArtifacts = new LinkedHashSet<File>();
412
413 ArtifactSelector artifactSelector =
414 new ArtifactSelector( project.getArtifact(), artifactSet, shadedGroupFilter );
415
416 if ( artifactSelector.isSelected( project.getArtifact() ) && !"pom".equals( project.getArtifact().getType() ) )
417 {
418 if ( invalidMainArtifact() )
419 {
420 getLog().error( "The project main artifact does not exist. This could have the following" );
421 getLog().error( "reasons:" );
422 getLog().error( "- You have invoked the goal directly from the command line. This is not" );
423 getLog().error( " supported. Please add the goal to the default lifecycle via an" );
424 getLog().error( " <execution> element in your POM and use \"mvn package\" to have it run." );
425 getLog().error( "- You have bound the goal to a lifecycle phase before \"package\". Please" );
426 getLog().error( " remove this binding from your POM such that the goal will be run in" );
427 getLog().error( " the proper phase." );
428 getLog().error(
429 "- You removed the configuration of the maven-jar-plugin that produces the main artifact." );
430 throw new MojoExecutionException(
431 "Failed to create shaded artifact, " + "project main artifact does not exist." );
432 }
433
434 artifacts.add( project.getArtifact().getFile() );
435
436 if ( createSourcesJar )
437 {
438 File file = shadedSourcesArtifactFile();
439 if ( file.isFile() )
440 {
441 sourceArtifacts.add( file );
442 }
443 }
444 }
445
446 for ( Artifact artifact : project.getArtifacts() )
447 {
448 if ( !artifactSelector.isSelected( artifact ) )
449 {
450 getLog().info( "Excluding " + artifact.getId() + " from the shaded jar." );
451
452 continue;
453 }
454
455 if ( "pom".equals( artifact.getType() ) )
456 {
457 getLog().info( "Skipping pom dependency " + artifact.getId() + " in the shaded jar." );
458 continue;
459 }
460
461 getLog().info( "Including " + artifact.getId() + " in the shaded jar." );
462
463 artifacts.add( artifact.getFile() );
464 artifactIds.add( getId( artifact ) );
465
466 if ( createSourcesJar )
467 {
468 File file = resolveArtifactSources( artifact );
469 if ( file != null )
470 {
471 sourceArtifacts.add( file );
472 }
473 }
474 }
475
476 File outputJar = ( outputFile != null ) ? outputFile : shadedArtifactFileWithClassifier();
477 File sourcesJar = shadedSourceArtifactFileWithClassifier();
478
479
480 try
481 {
482 List<Filter> filters = getFilters();
483
484 List<Relocator> relocators = getRelocators();
485
486 List<ResourceTransformer> resourceTransformers = getResourceTransformers();
487
488 ShadeRequest shadeRequest = new ShadeRequest();
489 shadeRequest.setJars( artifacts );
490 shadeRequest.setUberJar( outputJar );
491 shadeRequest.setFilters( filters );
492 shadeRequest.setRelocators( relocators );
493 shadeRequest.setResourceTransformers( resourceTransformers );
494
495 shader.shade( shadeRequest );
496
497 if ( createSourcesJar )
498 {
499 ShadeRequest shadeSourcesRequest = new ShadeRequest();
500 shadeSourcesRequest.setJars( sourceArtifacts );
501 shadeSourcesRequest.setUberJar( sourcesJar );
502 shadeSourcesRequest.setFilters( filters );
503 shadeSourcesRequest.setRelocators( relocators );
504 shadeSourcesRequest.setResourceTransformers( resourceTransformers );
505 shadeSourcesRequest.setShadeSourcesContent( shadeSourcesContent );
506
507 shader.shade( shadeSourcesRequest );
508 }
509
510 if ( outputFile == null )
511 {
512 boolean renamed = false;
513
514
515
516
517 if ( finalName != null && finalName.length() > 0 && !finalName.equals(
518 project.getBuild().getFinalName() ) )
519 {
520 String finalFileName = finalName + "." + project.getArtifact().getArtifactHandler().getExtension();
521 File finalFile = new File( outputDirectory, finalFileName );
522 replaceFile( finalFile, outputJar );
523 outputJar = finalFile;
524
525 renamed = true;
526 }
527
528 if ( shadedArtifactAttached )
529 {
530 getLog().info( "Attaching shaded artifact." );
531 projectHelper.attachArtifact( project, project.getArtifact().getType(), shadedClassifierName,
532 outputJar );
533 if ( createSourcesJar )
534 {
535 projectHelper.attachArtifact( project, "jar", shadedClassifierName + "-sources", sourcesJar );
536 }
537 }
538 else if ( !renamed )
539 {
540 getLog().info( "Replacing original artifact with shaded artifact." );
541 File originalArtifact = project.getArtifact().getFile();
542 replaceFile( originalArtifact, outputJar );
543
544 if ( createSourcesJar )
545 {
546 File shadedSources = shadedSourcesArtifactFile();
547
548 replaceFile( shadedSources, sourcesJar );
549
550 projectHelper.attachArtifact( project, "jar", "sources", shadedSources );
551 }
552
553 if ( createDependencyReducedPom )
554 {
555 createDependencyReducedPom( artifactIds );
556 }
557 }
558 }
559 }
560 catch ( Exception e )
561 {
562 throw new MojoExecutionException( "Error creating shaded jar: " + e.getMessage(), e );
563 }
564 }
565
566 private boolean invalidMainArtifact()
567 {
568 return project.getArtifact().getFile() == null || !project.getArtifact().getFile().isFile();
569 }
570
571 private void replaceFile( File oldFile, File newFile )
572 throws MojoExecutionException
573 {
574 getLog().info( "Replacing " + oldFile + " with " + newFile );
575
576 File origFile = new File( outputDirectory, "original-" + oldFile.getName() );
577 if ( oldFile.exists() && !oldFile.renameTo( origFile ) )
578 {
579
580 System.gc();
581 System.gc();
582
583 if ( !oldFile.renameTo( origFile ) )
584 {
585
586 try
587 {
588 FileOutputStream fout = new FileOutputStream( origFile );
589 FileInputStream fin = new FileInputStream( oldFile );
590 try
591 {
592 IOUtil.copy( fin, fout );
593 }
594 finally
595 {
596 IOUtil.close( fin );
597 IOUtil.close( fout );
598 }
599 }
600 catch ( IOException ex )
601 {
602
603 getLog().warn( ex );
604 }
605 }
606 }
607 if ( !newFile.renameTo( oldFile ) )
608 {
609
610 System.gc();
611 System.gc();
612
613 if ( !newFile.renameTo( oldFile ) )
614 {
615
616 try
617 {
618 FileOutputStream fout = new FileOutputStream( oldFile );
619 FileInputStream fin = new FileInputStream( newFile );
620 try
621 {
622 IOUtil.copy( fin, fout );
623 }
624 finally
625 {
626 IOUtil.close( fin );
627 IOUtil.close( fout );
628 }
629 }
630 catch ( IOException ex )
631 {
632 throw new MojoExecutionException( "Could not replace original artifact with shaded artifact!", ex );
633 }
634 }
635 }
636 }
637
638 private File resolveArtifactSources( Artifact artifact )
639 {
640
641 Artifact resolvedArtifact =
642 artifactFactory.createArtifactWithClassifier( artifact.getGroupId(), artifact.getArtifactId(),
643 artifact.getVersion(), "java-source", "sources" );
644
645 try
646 {
647 artifactResolver.resolve( resolvedArtifact, remoteArtifactRepositories, localRepository );
648 }
649 catch ( ArtifactNotFoundException e )
650 {
651
652 }
653 catch ( ArtifactResolutionException e )
654 {
655 getLog().warn( "Could not get sources for " + artifact );
656 }
657
658 if ( resolvedArtifact.isResolved() )
659 {
660 return resolvedArtifact.getFile();
661 }
662 return null;
663 }
664
665 private List<Relocator> getRelocators()
666 {
667 List<Relocator> relocators = new ArrayList<Relocator>();
668
669 if ( relocations == null )
670 {
671 return relocators;
672 }
673
674 for ( int i = 0; i < relocations.length; i++ )
675 {
676 PackageRelocation r = relocations[i];
677
678 relocators.add( new SimpleRelocator( r.getPattern(), r.getShadedPattern(), r.getIncludes(), r.getExcludes(),
679 r.isRawString() ) );
680 }
681
682 return relocators;
683 }
684
685 private List<ResourceTransformer> getResourceTransformers()
686 {
687 if ( transformers == null )
688 {
689 return Collections.emptyList();
690 }
691
692 return Arrays.asList( transformers );
693 }
694
695 private List<Filter> getFilters()
696 throws MojoExecutionException
697 {
698 List<Filter> filters = new ArrayList<Filter>();
699 List<SimpleFilter> simpleFilters = new ArrayList<SimpleFilter>();
700
701 if ( this.filters != null && this.filters.length > 0 )
702 {
703 Map<Artifact, ArtifactId> artifacts = new HashMap<Artifact, ArtifactId>();
704
705 artifacts.put( project.getArtifact(), new ArtifactId( project.getArtifact() ) );
706
707 for ( Artifact artifact : project.getArtifacts() )
708 {
709 artifacts.put( artifact, new ArtifactId( artifact ) );
710 }
711
712 for ( ArchiveFilter filter : this.filters )
713 {
714 ArtifactId pattern = new ArtifactId( filter.getArtifact() );
715
716 Set<File> jars = new HashSet<File>();
717
718 for ( Map.Entry<Artifact, ArtifactId> entry : artifacts.entrySet() )
719 {
720 if ( entry.getValue().matches( pattern ) )
721 {
722 Artifact artifact = entry.getKey();
723
724 jars.add( artifact.getFile() );
725
726 if ( createSourcesJar )
727 {
728 File file = resolveArtifactSources( artifact );
729 if ( file != null )
730 {
731 jars.add( file );
732 }
733 }
734 }
735 }
736
737 if ( jars.isEmpty() )
738 {
739 getLog().info( "No artifact matching filter " + filter.getArtifact() );
740
741 continue;
742 }
743
744 simpleFilters.add( new SimpleFilter( jars, filter.getIncludes(), filter.getExcludes() ) );
745 }
746 }
747
748 filters.addAll( simpleFilters );
749
750 if ( minimizeJar )
751 {
752 getLog().info( "Minimizing jar " + project.getArtifact() );
753
754 try
755 {
756 filters.add( new MinijarFilter( project, getLog(), simpleFilters ) );
757 }
758 catch ( IOException e )
759 {
760 throw new MojoExecutionException( "Failed to analyze class dependencies", e );
761 }
762 }
763
764 return filters;
765 }
766
767 private File shadedArtifactFileWithClassifier()
768 {
769 Artifact artifact = project.getArtifact();
770 final String shadedName = shadedArtifactId + "-" + artifact.getVersion() + "-" + shadedClassifierName + "."
771 + artifact.getArtifactHandler().getExtension();
772 return new File( outputDirectory, shadedName );
773 }
774
775 private File shadedSourceArtifactFileWithClassifier()
776 {
777 Artifact artifact = project.getArtifact();
778 final String shadedName =
779 shadedArtifactId + "-" + artifact.getVersion() + "-" + shadedClassifierName + "-sources."
780 + artifact.getArtifactHandler().getExtension();
781 return new File( outputDirectory, shadedName );
782 }
783
784 private File shadedSourcesArtifactFile()
785 {
786 Artifact artifact = project.getArtifact();
787
788 String shadedName;
789
790 if ( project.getBuild().getFinalName() != null )
791 {
792 shadedName = project.getBuild().getFinalName() + "-sources." + artifact.getArtifactHandler().getExtension();
793 }
794 else
795 {
796 shadedName = shadedArtifactId + "-" + artifact.getVersion() + "-sources."
797 + artifact.getArtifactHandler().getExtension();
798 }
799
800 return new File( outputDirectory, shadedName );
801 }
802
803
804
805 private void createDependencyReducedPom( Set<String> artifactsToRemove )
806 throws IOException, DependencyGraphBuilderException, ProjectBuildingException
807 {
808 Model model = project.getOriginalModel();
809 List<Dependency> dependencies = new ArrayList<Dependency>();
810
811 boolean modified = false;
812
813 List<Dependency> transitiveDeps = new ArrayList<Dependency>();
814
815 for ( Artifact artifact : project.getArtifacts() )
816 {
817 if ( "pom".equals( artifact.getType() ) )
818 {
819
820 continue;
821 }
822
823
824 Dependency dep = new Dependency();
825 dep.setArtifactId( artifact.getArtifactId() );
826 if ( artifact.hasClassifier() )
827 {
828 dep.setClassifier( artifact.getClassifier() );
829 }
830 dep.setGroupId( artifact.getGroupId() );
831 dep.setOptional( artifact.isOptional() );
832 dep.setScope( artifact.getScope() );
833 dep.setType( artifact.getType() );
834 if ( useBaseVersion )
835 {
836 dep.setVersion( artifact.getBaseVersion() );
837 }
838 else
839 {
840 dep.setVersion( artifact.getVersion() );
841 }
842
843
844
845 transitiveDeps.add( dep );
846 }
847 List<Dependency> origDeps = project.getDependencies();
848
849 if ( promoteTransitiveDependencies )
850 {
851 origDeps = transitiveDeps;
852 }
853
854 for ( Dependency d : origDeps )
855 {
856 dependencies.add( d );
857
858 String id = getId( d );
859
860 if ( artifactsToRemove.contains( id ) )
861 {
862 modified = true;
863
864 if ( keepDependenciesWithProvidedScope )
865 {
866 d.setScope( "provided" );
867 }
868 else
869 {
870 dependencies.remove( d );
871 }
872 }
873 }
874
875
876 if ( modified )
877 {
878 while ( modified )
879 {
880
881 model.setDependencies( dependencies );
882
883 if ( generateUniqueDependencyReducedPom )
884 {
885 dependencyReducedPomLocation =
886 File.createTempFile( "dependency-reduced-pom-", ".xml", project.getBasedir() );
887 project.getProperties().setProperty( "maven.shade.dependency-reduced-pom",
888 dependencyReducedPomLocation.getAbsolutePath() );
889 }
890 else
891 {
892 if ( dependencyReducedPomLocation == null )
893 {
894
895 dependencyReducedPomLocation = new File( project.getBasedir(), "dependency-reduced-pom.xml" );
896 }
897 }
898
899 File f = dependencyReducedPomLocation;
900 getLog().info( "Dependency-reduced POM written at: " + f.getAbsolutePath() );
901
902 if ( f.exists() )
903 {
904 f.delete();
905 }
906
907 Writer w = WriterFactory.newXmlWriter( f );
908
909 String origRelativePath = null;
910 String replaceRelativePath = null;
911 if ( model.getParent() != null )
912 {
913 origRelativePath = model.getParent().getRelativePath();
914
915 }
916 replaceRelativePath = origRelativePath;
917
918 if ( origRelativePath == null )
919 {
920 origRelativePath = "../pom.xml";
921 }
922
923 if ( model.getParent() != null )
924 {
925 File parentFile =
926 new File( project.getBasedir(), model.getParent().getRelativePath() ).getCanonicalFile();
927 if ( !parentFile.isFile() )
928 {
929 parentFile = new File( parentFile, "pom.xml" );
930 }
931
932 parentFile = parentFile.getCanonicalFile();
933
934 String relPath = RelativizePath.convertToRelativePath( parentFile, f );
935 model.getParent().setRelativePath( relPath );
936 }
937
938 try
939 {
940 PomWriter.write( w, model, true );
941 }
942 finally
943 {
944 if ( model.getParent() != null )
945 {
946 model.getParent().setRelativePath( replaceRelativePath );
947 }
948 w.close();
949 }
950
951 ProjectBuildingRequest projectBuildingRequest =
952 new DefaultProjectBuildingRequest( session.getProjectBuildingRequest() );
953 projectBuildingRequest.setLocalRepository( localRepository );
954 projectBuildingRequest.setRemoteRepositories( remoteArtifactRepositories );
955
956 ProjectBuildingResult result = projectBuilder.build( f, projectBuildingRequest );
957
958 modified = updateExcludesInDeps( result.getProject(), dependencies, transitiveDeps );
959 }
960
961 project.setFile( dependencyReducedPomLocation );
962 }
963 }
964
965 private String getId( Artifact artifact )
966 {
967 return getId( artifact.getGroupId(), artifact.getArtifactId(), artifact.getType(), artifact.getClassifier() );
968 }
969
970 private String getId( Dependency dependency )
971 {
972 return getId( dependency.getGroupId(), dependency.getArtifactId(), dependency.getType(),
973 dependency.getClassifier() );
974 }
975
976 private String getId( String groupId, String artifactId, String type, String classifier )
977 {
978 return groupId + ":" + artifactId + ":" + type + ":" + ( ( classifier != null ) ? classifier : "" );
979 }
980
981 public boolean updateExcludesInDeps( MavenProject project, List<Dependency> dependencies,
982 List<Dependency> transitiveDeps )
983 throws DependencyGraphBuilderException
984 {
985 DependencyNode node = dependencyGraphBuilder.buildDependencyGraph( project, null );
986 boolean modified = false;
987 for ( DependencyNode n2 : node.getChildren() )
988 {
989 for ( DependencyNode n3 : n2.getChildren() )
990 {
991
992
993
994
995
996
997 boolean found = false;
998 for ( Dependency dep : transitiveDeps )
999 {
1000 if ( dep.getArtifactId().equals( n3.getArtifact().getArtifactId() )
1001 && dep.getGroupId().equals( n3.getArtifact().getGroupId() ) )
1002 {
1003 found = true;
1004 break;
1005 }
1006 }
1007
1008 if ( !found )
1009 {
1010 for ( Dependency dep : dependencies )
1011 {
1012 if ( dep.getArtifactId().equals( n2.getArtifact().getArtifactId() )
1013 && dep.getGroupId().equals( n2.getArtifact().getGroupId() ) )
1014 {
1015 Exclusion exclusion = new Exclusion();
1016 exclusion.setArtifactId( n3.getArtifact().getArtifactId() );
1017 exclusion.setGroupId( n3.getArtifact().getGroupId() );
1018 dep.addExclusion( exclusion );
1019 modified = true;
1020 break;
1021 }
1022 }
1023 }
1024 }
1025 }
1026 return modified;
1027 }
1028 }