View Javadoc

1   package org.apache.maven.plugins.shade.mojo;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
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.ArtifactCollector;
27  import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
28  import org.apache.maven.artifact.resolver.ArtifactResolutionException;
29  import org.apache.maven.artifact.resolver.ArtifactResolver;
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.shade.Shader;
36  import org.apache.maven.plugins.shade.filter.Filter;
37  import org.apache.maven.plugins.shade.filter.MinijarFilter;
38  import org.apache.maven.plugins.shade.filter.SimpleFilter;
39  import org.apache.maven.plugins.shade.pom.PomWriter;
40  import org.apache.maven.plugins.shade.relocation.Relocator;
41  import org.apache.maven.plugins.shade.relocation.SimpleRelocator;
42  import org.apache.maven.plugins.shade.resource.ResourceTransformer;
43  import org.apache.maven.project.MavenProject;
44  import org.apache.maven.project.MavenProjectBuilder;
45  import org.apache.maven.project.MavenProjectHelper;
46  import org.apache.maven.project.ProjectBuildingException;
47  import org.apache.maven.shared.dependency.tree.DependencyNode;
48  import org.apache.maven.shared.dependency.tree.DependencyTreeBuilder;
49  import org.apache.maven.shared.dependency.tree.DependencyTreeBuilderException;
50  import org.codehaus.plexus.PlexusConstants;
51  import org.codehaus.plexus.PlexusContainer;
52  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
53  import org.codehaus.plexus.context.Context;
54  import org.codehaus.plexus.context.ContextException;
55  import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
56  import org.codehaus.plexus.util.IOUtil;
57  import org.codehaus.plexus.util.WriterFactory;
58  
59  import java.io.File;
60  import java.io.FileInputStream;
61  import java.io.FileOutputStream;
62  import java.io.IOException;
63  import java.io.Writer;
64  import java.util.ArrayList;
65  import java.util.Arrays;
66  import java.util.Collections;
67  import java.util.HashMap;
68  import java.util.HashSet;
69  import java.util.Iterator;
70  import java.util.LinkedHashSet;
71  import java.util.List;
72  import java.util.Map;
73  import java.util.Set;
74  
75  /**
76   * Mojo that performs shading delegating to the Shader component.
77   *
78   * @author Jason van Zyl
79   * @author Mauro Talevi
80   * @author David Blevins
81   * @author Hiram Chirino
82   * @goal shade
83   * @phase package
84   * @requiresDependencyResolution runtime
85   * @threadSafe
86   */
87  public class ShadeMojo
88      extends AbstractMojo
89      implements Contextualizable
90  {
91      /**
92       * @parameter default-value="${project}"
93       * @readonly
94       * @required
95       */
96      private MavenProject project;
97  
98      /**
99       * @component
100      * @required
101      * @readonly
102      */
103     private MavenProjectHelper projectHelper;
104 
105     /**
106      * @component role="org.apache.maven.plugins.shade.Shader" roleHint="default"
107      * @required
108      * @readonly
109      */
110     private Shader shader;
111 
112     /**
113      * The dependency tree builder to use.
114      *
115      * @component
116      * @required
117      * @readonly
118      */
119     private DependencyTreeBuilder dependencyTreeBuilder;
120 
121     /**
122      * ProjectBuilder, needed to create projects from the artifacts.
123      *
124      * @component
125      * @required
126      * @readonly
127      */
128     private MavenProjectBuilder mavenProjectBuilder;
129 
130     /**
131      * The artifact metadata source to use.
132      *
133      * @component
134      * @required
135      * @readonly
136      */
137     private ArtifactMetadataSource artifactMetadataSource;
138 
139     /**
140      * The artifact collector to use.
141      *
142      * @component
143      * @required
144      * @readonly
145      */
146     private ArtifactCollector artifactCollector;
147 
148     /**
149      * Remote repositories which will be searched for source attachments.
150      *
151      * @parameter default-value="${project.remoteArtifactRepositories}"
152      * @required
153      * @readonly
154      */
155     protected List remoteArtifactRepositories;
156 
157     /**
158      * Local maven repository.
159      *
160      * @parameter default-value="${localRepository}"
161      * @required
162      * @readonly
163      */
164     protected ArtifactRepository localRepository;
165 
166     /**
167      * Artifact factory, needed to download source jars for inclusion in classpath.
168      *
169      * @component
170      * @required
171      * @readonly
172      */
173     protected ArtifactFactory artifactFactory;
174 
175     /**
176      * Artifact resolver, needed to download source jars for inclusion in classpath.
177      *
178      * @component
179      * @required
180      * @readonly
181      */
182     protected ArtifactResolver artifactResolver;
183 
184     /**
185      * Artifacts to include/exclude from the final artifact. Artifacts are denoted by composite identifiers of the
186      * general form <code>groupId:artifactId:type:classifier</code>. Since version 1.3, the wildcard characters '*' and
187      * '?' can be used within the sub parts of those composite identifiers to do pattern matching. For convenience, the
188      * syntax <code>groupId</code> is equivalent to <code>groupId:*:*:*</code>, <code>groupId:artifactId</code> is
189      * equivalent to <code>groupId:artifactId:*:*</code> and <code>groupId:artifactId:classifier</code> is equivalent to
190      * <code>groupId:artifactId:*:classifier</code>. For example:
191      * <pre>
192      * &lt;artifactSet&gt;
193      *   &lt;includes&gt;
194      *     &lt;include&gt;org.apache.maven:*&lt;/include&gt;
195      *   &lt;/includes&gt;
196      *   &lt;excludes&gt;
197      *     &lt;exclude&gt;*:maven-core&lt;/exclude&gt;
198      *   &lt;/excludes&gt;
199      * &lt;/artifactSet&gt;
200      * </pre>
201      *
202      * @parameter
203      */
204     private ArtifactSet artifactSet;
205 
206     /**
207      * Packages to be relocated. For example:
208      * <pre>
209      * &lt;relocations&gt;
210      *   &lt;relocation&gt;
211      *     &lt;pattern&gt;org.apache&lt;/pattern&gt;
212      *     &lt;shadedPattern&gt;hidden.org.apache&lt;/shadedPattern&gt;
213      *     &lt;includes&gt;
214      *       &lt;include&gt;org.apache.maven.*&lt;/include&gt;
215      *     &lt;/includes&gt;
216      *     &lt;excludes&gt;
217      *       &lt;exclude&gt;org.apache.maven.Public*&lt;/exclude&gt;
218      *     &lt;/excludes&gt;
219      *   &lt;/relocation&gt;
220      * &lt;/relocations&gt;
221      * </pre>
222      * <em>Note:</em> Support for includes exists only since version 1.4.
223      *
224      * @parameter
225      */
226     private PackageRelocation[] relocations;
227 
228     /**
229      * Resource transformers to be used. Please see the "Examples" section for more information on available
230      * transformers and their configuration.
231      *
232      * @parameter
233      */
234     private ResourceTransformer[] transformers;
235 
236     /**
237      * Archive Filters to be used. Allows you to specify an artifact in the form of a composite identifier as used by
238      * {@link #artifactSet} and a set of include/exclude file patterns for filtering which contents of the archive are
239      * added to the shaded jar. From a logical perspective, includes are processed before excludes, thus it's possible
240      * to use an include to collect a set of files from the archive then use excludes to further reduce the set. By
241      * default, all files are included and no files are excluded. If multiple filters apply to an artifact, the
242      * intersection of the matched files will be included in the final JAR. For example:
243      * <pre>
244      * &lt;filters&gt;
245      *   &lt;filter&gt;
246      *     &lt;artifact&gt;junit:junit&lt;/artifact&gt;
247      *     &lt;includes&gt;
248      *       &lt;include&gt;org/junit/**&lt;/include&gt;
249      *     &lt;/includes&gt;
250      *     &lt;excludes&gt;
251      *       &lt;exclude&gt;org/junit/experimental/**&lt;/exclude&gt;
252      *     &lt;/excludes&gt;
253      *   &lt;/filter&gt;
254      * &lt;/filters&gt;
255      * </pre>
256      *
257      * @parameter
258      */
259     private ArchiveFilter[] filters;
260 
261     /**
262      * The destination directory for the shaded artifact.
263      *
264      * @parameter default-value="${project.build.directory}"
265      */
266     private File outputDirectory;
267 
268     /**
269      * The name of the shaded artifactId.
270      * <p/>
271      * If you like to change the name of the native artifact, you may use the &lt;build>&lt;finalName> setting.
272      * If this is set to something different than &lt;build>&lt;finalName>, no file replacement
273      * will be performed, even if shadedArtifactAttached is being used.
274      *
275      * @parameter expression="${finalName}"
276      */
277     private String finalName;
278 
279     /**
280      * The name of the shaded artifactId. So you may want to use a different artifactId and keep
281      * the standard version. If the original artifactId was "foo" then the final artifact would
282      * be something like foo-1.0.jar. So if you change the artifactId you might have something
283      * like foo-special-1.0.jar.
284      *
285      * @parameter expression="${shadedArtifactId}" default-value="${project.artifactId}"
286      */
287     private String shadedArtifactId;
288 
289     /**
290      * If specified, this will include only artifacts which have groupIds which
291      * start with this.
292      *
293      * @parameter expression="${shadedGroupFilter}"
294      */
295     private String shadedGroupFilter;
296 
297     /**
298      * Defines whether the shaded artifact should be attached as classifier to
299      * the original artifact.  If false, the shaded jar will be the main artifact
300      * of the project
301      *
302      * @parameter expression="${shadedArtifactAttached}" default-value="false"
303      */
304     private boolean shadedArtifactAttached;
305 
306     /**
307      * Flag whether to generate a simplified POM for the shaded artifact. If set to <code>true</code>, dependencies that
308      * have been included into the uber JAR will be removed from the <code>&lt;dependencies&gt;</code> section of the
309      * generated POM. The reduced POM will be named <code>dependency-reduced-pom.xml</code> and is stored into the same
310      * directory as the shaded artifact. Unless you also specify dependencyReducedPomLocation, the plugin will
311      * create a temporary file named <code>dependency-reduced-pom.xml</code> in the project basedir. 
312      *
313      * @parameter expression="${createDependencyReducedPom}" default-value="true"
314      */
315     private boolean createDependencyReducedPom;
316     
317     
318     /**
319      *  @parameter expression="${dependencyReducedPomLocation}" defaultValue="${basedir}/dependency-reduced-pom.xml"
320      *  Note: setting a value for this parameter with a directory other than ${basedir} will change the value of ${basedir}
321      *  for all executions that come after the shade execution. This is often not what you want. This is considered
322      *  an open issue with this plugin.
323      */
324     private File dependencyReducedPomLocation;
325 
326     /**
327      * When true, dependencies are kept in the pom but with scope 'provided'; when false,
328      * the dependency is removed.
329      *
330      * @parameter expression="${keepDependenciesWithProvidedScope}" default-value="false"
331      */
332     private boolean keepDependenciesWithProvidedScope;
333 
334     /**
335      * When true, transitive deps of removed dependencies are promoted to direct dependencies.
336      * This should allow the drop in replacement of the removed deps with the new shaded
337      * jar and everything should still work.
338      *
339      * @parameter expression="${promoteTransitiveDependencies}" default-value="false"
340      */
341     private boolean promoteTransitiveDependencies;
342 
343     /**
344      * The name of the classifier used in case the shaded artifact is attached.
345      *
346      * @parameter expression="${shadedClassifierName}" default-value="shaded"
347      */
348     private String shadedClassifierName;
349 
350     /**
351      * When true, it will attempt to create a sources jar as well
352      *
353      * @parameter expression="${createSourcesJar}" default-value="false"
354      */
355     private boolean createSourcesJar;
356 
357     /**
358      * When true, dependencies will be stripped down on the class level to only the transitive hull required for the
359      * artifact. <em>Note:</em> Usage of this feature requires Java 1.5 or higher.
360      *
361      * @parameter default-value="false"
362      * @since 1.4
363      */
364     private boolean minimizeJar;
365 
366     /**
367      * The path to the output file for the shaded artifact. When this parameter is set, the created archive will neither
368      * replace the project's main artifact nor will it be attached. Hence, this parameter causes the parameters
369      * {@link #finalName}, {@link #shadedArtifactAttached}, {@link #shadedClassifierName} and
370      * {@link #createDependencyReducedPom} to be ignored when used.
371      *
372      * @parameter
373      * @since 1.3
374      */
375     private File outputFile;
376 
377     /**
378      * You can pass here the roleHint about your own Shader implementation plexus component.
379      *
380      * @parameter
381      * @since 1.6
382      */
383     private String shaderHint;
384 
385     /**
386      * @since 1.6
387      */
388     private PlexusContainer plexusContainer;
389 
390     public void contextualize( Context context )
391         throws ContextException
392     {
393         plexusContainer = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
394     }
395 
396     /**
397      * @throws MojoExecutionException
398      */
399     public void execute()
400         throws MojoExecutionException
401     {
402 
403         if ( shaderHint != null )
404         {
405             try
406             {
407                 shader = (Shader) plexusContainer.lookup( Shader.ROLE, shaderHint );
408             }
409             catch ( ComponentLookupException e )
410             {
411                 throw new MojoExecutionException(
412                     "unable to lookup own Shader implementation with hint:'" + shaderHint + "'", e );
413             }
414         }
415 
416         Set<File> artifacts = new LinkedHashSet<File>();
417         Set<String> artifactIds = new LinkedHashSet<String>();
418         Set<File> sourceArtifacts = new LinkedHashSet<File>();
419 
420         ArtifactSelector artifactSelector =
421             new ArtifactSelector( project.getArtifact(), artifactSet, shadedGroupFilter );
422 
423         if ( artifactSelector.isSelected( project.getArtifact() ) && 
424                         !"pom".equals( project.getArtifact().getType() ) )
425         {
426             if ( invalidMainArtifact() )
427             {
428                 getLog().error( "The project main artifact does not exist. This could have the following" );
429                 getLog().error( "reasons:" );
430                 getLog().error( "- You have invoked the goal directly from the command line. This is not" );
431                 getLog().error( "  supported. Please add the goal to the default lifecycle via an" );
432                 getLog().error( "  <execution> element in your POM and use \"mvn package\" to have it run." );
433                 getLog().error( "- You have bound the goal to a lifecycle phase before \"package\". Please" );
434                 getLog().error( "  remove this binding from your POM such that the goal will be run in" );
435                 getLog().error( "  the proper phase." );
436                 getLog().error( "- You removed the configuration of the maven-jar-plugin that produces the main artifact." );
437                 throw new MojoExecutionException(
438                     "Failed to create shaded artifact, " + "project main artifact does not exist." );
439             }
440 
441             artifacts.add( project.getArtifact().getFile() );
442 
443             if ( createSourcesJar )
444             {
445                 File file = shadedSourcesArtifactFile();
446                 if ( file.isFile() )
447                 {
448                     sourceArtifacts.add( file );
449                 }
450             }
451         }
452 
453         for ( Iterator it = project.getArtifacts().iterator(); it.hasNext(); )
454         {
455             Artifact artifact = (Artifact) it.next();
456 
457             if ( !artifactSelector.isSelected( artifact ) )
458             {
459                 getLog().info( "Excluding " + artifact.getId() + " from the shaded jar." );
460 
461                 continue;
462             }
463 
464             if ( "pom".equals( artifact.getType() ) )
465             {
466                 getLog().info( "Skipping pom dependency " + artifact.getId() + " in the shaded jar." );
467                 continue;
468             }
469 
470             getLog().info( "Including " + artifact.getId() + " in the shaded jar." );
471 
472             artifacts.add( artifact.getFile() );
473             artifactIds.add( getId( artifact ) );
474 
475             if ( createSourcesJar )
476             {
477                 File file = resolveArtifactSources( artifact );
478                 if ( file != null )
479                 {
480                     sourceArtifacts.add( file );
481                 }
482             }
483         }
484 
485         File outputJar = ( outputFile != null ) ? outputFile : shadedArtifactFileWithClassifier();
486         File sourcesJar = shadedSourceArtifactFileWithClassifier();
487 
488         // Now add our extra resources
489         try
490         {
491             List<Filter> filters = getFilters();
492 
493             List<Relocator> relocators = getRelocators();
494 
495             List<ResourceTransformer> resourceTransformers = getResourceTransformers();
496 
497             shader.shade( artifacts, outputJar, filters, relocators, resourceTransformers );
498 
499             if ( createSourcesJar )
500             {
501                 shader.shade( sourceArtifacts, sourcesJar, filters, relocators, resourceTransformers );
502             }
503 
504             if ( outputFile == null )
505             {
506                 boolean renamed = false;
507 
508                 // rename the output file if a specific finalName is set
509                 // but don't rename if the finalName is the <build><finalName>
510                 // because this will be handled implicitly later
511                 if ( finalName != null && finalName.length() > 0 && !finalName.equals(
512                     project.getBuild().getFinalName() ) )
513                 {
514                     String finalFileName = finalName + "." + project.getArtifact().getArtifactHandler().getExtension();
515                     File finalFile = new File( outputDirectory, finalFileName );
516                     replaceFile( finalFile, outputJar );
517                     outputJar = finalFile;
518 
519                     renamed = true;
520                 }
521 
522                 if ( shadedArtifactAttached )
523                 {
524                     getLog().info( "Attaching shaded artifact." );
525                     projectHelper.attachArtifact( project, project.getArtifact().getType(), shadedClassifierName,
526                                                   outputJar );
527                     if ( createSourcesJar )
528                     {
529                         projectHelper.attachArtifact( project, "jar", shadedClassifierName + "-sources", sourcesJar );
530                     }
531                 }
532                 else if ( !renamed )
533                 {
534                     getLog().info( "Replacing original artifact with shaded artifact." );
535                     File originalArtifact = project.getArtifact().getFile();
536                     replaceFile( originalArtifact, outputJar );
537 
538                     if ( createSourcesJar )
539                     {
540                         File shadedSources = shadedSourcesArtifactFile();
541 
542                         replaceFile( shadedSources, sourcesJar );
543 
544                         projectHelper.attachArtifact( project, "jar", "sources", shadedSources );
545                     }
546 
547                     if ( createDependencyReducedPom )
548                     {
549                         createDependencyReducedPom( artifactIds );
550                     }
551                 }
552             }
553         }
554         catch ( Exception e )
555         {
556             throw new MojoExecutionException( "Error creating shaded jar: " + e.getMessage(), e );
557         }
558     }
559 
560     private boolean invalidMainArtifact( )
561     {
562         return project.getArtifact().getFile() == null || ! project.getArtifact().getFile().isFile();                                       
563     }
564 
565     private void replaceFile( File oldFile, File newFile )
566         throws MojoExecutionException
567     {
568         getLog().info( "Replacing " + oldFile + " with " + newFile );
569 
570         File origFile = new File( outputDirectory, "original-" + oldFile.getName() );
571         if ( oldFile.exists() && !oldFile.renameTo( origFile ) )
572         {
573             //try a gc to see if an unclosed stream needs garbage collecting
574             System.gc();
575             System.gc();
576 
577             if ( !oldFile.renameTo( origFile ) )
578             {
579                 // Still didn't work.   We'll do a copy
580                 try
581                 {
582                     FileOutputStream fout = new FileOutputStream( origFile );
583                     FileInputStream fin = new FileInputStream( oldFile );
584                     try
585                     {
586                         IOUtil.copy( fin, fout );
587                     }
588                     finally
589                     {
590                         IOUtil.close( fin );
591                         IOUtil.close( fout );
592                     }
593                 }
594                 catch ( IOException ex )
595                 {
596                     //kind of ignorable here.   We're just trying to save the original
597                     getLog().warn( ex );
598                 }
599             }
600         }
601         if ( !newFile.renameTo( oldFile ) )
602         {
603             //try a gc to see if an unclosed stream needs garbage collecting
604             System.gc();
605             System.gc();
606 
607             if ( !newFile.renameTo( oldFile ) )
608             {
609                 // Still didn't work.   We'll do a copy
610                 try
611                 {
612                     FileOutputStream fout = new FileOutputStream( oldFile );
613                     FileInputStream fin = new FileInputStream( newFile );
614                     try
615                     {
616                         IOUtil.copy( fin, fout );
617                     }
618                     finally
619                     {
620                         IOUtil.close( fin );
621                         IOUtil.close( fout );
622                     }
623                 }
624                 catch ( IOException ex )
625                 {
626                     throw new MojoExecutionException( "Could not replace original artifact with shaded artifact!", ex );
627                 }
628             }
629         }
630     }
631 
632     private File resolveArtifactSources( Artifact artifact )
633     {
634 
635         Artifact resolvedArtifact =
636             artifactFactory.createArtifactWithClassifier( artifact.getGroupId(), artifact.getArtifactId(),
637                                                           artifact.getVersion(), "java-source", "sources" );
638 
639         try
640         {
641             artifactResolver.resolve( resolvedArtifact, remoteArtifactRepositories, localRepository );
642         }
643         catch ( ArtifactNotFoundException e )
644         {
645             // ignore, the jar has not been found
646         }
647         catch ( ArtifactResolutionException e )
648         {
649             getLog().warn( "Could not get sources for " + artifact );
650         }
651 
652         if ( resolvedArtifact.isResolved() )
653         {
654             return resolvedArtifact.getFile();
655         }
656         return null;
657     }
658 
659     private List<Relocator> getRelocators()
660     {
661         List<Relocator> relocators = new ArrayList<Relocator>();
662 
663         if ( relocations == null )
664         {
665             return relocators;
666         }
667 
668         for ( int i = 0; i < relocations.length; i++ )
669         {
670             PackageRelocation r = relocations[i];
671 
672             relocators.add( new SimpleRelocator( r.getPattern(), r.getShadedPattern(), r.getIncludes(), r.getExcludes(),
673                                                  r.isRawString() ) );
674         }
675 
676         return relocators;
677     }
678 
679     private List<ResourceTransformer> getResourceTransformers()
680     {
681         if ( transformers == null )
682         {
683             return Collections.emptyList();
684         }
685 
686         return Arrays.asList( transformers );
687     }
688 
689     private List<Filter> getFilters()
690         throws MojoExecutionException
691     {
692         List<Filter> filters = new ArrayList<Filter>();
693         List<SimpleFilter> simpleFilters = new ArrayList<SimpleFilter>();
694 
695         if ( this.filters != null && this.filters.length > 0 )
696         {
697             Map<Artifact, ArtifactId> artifacts = new HashMap<Artifact, ArtifactId>();
698 
699             artifacts.put( project.getArtifact(), new ArtifactId( project.getArtifact() ) );
700 
701             for ( Iterator it = project.getArtifacts().iterator(); it.hasNext(); )
702             {
703                 Artifact artifact = (Artifact) it.next();
704 
705                 artifacts.put( artifact, new ArtifactId( artifact ) );
706             }
707 
708             for ( int i = 0; i < this.filters.length; i++ )
709             {
710                 ArchiveFilter filter = this.filters[i];
711 
712                 ArtifactId pattern = new ArtifactId( filter.getArtifact() );
713 
714                 Set<File> jars = new HashSet<File>();
715 
716                 for ( Iterator it = artifacts.entrySet().iterator(); it.hasNext(); )
717                 {
718                     Map.Entry entry = (Map.Entry) it.next();
719 
720                     if ( ( (ArtifactId) entry.getValue() ).matches( pattern ) )
721                     {
722                         Artifact 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     // We need to find the direct dependencies that have been included in the uber JAR so that we can modify the
804     // POM accordingly.
805     private void createDependencyReducedPom( Set<String> artifactsToRemove )
806         throws IOException, DependencyTreeBuilderException, 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 ( Iterator it = project.getArtifacts().iterator(); it.hasNext(); )
816         {
817             Artifact artifact = (Artifact) it.next();
818 
819             if ( "pom".equals( artifact.getType() ) )
820             {
821                 // don't include pom type dependencies in dependency reduced pom
822                 continue;
823             }
824 
825             //promote
826             Dependency dep = new Dependency();
827             dep.setArtifactId( artifact.getArtifactId() );
828             if ( artifact.hasClassifier() )
829             {
830                 dep.setClassifier( artifact.getClassifier() );
831             }
832             dep.setGroupId( artifact.getGroupId() );
833             dep.setOptional( artifact.isOptional() );
834             dep.setScope( artifact.getScope() );
835             dep.setType( artifact.getType() );
836             dep.setVersion( artifact.getVersion() );
837 
838             //we'll figure out the exclusions in a bit.
839 
840             transitiveDeps.add( dep );
841         }
842         List<Dependency> origDeps = project.getDependencies();
843 
844         if ( promoteTransitiveDependencies )
845         {
846             origDeps = transitiveDeps;
847         }
848 
849         for ( Iterator<Dependency> i = origDeps.iterator(); i.hasNext(); )
850         {
851             Dependency d = i.next();
852 
853             dependencies.add( d );
854 
855             String id = getId( d );
856 
857             if ( artifactsToRemove.contains( id ) )
858             {
859                 modified = true;
860 
861                 if ( keepDependenciesWithProvidedScope )
862                 {
863                     d.setScope( "provided" );
864                 }
865                 else
866                 {
867                     dependencies.remove( d );
868                 }
869             }
870         }
871 
872         // Check to see if we have a reduction and if so rewrite the POM.
873         if ( modified )
874         {
875             while ( modified )
876             {
877 
878                 model.setDependencies( dependencies );
879 
880                 if ( dependencyReducedPomLocation == null )
881                 {
882                     // MSHADE-123: We can't default to 'target' because it messes up uses of ${project.basedir}
883                     dependencyReducedPomLocation = new File ( project.getBasedir(), "dependency-reduced-pom.xml" );
884                 }
885                 
886                 File f = dependencyReducedPomLocation;
887                 if ( f.exists() )
888                 {
889                     f.delete();
890                 }
891 
892                 Writer w = WriterFactory.newXmlWriter( f );
893 
894                 String origRelativePath = null;
895                 String replaceRelativePath = null;
896                 if ( model.getParent() != null)
897                 {
898                     origRelativePath = model.getParent().getRelativePath();
899                     
900                 }
901                 replaceRelativePath = origRelativePath;
902 
903                 if ( origRelativePath == null )
904                 {
905                     origRelativePath = "../pom.xml";
906                 }
907 
908                 if ( model.getParent() != null ) 
909                 {
910                     File parentFile = new File( project.getBasedir(), model.getParent().getRelativePath() ).getCanonicalFile();
911                     if ( !parentFile.isFile() )
912                     {
913                         parentFile = new File( parentFile, "pom.xml");
914                     }
915                     
916                     parentFile = parentFile.getCanonicalFile();
917                     
918                     String relPath = RelativizePath.convertToRelativePath( parentFile, f );
919                     model.getParent().setRelativePath( relPath );
920                 }
921                 
922                 try
923                 {
924                     PomWriter.write( w, model, true );
925                 }
926                 finally
927                 {
928                     if ( model.getParent() != null )
929                     {
930                         model.getParent().setRelativePath( replaceRelativePath );
931                     }
932                     w.close();
933                 }
934 
935                 MavenProject p2 = mavenProjectBuilder.build( f, localRepository, null );
936                 modified = updateExcludesInDeps( p2, dependencies, transitiveDeps );
937 
938             }
939 
940             project.setFile( dependencyReducedPomLocation );
941         }
942     }
943     
944     private String getId( Artifact artifact )
945     {
946         return getId( artifact.getGroupId(), artifact.getArtifactId(), artifact.getType(), artifact.getClassifier() );
947     }
948 
949     private String getId( Dependency dependency )
950     {
951         return getId( dependency.getGroupId(), dependency.getArtifactId(), dependency.getType(),
952                       dependency.getClassifier() );
953     }
954 
955     private String getId( String groupId, String artifactId, String type, String classifier )
956     {
957         return groupId + ":" + artifactId + ":" + type + ":" + ( ( classifier != null ) ? classifier : "" );
958     }
959 
960     public boolean updateExcludesInDeps( MavenProject project, List<Dependency> dependencies, List<Dependency> transitiveDeps )
961         throws DependencyTreeBuilderException
962     {
963         DependencyNode node = dependencyTreeBuilder.buildDependencyTree( project, localRepository, artifactFactory,
964                                                                          artifactMetadataSource, null,
965                                                                          artifactCollector );
966         boolean modified = false;
967         Iterator it = node.getChildren().listIterator();
968         while ( it.hasNext() )
969         {
970             DependencyNode n2 = (DependencyNode) it.next();
971             Iterator it2 = n2.getChildren().listIterator();
972             while ( it2.hasNext() )
973             {
974                 DependencyNode n3 = (DependencyNode) it2.next();
975                 //anything two levels deep that is marked "included"
976                 //is stuff that was excluded by the original poms, make sure it
977                 //remains excluded IF promoting transitives.
978                 if ( n3.getState() == DependencyNode.INCLUDED )
979                 {
980                     //check if it really isn't in the list of original dependencies.  Maven
981                     //prior to 2.0.8 may grab versions from transients instead of
982                     //from the direct deps in which case they would be marked included
983                     //instead of OMITTED_FOR_DUPLICATE
984 
985                     //also, if not promoting the transitives, level 2's would be included
986                     boolean found = false;
987                     for ( int x = 0; x < transitiveDeps.size(); x++ )
988                     {
989                         Dependency dep = transitiveDeps.get( x );
990                         if ( dep.getArtifactId().equals( n3.getArtifact().getArtifactId() ) && dep.getGroupId().equals(
991                             n3.getArtifact().getGroupId() ) )
992                         {
993                             found = true;
994                         }
995 
996                     }
997 
998                     if ( !found )
999                     {
1000                         for ( int x = 0; x < dependencies.size(); x++ )
1001                         {
1002                             Dependency dep = dependencies.get( x );
1003                             if ( dep.getArtifactId().equals( n2.getArtifact().getArtifactId() )
1004                                 && dep.getGroupId().equals( n2.getArtifact().getGroupId() ) )
1005                             {
1006                                 Exclusion exclusion = new Exclusion();
1007                                 exclusion.setArtifactId( n3.getArtifact().getArtifactId() );
1008                                 exclusion.setGroupId( n3.getArtifact().getGroupId() );
1009                                 dep.addExclusion( exclusion );
1010                                 modified = true;
1011                                 break;
1012                             }
1013                         }
1014                     }
1015                 }
1016             }
1017         }
1018         return modified;
1019     }
1020 }