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