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 }