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