This project has retired. For details please refer to its
Attic page.
RepositoryModelResolver xref
1 package org.apache.archiva.metadata.repository.storage.maven2;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.archiva.admin.model.beans.ManagedRepository;
23 import org.apache.archiva.admin.model.beans.NetworkProxy;
24 import org.apache.archiva.admin.model.beans.RemoteRepository;
25 import org.apache.archiva.common.utils.VersionUtil;
26 import org.apache.archiva.maven2.metadata.MavenMetadataReader;
27 import org.apache.archiva.metadata.repository.storage.RepositoryPathTranslator;
28 import org.apache.archiva.model.ArchivaRepositoryMetadata;
29 import org.apache.archiva.model.SnapshotVersion;
30 import org.apache.archiva.proxy.common.WagonFactory;
31 import org.apache.archiva.proxy.common.WagonFactoryException;
32 import org.apache.archiva.proxy.common.WagonFactoryRequest;
33 import org.apache.archiva.xml.XMLException;
34 import org.apache.commons.io.FileUtils;
35 import org.apache.commons.lang.StringUtils;
36 import org.apache.maven.model.Repository;
37 import org.apache.maven.model.building.FileModelSource;
38 import org.apache.maven.model.building.ModelSource;
39 import org.apache.maven.model.resolution.InvalidRepositoryException;
40 import org.apache.maven.model.resolution.ModelResolver;
41 import org.apache.maven.model.resolution.UnresolvableModelException;
42 import org.apache.maven.wagon.ConnectionException;
43 import org.apache.maven.wagon.ResourceDoesNotExistException;
44 import org.apache.maven.wagon.TransferFailedException;
45 import org.apache.maven.wagon.Wagon;
46 import org.apache.maven.wagon.authentication.AuthenticationException;
47 import org.apache.maven.wagon.authentication.AuthenticationInfo;
48 import org.apache.maven.wagon.authorization.AuthorizationException;
49 import org.apache.maven.wagon.proxy.ProxyInfo;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52
53 import java.io.File;
54 import java.io.IOException;
55 import java.nio.file.Files;
56 import java.util.List;
57 import java.util.Map;
58
59 public class RepositoryModelResolver
60 implements ModelResolver
61 {
62 private File basedir;
63
64 private RepositoryPathTranslator pathTranslator;
65
66 private WagonFactory wagonFactory;
67
68 private List<RemoteRepository> remoteRepositories;
69
70 private ManagedRepository targetRepository;
71
72 private static final Logger log = LoggerFactory.getLogger( RepositoryModelResolver.class );
73
74 private static final String METADATA_FILENAME = "maven-metadata.xml";
75
76
77 Map<String, NetworkProxy> networkProxyMap;
78
79 private ManagedRepository managedRepository;
80
81 public RepositoryModelResolver( File basedir, RepositoryPathTranslator pathTranslator )
82 {
83 this.basedir = basedir;
84
85 this.pathTranslator = pathTranslator;
86 }
87
88 public RepositoryModelResolver( ManagedRepository managedRepository, RepositoryPathTranslator pathTranslator,
89 WagonFactory wagonFactory, List<RemoteRepository> remoteRepositories,
90 Map<String, NetworkProxy> networkProxiesMap, ManagedRepository targetRepository )
91 {
92 this( new File( managedRepository.getLocation() ), pathTranslator );
93
94 this.managedRepository = managedRepository;
95
96 this.wagonFactory = wagonFactory;
97
98 this.remoteRepositories = remoteRepositories;
99
100 this.networkProxyMap = networkProxiesMap;
101
102 this.targetRepository = targetRepository;
103 }
104
105 @Override
106 public ModelSource resolveModel( String groupId, String artifactId, String version )
107 throws UnresolvableModelException
108 {
109 String filename = artifactId + "-" + version + ".pom";
110
111
112 File model = pathTranslator.toFile( basedir, groupId, artifactId, version, filename );
113
114 if ( !model.exists() )
115 {
116
117
118
119
120 if ( StringUtils.contains( version, VersionUtil.SNAPSHOT ) )
121 {
122 File localSnapshotModel = findTimeStampedSnapshotPom( groupId, artifactId, version, model.getParent() );
123 if ( localSnapshotModel != null )
124 {
125 return new FileModelSource( localSnapshotModel );
126 }
127
128 }
129
130 for ( RemoteRepository remoteRepository : remoteRepositories )
131 {
132 try
133 {
134 boolean success = getModelFromProxy( remoteRepository, groupId, artifactId, version, filename );
135 if ( success && model.exists() )
136 {
137 log.info( "Model '{}' successfully retrieved from remote repository '{}'",
138 model.getAbsolutePath(), remoteRepository.getId() );
139 break;
140 }
141 }
142 catch ( ResourceDoesNotExistException e )
143 {
144 log.info(
145 "An exception was caught while attempting to retrieve model '{}' from remote repository '{}'.Reason:{}",
146 model.getAbsolutePath(), remoteRepository.getId(), e.getMessage() );
147 }
148 catch ( Exception e )
149 {
150 log.warn(
151 "An exception was caught while attempting to retrieve model '{}' from remote repository '{}'.Reason:{}",
152 model.getAbsolutePath(), remoteRepository.getId(), e.getMessage() );
153
154 continue;
155 }
156 }
157 }
158
159 return new FileModelSource( model );
160 }
161
162 protected File findTimeStampedSnapshotPom( String groupId, String artifactId, String version,
163 String parentDirectory )
164 {
165
166
167 File mavenMetadata = new File( parentDirectory, METADATA_FILENAME );
168 if ( mavenMetadata.exists() )
169 {
170 try
171 {
172 ArchivaRepositoryMetadata archivaRepositoryMetadata = MavenMetadataReader.read( mavenMetadata );
173 SnapshotVersion snapshotVersion = archivaRepositoryMetadata.getSnapshotVersion();
174 if ( snapshotVersion != null )
175 {
176 String lastVersion = snapshotVersion.getTimestamp();
177 int buildNumber = snapshotVersion.getBuildNumber();
178 String snapshotPath =
179 StringUtils.replaceChars( groupId, '.', '/' ) + '/' + artifactId + '/' + version + '/'
180 + artifactId + '-' + StringUtils.remove( version, "-" + VersionUtil.SNAPSHOT ) + '-'
181 + lastVersion + '-' + buildNumber + ".pom";
182
183 log.debug( "use snapshot path {} for maven coordinate {}:{}:{}", snapshotPath, groupId, artifactId,
184 version );
185
186 File model = new File( basedir, snapshotPath );
187
188 if ( model.exists() )
189 {
190 return model;
191 }
192 }
193 }
194 catch ( XMLException e )
195 {
196 log.warn( "fail to read {}, {}", mavenMetadata.getAbsolutePath(), e.getCause() );
197 }
198 }
199
200 return null;
201 }
202
203 @Override
204 public void addRepository( Repository repository )
205 throws InvalidRepositoryException
206 {
207
208
209
210 }
211
212 @Override
213 public ModelResolver newCopy()
214 {
215 return new RepositoryModelResolver( managedRepository, pathTranslator, wagonFactory, remoteRepositories,
216 networkProxyMap, targetRepository );
217 }
218
219
220
221 private boolean getModelFromProxy( RemoteRepository remoteRepository, String groupId, String artifactId,
222 String version, String filename )
223 throws AuthorizationException, TransferFailedException, ResourceDoesNotExistException, WagonFactoryException,
224 XMLException, IOException
225 {
226 boolean success = false;
227 File tmpMd5 = null;
228 File tmpSha1 = null;
229 File tmpResource = null;
230 String artifactPath = pathTranslator.toPath( groupId, artifactId, version, filename );
231 File resource = new File( targetRepository.getLocation(), artifactPath );
232
233 File workingDirectory = createWorkingDirectory( targetRepository.getLocation() );
234 try
235 {
236 Wagon wagon = null;
237 try
238 {
239 String protocol = getProtocol( remoteRepository.getUrl() );
240 final NetworkProxy networkProxy = this.networkProxyMap.get( remoteRepository.getId() );
241
242 wagon = wagonFactory.getWagon(
243 new WagonFactoryRequest( "wagon#" + protocol, remoteRepository.getExtraHeaders() ).networkProxy(
244 networkProxy )
245 );
246
247 if ( wagon == null )
248 {
249 throw new RuntimeException( "Unsupported remote repository protocol: " + protocol );
250 }
251
252 boolean connected = connectToRepository( wagon, remoteRepository );
253 if ( connected )
254 {
255 tmpResource = new File( workingDirectory, filename );
256
257 if ( VersionUtil.isSnapshot( version ) )
258 {
259
260 File tmpMetadataResource = new File( workingDirectory, METADATA_FILENAME );
261
262 String metadataPath =
263 StringUtils.substringBeforeLast( artifactPath, "/" ) + "/" + METADATA_FILENAME;
264
265 wagon.get( addParameters( metadataPath, remoteRepository ), tmpMetadataResource );
266
267 log.debug( "Successfully downloaded metadata." );
268
269 ArchivaRepositoryMetadata metadata = MavenMetadataReader.read( tmpMetadataResource );
270
271
272 SnapshotVersion snapshotVersion = metadata.getSnapshotVersion();
273 String timestampVersion = version;
274 if ( snapshotVersion != null )
275 {
276 timestampVersion = timestampVersion.substring( 0, timestampVersion.length()
277 - 8 );
278 timestampVersion = timestampVersion + snapshotVersion.getTimestamp() + "-"
279 + snapshotVersion.getBuildNumber();
280
281 filename = artifactId + "-" + timestampVersion + ".pom";
282
283 artifactPath = pathTranslator.toPath( groupId, artifactId, version, filename );
284
285 log.debug( "New artifactPath :{}", artifactPath );
286 }
287 }
288
289 log.info( "Retrieving {} from {}", artifactPath, remoteRepository.getName() );
290
291 wagon.get( addParameters( artifactPath, remoteRepository ), tmpResource );
292
293 log.debug( "Downloaded successfully." );
294
295 tmpSha1 = transferChecksum( wagon, remoteRepository, artifactPath, tmpResource, workingDirectory,
296 ".sha1" );
297 tmpMd5 = transferChecksum( wagon, remoteRepository, artifactPath, tmpResource, workingDirectory,
298 ".md5" );
299 }
300 }
301 finally
302 {
303 if ( wagon != null )
304 {
305 try
306 {
307 wagon.disconnect();
308 }
309 catch ( ConnectionException e )
310 {
311 log.warn( "Unable to disconnect wagon.", e );
312 }
313 }
314 }
315
316 if ( resource != null )
317 {
318 synchronized ( resource.getAbsolutePath().intern() )
319 {
320 File directory = resource.getParentFile();
321 moveFileIfExists( tmpMd5, directory );
322 moveFileIfExists( tmpSha1, directory );
323 moveFileIfExists( tmpResource, directory );
324 success = true;
325 }
326 }
327 }
328 finally
329 {
330 FileUtils.deleteQuietly( workingDirectory );
331 }
332
333
334
335 return success;
336 }
337
338
339
340
341
342
343
344 private boolean connectToRepository( Wagon wagon, RemoteRepository remoteRepository )
345 {
346 boolean connected;
347
348 final NetworkProxy proxyConnector = this.networkProxyMap.get( remoteRepository.getId() );
349 ProxyInfo networkProxy = null;
350 if ( proxyConnector != null )
351 {
352 networkProxy = new ProxyInfo();
353 networkProxy.setType( proxyConnector.getProtocol() );
354 networkProxy.setHost( proxyConnector.getHost() );
355 networkProxy.setPort( proxyConnector.getPort() );
356 networkProxy.setUserName( proxyConnector.getUsername() );
357 networkProxy.setPassword( proxyConnector.getPassword() );
358
359 String msg = "Using network proxy " + networkProxy.getHost() + ":" + networkProxy.getPort()
360 + " to connect to remote repository " + remoteRepository.getUrl();
361 if ( networkProxy.getNonProxyHosts() != null )
362 {
363 msg += "; excluding hosts: " + networkProxy.getNonProxyHosts();
364 }
365
366 if ( StringUtils.isNotBlank( networkProxy.getUserName() ) )
367 {
368 msg += "; as user: " + networkProxy.getUserName();
369 }
370
371 log.debug( msg );
372 }
373
374 AuthenticationInfo authInfo = null;
375 String username = remoteRepository.getUserName();
376 String password = remoteRepository.getPassword();
377
378 if ( StringUtils.isNotBlank( username ) && StringUtils.isNotBlank( password ) )
379 {
380 log.debug( "Using username {} to connect to remote repository {}", username, remoteRepository.getUrl() );
381 authInfo = new AuthenticationInfo();
382 authInfo.setUserName( username );
383 authInfo.setPassword( password );
384 }
385
386
387 int timeoutInMilliseconds = remoteRepository.getTimeout() * 1000;
388
389
390 wagon.setReadTimeout( timeoutInMilliseconds );
391 wagon.setTimeout( timeoutInMilliseconds );
392
393 try
394 {
395 org.apache.maven.wagon.repository.Repository wagonRepository =
396 new org.apache.maven.wagon.repository.Repository( remoteRepository.getId(), remoteRepository.getUrl() );
397 if ( networkProxy != null )
398 {
399 wagon.connect( wagonRepository, authInfo, networkProxy );
400 }
401 else
402 {
403 wagon.connect( wagonRepository, authInfo );
404 }
405 connected = true;
406 }
407 catch ( ConnectionException | AuthenticationException e )
408 {
409 log.error( "Could not connect to {}:{} ", remoteRepository.getName(), e.getMessage() );
410 connected = false;
411 }
412
413 return connected;
414 }
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429 private File transferChecksum( final Wagon wagon, final RemoteRepository remoteRepository,
430 final String remotePath, final File resource,
431 final File workingDir, final String ext )
432 throws AuthorizationException, TransferFailedException, ResourceDoesNotExistException
433 {
434 File destFile = new File( workingDir, resource.getName() + ext );
435 String remoteChecksumPath = remotePath + ext;
436
437 log.info( "Retrieving {} from {}", remoteChecksumPath, remoteRepository.getName() );
438
439 wagon.get( addParameters( remoteChecksumPath, remoteRepository ), destFile );
440
441 log.debug( "Downloaded successfully." );
442
443 return destFile;
444 }
445
446 private String getProtocol( String url )
447 {
448 String protocol = StringUtils.substringBefore( url, ":" );
449
450 return protocol;
451 }
452
453 private File createWorkingDirectory( String targetRepository )
454 throws IOException
455 {
456 return Files.createTempDirectory( "temp" ).toFile();
457 }
458
459 private void moveFileIfExists( File fileToMove, File directory )
460 {
461 if ( fileToMove != null && fileToMove.exists() )
462 {
463 File newLocation = new File( directory, fileToMove.getName() );
464 if ( newLocation.exists() && !newLocation.delete() )
465 {
466 throw new RuntimeException(
467 "Unable to overwrite existing target file: " + newLocation.getAbsolutePath() );
468 }
469
470 newLocation.getParentFile().mkdirs();
471 if ( !fileToMove.renameTo( newLocation ) )
472 {
473 log.warn( "Unable to rename tmp file to its final name... resorting to copy command." );
474
475 try
476 {
477 FileUtils.copyFile( fileToMove, newLocation );
478 }
479 catch ( IOException e )
480 {
481 if ( newLocation.exists() )
482 {
483 log.error( "Tried to copy file {} to {} but file with this name already exists.",
484 fileToMove.getName(), newLocation.getAbsolutePath() );
485 }
486 else
487 {
488 throw new RuntimeException(
489 "Cannot copy tmp file " + fileToMove.getAbsolutePath() + " to its final location", e );
490 }
491 }
492 finally
493 {
494 FileUtils.deleteQuietly( fileToMove );
495 }
496 }
497 }
498 }
499
500 protected String addParameters( String path, RemoteRepository remoteRepository )
501 {
502 if ( remoteRepository.getExtraParameters().isEmpty() )
503 {
504 return path;
505 }
506
507 boolean question = false;
508
509 StringBuilder res = new StringBuilder( path == null ? "" : path );
510
511 for ( Map.Entry<String, String> entry : remoteRepository.getExtraParameters().entrySet() )
512 {
513 if ( !question )
514 {
515 res.append( '?' ).append( entry.getKey() ).append( '=' ).append( entry.getValue() );
516 }
517 }
518
519 return res.toString();
520 }
521 }