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