View Javadoc
1   package org.codehaus.mojo.webstart.util;
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.commons.collections.CollectionUtils;
23  import org.apache.maven.artifact.Artifact;
24  import org.apache.maven.artifact.factory.ArtifactFactory;
25  import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
26  import org.apache.maven.artifact.repository.ArtifactRepository;
27  import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
28  import org.apache.maven.artifact.resolver.ArtifactResolutionException;
29  import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
30  import org.apache.maven.artifact.resolver.ArtifactResolver;
31  import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
32  import org.apache.maven.plugin.MojoExecutionException;
33  import org.apache.maven.project.MavenProject;
34  import org.codehaus.mojo.webstart.JarResource;
35  import org.codehaus.plexus.component.annotations.Component;
36  import org.codehaus.plexus.component.annotations.Requirement;
37  import org.codehaus.plexus.logging.AbstractLogEnabled;
38  
39  import java.net.MalformedURLException;
40  import java.net.URL;
41  import java.util.LinkedHashSet;
42  import java.util.List;
43  import java.util.Map;
44  import java.util.Set;
45  
46  /**
47   * Default implementation of {@link ArtifactUtil}.
48   *
49   * @author tchemit <chemit@codelutin.com>
50   * @since 1.0-beta-4
51   */
52  @Component( role = ArtifactUtil.class, hint = "default" )
53  public class DefaultArtifactUtil
54      extends AbstractLogEnabled
55      implements ArtifactUtil
56  {
57  
58      /**
59       */
60      @Requirement
61      private ArtifactFactory artifactFactory;
62  
63      /**
64       * Artifact resolver, needed to download source jars for inclusion in classpath.
65       */
66      @Requirement
67      private ArtifactResolver artifactResolver;
68  
69      /**
70       * The project's artifact metadata source, used to resolve transitive dependencies.
71       */
72      @Requirement
73      private ArtifactMetadataSource artifactMetadataSource;
74  
75      /**
76       * {@inheritDoc}
77       */
78      public Artifact createArtifact( JarResource jarResource )
79      {
80  
81          if ( jarResource.getClassifier() == null )
82          {
83              return artifactFactory.createArtifact( jarResource.getGroupId(), jarResource.getArtifactId(),
84                                                     jarResource.getVersion(), Artifact.SCOPE_RUNTIME, "jar" );
85          }
86          else
87          {
88              return artifactFactory.createArtifactWithClassifier( jarResource.getGroupId(), jarResource.getArtifactId(),
89                                                                   jarResource.getVersion(), "jar",
90                                                                   jarResource.getClassifier() );
91          }
92      }
93  
94      /**
95       * {@inheritDoc}
96       */
97      public MavenProject resolveFromReactor( Artifact artifact, MavenProject mp, List<MavenProject> reactorProjects )
98          throws MojoExecutionException
99      {
100         MavenProject result = null;
101 
102         String artifactId = artifact.getArtifactId();
103         String groupId = artifact.getGroupId();
104 
105         if ( CollectionUtils.isNotEmpty( reactorProjects ) )
106         {
107             for ( MavenProject reactorProject : reactorProjects )
108             {
109                 if ( reactorProject.getArtifactId().equals( artifactId ) &&
110                     reactorProject.getGroupId().equals( groupId ) )
111                 {
112                     result = reactorProject;
113                     break;
114                 }
115             }
116         }
117 
118         return result;
119     }
120 
121     /**
122      * {@inheritDoc}
123      */
124     public void resolveFromRepositories( Artifact artifact, List remoteRepositories,
125                                          ArtifactRepository localRepository )
126         throws MojoExecutionException
127     {
128         try
129         {
130             artifactResolver.resolve( artifact, remoteRepositories, localRepository );
131         }
132         catch ( ArtifactResolutionException e )
133         {
134             throw new MojoExecutionException( "Could not resolv artifact: " + artifact, e );
135         }
136         catch ( ArtifactNotFoundException e )
137         {
138             throw new MojoExecutionException( "Could not find artifact: " + artifact, e );
139         }
140     }
141 
142     /**
143      * {@inheritDoc}
144      */
145     public Set<Artifact> resolveTransitively( Set<Artifact> jarResourceArtifacts, Set<MavenProject> siblingProjects,
146                                               Artifact originateArtifact, ArtifactRepository localRepository,
147                                               List<ArtifactRepository> remoteRepositories,
148                                               ArtifactFilter artifactFilter, Map managedVersions)
149         throws MojoExecutionException
150     {
151 
152         Set<Artifact> resultArtifacts = new LinkedHashSet<Artifact>();
153 
154         if ( CollectionUtils.isNotEmpty( siblingProjects ) )
155         {
156 
157             // getting transitive dependencies from project
158             for ( MavenProject siblingProject : siblingProjects )
159             {
160                 Set<Artifact> artifacts = siblingProject.getArtifacts();
161                 for ( Artifact artifact : artifacts )
162                 {
163                     if ( artifactFilter.include( artifact ) )
164                     {
165 
166                         resultArtifacts.add( artifact );
167                     }
168                 }
169             }
170         }
171         try
172         {
173             ArtifactResolutionResult result =
174                 artifactResolver.resolveTransitively( jarResourceArtifacts, originateArtifact,
175                                                       managedVersions,
176                                                       localRepository, remoteRepositories, this.artifactMetadataSource,
177                                                       artifactFilter );
178 
179             resultArtifacts.addAll( result.getArtifacts() );
180 
181             return resultArtifacts;
182         }
183         catch ( ArtifactResolutionException e )
184         {
185             throw new MojoExecutionException( "Could not resolv transitive dependencies", e );
186         }
187         catch ( ArtifactNotFoundException e )
188         {
189             throw new MojoExecutionException( "Could not find transitive dependencies ", e );
190         }
191     }
192 
193     /**
194      * Tests if the given fully qualified name exists in the given artifact.
195      *
196      * @param artifact  artifact to test
197      * @param mainClass the fully qualified name to find in artifact
198      * @return {@code true} if given artifact contains the given fqn, {@code false} otherwise
199      * @throws MojoExecutionException if artifact file url is mal formed
200      */
201 
202     public boolean artifactContainsClass( Artifact artifact, final String mainClass )
203         throws MojoExecutionException
204     {
205         boolean containsClass = true;
206 
207         // JarArchiver.grabFilesAndDirs()
208         URL url;
209         try
210         {
211             url = artifact.getFile().toURI().toURL();
212         }
213         catch ( MalformedURLException e )
214         {
215             throw new MojoExecutionException( "Could not get artifact url: " + artifact.getFile(), e );
216         }
217         ClassLoader cl = new java.net.URLClassLoader( new URL[]{ url } );
218         Class<?> c = null;
219         try
220         {
221             c = Class.forName( mainClass, false, cl );
222         }
223         catch ( ClassNotFoundException e )
224         {
225             getLogger().debug( "artifact " + artifact + " doesn't contain the main class: " + mainClass );
226             containsClass = false;
227         }
228         catch ( Throwable t )
229         {
230             getLogger().info( "artifact " + artifact + " seems to contain the main class: " + mainClass +
231                                   " but the jar doesn't seem to contain all dependencies " + t.getMessage() );
232         }
233 
234         if ( c != null )
235         {
236             getLogger().debug( "Checking if the loaded class contains a main method." );
237 
238             try
239             {
240                 c.getMethod( "main", String[].class );
241             }
242             catch ( NoSuchMethodException e )
243             {
244                 getLogger().warn(
245                     "The specified main class (" + mainClass + ") doesn't seem to contain a main method... " +
246                         "Please check your configuration." + e.getMessage() );
247             }
248             catch ( NoClassDefFoundError e )
249             {
250                 // undocumented in SDK 5.0. is this due to the ClassLoader lazy loading the Method
251                 // thus making this a case tackled by the JVM Spec (Ref 5.3.5)!
252                 // Reported as Incident 633981 to Sun just in case ...
253                 getLogger().warn( "Something failed while checking if the main class contains the main() method. " +
254                                       "This is probably due to the limited classpath we have provided to the class loader. " +
255                                       "The specified main class (" + mainClass +
256                                       ") found in the jar is *assumed* to contain a main method... " + e.getMessage() );
257             }
258             catch ( Throwable t )
259             {
260                 getLogger().error( "Unknown error: Couldn't check if the main class has a main method. " +
261                                        "The specified main class (" + mainClass +
262                                        ") found in the jar is *assumed* to contain a main method...", t );
263             }
264         }
265 
266         return containsClass;
267     }
268 }