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