View Javadoc
1   package org.apache.maven.repository.internal;
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 java.io.FileInputStream;
23  import java.util.ArrayList;
24  import java.util.Collections;
25  import java.util.HashMap;
26  import java.util.List;
27  import java.util.Map;
28  
29  import javax.inject.Inject;
30  import javax.inject.Named;
31  
32  import org.apache.maven.artifact.repository.metadata.Versioning;
33  import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader;
34  import org.codehaus.plexus.component.annotations.Component;
35  import org.codehaus.plexus.component.annotations.Requirement;
36  import org.codehaus.plexus.util.IOUtil;
37  import org.eclipse.aether.RepositoryEvent.EventType;
38  import org.eclipse.aether.RepositoryEvent;
39  import org.eclipse.aether.RepositorySystemSession;
40  import org.eclipse.aether.RequestTrace;
41  import org.eclipse.aether.SyncContext;
42  import org.eclipse.aether.impl.MetadataResolver;
43  import org.eclipse.aether.impl.RepositoryEventDispatcher;
44  import org.eclipse.aether.impl.SyncContextFactory;
45  import org.eclipse.aether.impl.VersionRangeResolver;
46  import org.eclipse.aether.metadata.DefaultMetadata;
47  import org.eclipse.aether.metadata.Metadata;
48  import org.eclipse.aether.repository.ArtifactRepository;
49  import org.eclipse.aether.repository.RemoteRepository;
50  import org.eclipse.aether.repository.WorkspaceReader;
51  import org.eclipse.aether.resolution.MetadataRequest;
52  import org.eclipse.aether.resolution.MetadataResult;
53  import org.eclipse.aether.resolution.VersionRangeRequest;
54  import org.eclipse.aether.resolution.VersionRangeResolutionException;
55  import org.eclipse.aether.resolution.VersionRangeResult;
56  import org.eclipse.aether.spi.locator.Service;
57  import org.eclipse.aether.spi.locator.ServiceLocator;
58  import org.eclipse.aether.spi.log.Logger;
59  import org.eclipse.aether.spi.log.LoggerFactory;
60  import org.eclipse.aether.spi.log.NullLoggerFactory;
61  import org.eclipse.aether.util.version.GenericVersionScheme;
62  import org.eclipse.aether.version.InvalidVersionSpecificationException;
63  import org.eclipse.aether.version.Version;
64  import org.eclipse.aether.version.VersionConstraint;
65  import org.eclipse.aether.version.VersionScheme;
66  
67  /**
68   * @author Benjamin Bentmann
69   */
70  @Named
71  @Component( role = VersionRangeResolver.class )
72  public class DefaultVersionRangeResolver
73      implements VersionRangeResolver, Service
74  {
75  
76      private static final String MAVEN_METADATA_XML = "maven-metadata.xml";
77  
78      @SuppressWarnings( "unused" )
79      @Requirement( role = LoggerFactory.class )
80      private Logger logger = NullLoggerFactory.LOGGER;
81  
82      @Requirement
83      private MetadataResolver metadataResolver;
84  
85      @Requirement
86      private SyncContextFactory syncContextFactory;
87  
88      @Requirement
89      private RepositoryEventDispatcher repositoryEventDispatcher;
90  
91      public DefaultVersionRangeResolver()
92      {
93          // enable default constructor
94      }
95  
96      @Inject
97      DefaultVersionRangeResolver( MetadataResolver metadataResolver, SyncContextFactory syncContextFactory,
98                                   RepositoryEventDispatcher repositoryEventDispatcher, LoggerFactory loggerFactory )
99      {
100         setMetadataResolver( metadataResolver );
101         setSyncContextFactory( syncContextFactory );
102         setLoggerFactory( loggerFactory );
103         setRepositoryEventDispatcher( repositoryEventDispatcher );
104     }
105 
106     public void initService( ServiceLocator locator )
107     {
108         setLoggerFactory( locator.getService( LoggerFactory.class ) );
109         setMetadataResolver( locator.getService( MetadataResolver.class ) );
110         setSyncContextFactory( locator.getService( SyncContextFactory.class ) );
111         setRepositoryEventDispatcher( locator.getService( RepositoryEventDispatcher.class ) );
112     }
113 
114     public DefaultVersionRangeResolver setLoggerFactory( LoggerFactory loggerFactory )
115     {
116         this.logger = NullLoggerFactory.getSafeLogger( loggerFactory, getClass() );
117         return this;
118     }
119 
120     void setLogger( LoggerFactory loggerFactory )
121     {
122         // plexus support
123         setLoggerFactory( loggerFactory );
124     }
125 
126     public DefaultVersionRangeResolver setMetadataResolver( MetadataResolver metadataResolver )
127     {
128         if ( metadataResolver == null )
129         {
130             throw new IllegalArgumentException( "metadata resolver has not been specified" );
131         }
132         this.metadataResolver = metadataResolver;
133         return this;
134     }
135 
136     public DefaultVersionRangeResolver setSyncContextFactory( SyncContextFactory syncContextFactory )
137     {
138         if ( syncContextFactory == null )
139         {
140             throw new IllegalArgumentException( "sync context factory has not been specified" );
141         }
142         this.syncContextFactory = syncContextFactory;
143         return this;
144     }
145 
146     public DefaultVersionRangeResolver setRepositoryEventDispatcher( RepositoryEventDispatcher red )
147     {
148         if ( red == null )
149         {
150             throw new IllegalArgumentException( "repository event dispatcher has not been specified" );
151         }
152         this.repositoryEventDispatcher = red;
153         return this;
154     }
155 
156     public VersionRangeResult resolveVersionRange( RepositorySystemSession session, VersionRangeRequest request )
157         throws VersionRangeResolutionException
158     {
159         VersionRangeResult result = new VersionRangeResult( request );
160 
161         VersionScheme versionScheme = new GenericVersionScheme();
162 
163         VersionConstraint versionConstraint;
164         try
165         {
166             versionConstraint = versionScheme.parseVersionConstraint( request.getArtifact().getVersion() );
167         }
168         catch ( InvalidVersionSpecificationException e )
169         {
170             result.addException( e );
171             throw new VersionRangeResolutionException( result );
172         }
173 
174         result.setVersionConstraint( versionConstraint );
175 
176         if ( versionConstraint.getRange() == null )
177         {
178             result.addVersion( versionConstraint.getVersion() );
179         }
180         else
181         {
182             Map<String, ArtifactRepository> versionIndex = getVersions( session, result, request );
183 
184             List<Version> versions = new ArrayList<Version>();
185             for ( Map.Entry<String, ArtifactRepository> v : versionIndex.entrySet() )
186             {
187                 try
188                 {
189                     Version ver = versionScheme.parseVersion( v.getKey() );
190                     if ( versionConstraint.containsVersion( ver ) )
191                     {
192                         versions.add( ver );
193                         result.setRepository( ver, v.getValue() );
194                     }
195                 }
196                 catch ( InvalidVersionSpecificationException e )
197                 {
198                     result.addException( e );
199                 }
200             }
201 
202             Collections.sort( versions );
203             result.setVersions( versions );
204         }
205 
206         return result;
207     }
208 
209     private Map<String, ArtifactRepository> getVersions( RepositorySystemSession session, VersionRangeResult result,
210                                                          VersionRangeRequest request )
211     {
212         RequestTrace trace = RequestTrace.newChild( request.getTrace(), request );
213 
214         Map<String, ArtifactRepository> versionIndex = new HashMap<String, ArtifactRepository>();
215 
216         Metadata metadata =
217             new DefaultMetadata( request.getArtifact().getGroupId(), request.getArtifact().getArtifactId(),
218                                  MAVEN_METADATA_XML, Metadata.Nature.RELEASE_OR_SNAPSHOT );
219 
220         List<MetadataRequest> metadataRequests = new ArrayList<MetadataRequest>( request.getRepositories().size() );
221 
222         metadataRequests.add( new MetadataRequest( metadata, null, request.getRequestContext() ) );
223 
224         for ( RemoteRepository repository : request.getRepositories() )
225         {
226             MetadataRequest metadataRequest = new MetadataRequest( metadata, repository, request.getRequestContext() );
227             metadataRequest.setDeleteLocalCopyIfMissing( true );
228             metadataRequest.setTrace( trace );
229             metadataRequests.add( metadataRequest );
230         }
231 
232         List<MetadataResult> metadataResults = metadataResolver.resolveMetadata( session, metadataRequests );
233 
234         WorkspaceReader workspace = session.getWorkspaceReader();
235         if ( workspace != null )
236         {
237             List<String> versions = workspace.findVersions( request.getArtifact() );
238             for ( String version : versions )
239             {
240                 versionIndex.put( version, workspace.getRepository() );
241             }
242         }
243 
244         for ( MetadataResult metadataResult : metadataResults )
245         {
246             result.addException( metadataResult.getException() );
247 
248             ArtifactRepository repository = metadataResult.getRequest().getRepository();
249             if ( repository == null )
250             {
251                 repository = session.getLocalRepository();
252             }
253 
254             Versioning versioning = readVersions( session, trace, metadataResult.getMetadata(), repository, result );
255             for ( String version : versioning.getVersions() )
256             {
257                 if ( !versionIndex.containsKey( version ) )
258                 {
259                     versionIndex.put( version, repository );
260                 }
261             }
262         }
263 
264         return versionIndex;
265     }
266 
267     private Versioning readVersions( RepositorySystemSession session, RequestTrace trace, Metadata metadata,
268                                      ArtifactRepository repository, VersionRangeResult result )
269     {
270         Versioning versioning = null;
271 
272         FileInputStream fis = null;
273         try
274         {
275             if ( metadata != null )
276             {
277                 SyncContext syncContext = syncContextFactory.newInstance( session, true );
278 
279                 try
280                 {
281                     syncContext.acquire( null, Collections.singleton( metadata ) );
282 
283                     if ( metadata.getFile() != null && metadata.getFile().exists() )
284                     {
285                         fis = new FileInputStream( metadata.getFile() );
286                         org.apache.maven.artifact.repository.metadata.Metadata m =
287                             new MetadataXpp3Reader().read( fis, false );
288                         versioning = m.getVersioning();
289                     }
290                 }
291                 finally
292                 {
293                     syncContext.close();
294                 }
295             }
296         }
297         catch ( Exception e )
298         {
299             invalidMetadata( session, trace, metadata, repository, e );
300             result.addException( e );
301         }
302         finally
303         {
304             IOUtil.close( fis );
305         }
306 
307         return ( versioning != null ) ? versioning : new Versioning();
308     }
309 
310     private void invalidMetadata( RepositorySystemSession session, RequestTrace trace, Metadata metadata,
311                                   ArtifactRepository repository, Exception exception )
312     {
313         RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.METADATA_INVALID );
314         event.setTrace( trace );
315         event.setMetadata( metadata );
316         event.setException( exception );
317         event.setRepository( repository );
318 
319         repositoryEventDispatcher.dispatch( event.build() );
320     }
321 
322 }