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