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