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 org.apache.commons.lang3.Validate;
23  import org.apache.maven.artifact.repository.metadata.Versioning;
24  import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader;
25  import org.codehaus.plexus.component.annotations.Component;
26  import org.codehaus.plexus.component.annotations.Requirement;
27  import org.codehaus.plexus.util.IOUtil;
28  import org.eclipse.aether.RepositoryEvent;
29  import org.eclipse.aether.RepositoryEvent.EventType;
30  import org.eclipse.aether.RepositorySystemSession;
31  import org.eclipse.aether.RequestTrace;
32  import org.eclipse.aether.SyncContext;
33  import org.eclipse.aether.impl.MetadataResolver;
34  import org.eclipse.aether.impl.RepositoryEventDispatcher;
35  import org.eclipse.aether.impl.SyncContextFactory;
36  import org.eclipse.aether.impl.VersionRangeResolver;
37  import org.eclipse.aether.metadata.DefaultMetadata;
38  import org.eclipse.aether.metadata.Metadata;
39  import org.eclipse.aether.repository.ArtifactRepository;
40  import org.eclipse.aether.repository.RemoteRepository;
41  import org.eclipse.aether.repository.WorkspaceReader;
42  import org.eclipse.aether.resolution.MetadataRequest;
43  import org.eclipse.aether.resolution.MetadataResult;
44  import org.eclipse.aether.resolution.VersionRangeRequest;
45  import org.eclipse.aether.resolution.VersionRangeResolutionException;
46  import org.eclipse.aether.resolution.VersionRangeResult;
47  import org.eclipse.aether.spi.locator.Service;
48  import org.eclipse.aether.spi.locator.ServiceLocator;
49  import org.eclipse.aether.spi.log.Logger;
50  import org.eclipse.aether.spi.log.LoggerFactory;
51  import org.eclipse.aether.spi.log.NullLoggerFactory;
52  import org.eclipse.aether.util.version.GenericVersionScheme;
53  import org.eclipse.aether.version.InvalidVersionSpecificationException;
54  import org.eclipse.aether.version.Version;
55  import org.eclipse.aether.version.VersionConstraint;
56  import org.eclipse.aether.version.VersionScheme;
57  
58  import javax.inject.Inject;
59  import javax.inject.Named;
60  import java.io.FileInputStream;
61  import java.util.ArrayList;
62  import java.util.Collections;
63  import java.util.HashMap;
64  import java.util.List;
65  import java.util.Map;
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         this.metadataResolver = Validate.notNull( metadataResolver, "metadataResolver cannot be null" );
129         return this;
130     }
131 
132     public DefaultVersionRangeResolver setSyncContextFactory( SyncContextFactory syncContextFactory )
133     {
134         this.syncContextFactory = Validate.notNull( syncContextFactory, "syncContextFactory cannot be null" );
135         return this;
136     }
137 
138     public DefaultVersionRangeResolver setRepositoryEventDispatcher(
139         RepositoryEventDispatcher repositoryEventDispatcher )
140     {
141         this.repositoryEventDispatcher = Validate.notNull( repositoryEventDispatcher,
142             "repositoryEventDispatcher cannot be null" );
143         return this;
144     }
145 
146     public VersionRangeResult resolveVersionRange( RepositorySystemSession session, VersionRangeRequest request )
147         throws VersionRangeResolutionException
148     {
149         VersionRangeResult result = new VersionRangeResult( request );
150 
151         VersionScheme versionScheme = new GenericVersionScheme();
152 
153         VersionConstraint versionConstraint;
154         try
155         {
156             versionConstraint = versionScheme.parseVersionConstraint( request.getArtifact().getVersion() );
157         }
158         catch ( InvalidVersionSpecificationException e )
159         {
160             result.addException( e );
161             throw new VersionRangeResolutionException( result );
162         }
163 
164         result.setVersionConstraint( versionConstraint );
165 
166         if ( versionConstraint.getRange() == null )
167         {
168             result.addVersion( versionConstraint.getVersion() );
169         }
170         else
171         {
172             Map<String, ArtifactRepository> versionIndex = getVersions( session, result, request );
173 
174             List<Version> versions = new ArrayList<>();
175             for ( Map.Entry<String, ArtifactRepository> v : versionIndex.entrySet() )
176             {
177                 try
178                 {
179                     Version ver = versionScheme.parseVersion( v.getKey() );
180                     if ( versionConstraint.containsVersion( ver ) )
181                     {
182                         versions.add( ver );
183                         result.setRepository( ver, v.getValue() );
184                     }
185                 }
186                 catch ( InvalidVersionSpecificationException e )
187                 {
188                     result.addException( e );
189                 }
190             }
191 
192             Collections.sort( versions );
193             result.setVersions( versions );
194         }
195 
196         return result;
197     }
198 
199     private Map<String, ArtifactRepository> getVersions( RepositorySystemSession session, VersionRangeResult result,
200                                                          VersionRangeRequest request )
201     {
202         RequestTrace trace = RequestTrace.newChild( request.getTrace(), request );
203 
204         Map<String, ArtifactRepository> versionIndex = new HashMap<>();
205 
206         Metadata metadata =
207             new DefaultMetadata( request.getArtifact().getGroupId(), request.getArtifact().getArtifactId(),
208                                  MAVEN_METADATA_XML, Metadata.Nature.RELEASE_OR_SNAPSHOT );
209 
210         List<MetadataRequest> metadataRequests = new ArrayList<>( request.getRepositories().size() );
211 
212         metadataRequests.add( new MetadataRequest( metadata, null, request.getRequestContext() ) );
213 
214         for ( RemoteRepository repository : request.getRepositories() )
215         {
216             MetadataRequest metadataRequest = new MetadataRequest( metadata, repository, request.getRequestContext() );
217             metadataRequest.setDeleteLocalCopyIfMissing( true );
218             metadataRequest.setTrace( trace );
219             metadataRequests.add( metadataRequest );
220         }
221 
222         List<MetadataResult> metadataResults = metadataResolver.resolveMetadata( session, metadataRequests );
223 
224         WorkspaceReader workspace = session.getWorkspaceReader();
225         if ( workspace != null )
226         {
227             List<String> versions = workspace.findVersions( request.getArtifact() );
228             for ( String version : versions )
229             {
230                 versionIndex.put( version, workspace.getRepository() );
231             }
232         }
233 
234         for ( MetadataResult metadataResult : metadataResults )
235         {
236             result.addException( metadataResult.getException() );
237 
238             ArtifactRepository repository = metadataResult.getRequest().getRepository();
239             if ( repository == null )
240             {
241                 repository = session.getLocalRepository();
242             }
243 
244             Versioning versioning = readVersions( session, trace, metadataResult.getMetadata(), repository, result );
245             for ( String version : versioning.getVersions() )
246             {
247                 if ( !versionIndex.containsKey( version ) )
248                 {
249                     versionIndex.put( version, repository );
250                 }
251             }
252         }
253 
254         return versionIndex;
255     }
256 
257     private Versioning readVersions( RepositorySystemSession session, RequestTrace trace, Metadata metadata,
258                                      ArtifactRepository repository, VersionRangeResult result )
259     {
260         Versioning versioning = null;
261 
262         FileInputStream fis = null;
263         try
264         {
265             if ( metadata != null )
266             {
267 
268                 try ( SyncContext syncContext = syncContextFactory.newInstance( session, true ) )
269                 {
270                     syncContext.acquire( null, Collections.singleton( metadata ) );
271 
272                     if ( metadata.getFile() != null && metadata.getFile().exists() )
273                     {
274                         fis = new FileInputStream( metadata.getFile() );
275                         org.apache.maven.artifact.repository.metadata.Metadata m =
276                             new MetadataXpp3Reader().read( fis, false );
277                         versioning = m.getVersioning();
278                     }
279                 }
280             }
281         }
282         catch ( Exception e )
283         {
284             invalidMetadata( session, trace, metadata, repository, e );
285             result.addException( e );
286         }
287         finally
288         {
289             IOUtil.close( fis );
290         }
291 
292         return ( versioning != null ) ? versioning : new Versioning();
293     }
294 
295     private void invalidMetadata( RepositorySystemSession session, RequestTrace trace, Metadata metadata,
296                                   ArtifactRepository repository, Exception exception )
297     {
298         RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.METADATA_INVALID );
299         event.setTrace( trace );
300         event.setMetadata( metadata );
301         event.setException( exception );
302         event.setRepository( repository );
303 
304         repositoryEventDispatcher.dispatch( event.build() );
305     }
306 
307 }