View Javadoc

1   package org.apache.maven;
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.ArtifactUtils;
23  import org.apache.maven.project.MavenProject;
24  import org.sonatype.aether.artifact.Artifact;
25  import org.sonatype.aether.repository.WorkspaceReader;
26  import org.sonatype.aether.repository.WorkspaceRepository;
27  
28  import java.io.File;
29  import java.util.ArrayList;
30  import java.util.Collection;
31  import java.util.Collections;
32  import java.util.HashMap;
33  import java.util.HashSet;
34  import java.util.List;
35  import java.util.Map;
36  
37  /**
38   * An implementation of a workspace reader that knows how to search the Maven reactor for artifacts.
39   * 
40   * @author Jason van Zyl
41   */
42  class ReactorReader
43      implements WorkspaceReader
44  {
45  
46      private Map<String, MavenProject> projectsByGAV;
47  
48      private Map<String, List<MavenProject>> projectsByGA;
49  
50      private WorkspaceRepository repository;
51  
52      public ReactorReader( Map<String, MavenProject> reactorProjects )
53      {
54          projectsByGAV = reactorProjects;
55  
56          projectsByGA = new HashMap<String, List<MavenProject>>( reactorProjects.size() * 2 );
57          for ( MavenProject project : reactorProjects.values() )
58          {
59              String key = ArtifactUtils.versionlessKey( project.getGroupId(), project.getArtifactId() );
60  
61              List<MavenProject> projects = projectsByGA.get( key );
62  
63              if ( projects == null )
64              {
65                  projects = new ArrayList<MavenProject>( 1 );
66                  projectsByGA.put( key, projects );
67              }
68  
69              projects.add( project );
70          }
71  
72          repository = new WorkspaceRepository( "reactor", new HashSet<String>( projectsByGAV.keySet() ) );
73      }
74  
75      private File find( MavenProject project, Artifact artifact )
76      {
77          if ( "pom".equals( artifact.getExtension() ) )
78          {
79              return project.getFile();
80          }
81  
82          org.apache.maven.artifact.Artifact projectArtifact = findMatchingArtifact( project, artifact );
83  
84          if ( hasArtifactFileFromPackagePhase( projectArtifact ) )
85          {
86              return projectArtifact.getFile();
87          }
88          else if ( !hasBeenPackaged( project ) )
89          {
90              // fallback to loose class files only if artifacts haven't been packaged yet
91  
92              if ( isTestArtifact( artifact ) )
93              {
94                  if ( project.hasLifecyclePhase( "test-compile" ) )
95                  {
96                      return new File( project.getBuild().getTestOutputDirectory() );
97                  }
98              }
99              else
100             {
101                 if ( project.hasLifecyclePhase( "compile" ) )
102                 {
103                     return new File( project.getBuild().getOutputDirectory() );
104                 }
105             }
106         }
107 
108         // The fall-through indicates that the artifact cannot be found;
109         // for instance if package produced nothing or classifier problems.
110         return null;
111     }
112 
113     private boolean hasArtifactFileFromPackagePhase( org.apache.maven.artifact.Artifact projectArtifact )
114     {
115         return projectArtifact != null && projectArtifact.getFile() != null && projectArtifact.getFile().exists();
116     }
117 
118     private boolean hasBeenPackaged( MavenProject project )
119     {
120         return project.hasLifecyclePhase( "package" ) || project.hasLifecyclePhase( "install" )
121             || project.hasLifecyclePhase( "deploy" );
122     }
123 
124     /**
125      * Tries to resolve the specified artifact from the artifacts of the given project.
126      * 
127      * @param project The project to try to resolve the artifact from, must not be <code>null</code>.
128      * @param requestedArtifact The artifact to resolve, must not be <code>null</code>.
129      * @return The matching artifact from the project or <code>null</code> if not found.
130      */
131     private org.apache.maven.artifact.Artifact findMatchingArtifact( MavenProject project, Artifact requestedArtifact )
132     {
133         String requestedRepositoryConflictId = getConflictId( requestedArtifact );
134 
135         org.apache.maven.artifact.Artifact mainArtifact = project.getArtifact();
136         if ( requestedRepositoryConflictId.equals( getConflictId( mainArtifact ) ) )
137         {
138             return mainArtifact;
139         }
140 
141         Collection<org.apache.maven.artifact.Artifact> attachedArtifacts = project.getAttachedArtifacts();
142         if ( attachedArtifacts != null && !attachedArtifacts.isEmpty() )
143         {
144             for ( org.apache.maven.artifact.Artifact attachedArtifact : attachedArtifacts )
145             {
146                 if ( requestedRepositoryConflictId.equals( getConflictId( attachedArtifact ) ) )
147                 {
148                     return attachedArtifact;
149                 }
150             }
151         }
152 
153         return null;
154     }
155 
156     /**
157      * Gets the repository conflict id of the specified artifact. Unlike the dependency conflict id, the repository
158      * conflict id uses the artifact file extension instead of the artifact type. Hence, the repository conflict id more
159      * closely reflects the identity of artifacts as perceived by a repository.
160      * 
161      * @param artifact The artifact, must not be <code>null</code>.
162      * @return The repository conflict id, never <code>null</code>.
163      */
164     private String getConflictId( org.apache.maven.artifact.Artifact artifact )
165     {
166         StringBuilder buffer = new StringBuilder( 128 );
167         buffer.append( artifact.getGroupId() );
168         buffer.append( ':' ).append( artifact.getArtifactId() );
169         if ( artifact.getArtifactHandler() != null )
170         {
171             buffer.append( ':' ).append( artifact.getArtifactHandler().getExtension() );
172         }
173         else
174         {
175             buffer.append( ':' ).append( artifact.getType() );
176         }
177         if ( artifact.hasClassifier() )
178         {
179             buffer.append( ':' ).append( artifact.getClassifier() );
180         }
181         return buffer.toString();
182     }
183 
184     private String getConflictId( Artifact artifact )
185     {
186         StringBuilder buffer = new StringBuilder( 128 );
187         buffer.append( artifact.getGroupId() );
188         buffer.append( ':' ).append( artifact.getArtifactId() );
189         buffer.append( ':' ).append( artifact.getExtension() );
190         if ( artifact.getClassifier().length() > 0 )
191         {
192             buffer.append( ':' ).append( artifact.getClassifier() );
193         }
194         return buffer.toString();
195     }
196 
197     /**
198      * Determines whether the specified artifact refers to test classes.
199      * 
200      * @param artifact The artifact to check, must not be {@code null}.
201      * @return {@code true} if the artifact refers to test classes, {@code false} otherwise.
202      */
203     private static boolean isTestArtifact( Artifact artifact )
204     {
205         return ( "test-jar".equals( artifact.getProperty( "type", "" ) ) )
206             || ( "jar".equals( artifact.getExtension() ) && "tests".equals( artifact.getClassifier() ) );
207     }
208 
209     public File findArtifact( Artifact artifact )
210     {
211         String projectKey = ArtifactUtils.key( artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion() );
212 
213         MavenProject project = projectsByGAV.get( projectKey );
214 
215         if ( project != null )
216         {
217             File file = find( project, artifact );
218             if ( file == null && project != project.getExecutionProject() )
219             {
220                 file = find( project.getExecutionProject(), artifact );
221             }
222             return file;
223         }
224 
225         return null;
226     }
227 
228     public List<String> findVersions( Artifact artifact )
229     {
230         String key = ArtifactUtils.versionlessKey( artifact.getGroupId(), artifact.getArtifactId() );
231 
232         List<MavenProject> projects = projectsByGA.get( key );
233         if ( projects == null || projects.isEmpty() )
234         {
235             return Collections.emptyList();
236         }
237 
238         List<String> versions = new ArrayList<String>();
239 
240         for ( MavenProject project : projects )
241         {
242             if ( find( project, artifact ) != null )
243             {
244                 versions.add( project.getVersion() );
245             }
246         }
247 
248         return Collections.unmodifiableList( versions );
249     }
250 
251     public WorkspaceRepository getRepository()
252     {
253         return repository;
254     }
255 
256 }