1 package org.apache.maven.artifact.repository.metadata;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 import java.io.File;
19 import java.io.FileNotFoundException;
20 import java.io.IOException;
21 import java.io.Reader;
22 import java.io.Writer;
23 import java.util.Date;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27
28 import org.apache.maven.artifact.metadata.ArtifactMetadata;
29 import org.apache.maven.artifact.repository.ArtifactRepository;
30 import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
31 import org.apache.maven.artifact.repository.DefaultRepositoryRequest;
32 import org.apache.maven.artifact.repository.RepositoryRequest;
33 import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader;
34 import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Writer;
35 import org.apache.maven.repository.legacy.UpdateCheckManager;
36 import org.apache.maven.repository.legacy.WagonManager;
37 import org.apache.maven.wagon.ResourceDoesNotExistException;
38 import org.apache.maven.wagon.TransferFailedException;
39 import org.codehaus.plexus.component.annotations.Component;
40 import org.codehaus.plexus.component.annotations.Requirement;
41 import org.codehaus.plexus.logging.AbstractLogEnabled;
42 import org.codehaus.plexus.util.IOUtil;
43 import org.codehaus.plexus.util.ReaderFactory;
44 import org.codehaus.plexus.util.WriterFactory;
45 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
46
47
48
49
50 @Component(role=RepositoryMetadataManager.class)
51 public class DefaultRepositoryMetadataManager
52 extends AbstractLogEnabled
53 implements RepositoryMetadataManager
54 {
55 @Requirement
56 private WagonManager wagonManager;
57
58 @Requirement
59 private UpdateCheckManager updateCheckManager;
60
61 public void resolve( RepositoryMetadata metadata, List<ArtifactRepository> remoteRepositories, ArtifactRepository localRepository )
62 throws RepositoryMetadataResolutionException
63 {
64 RepositoryRequest request = new DefaultRepositoryRequest();
65 request.setLocalRepository( localRepository );
66 request.setRemoteRepositories( remoteRepositories );
67 resolve( metadata, request );
68 }
69
70 public void resolve( RepositoryMetadata metadata, RepositoryRequest request )
71 throws RepositoryMetadataResolutionException
72 {
73 ArtifactRepository localRepository = request.getLocalRepository();
74 List<ArtifactRepository> remoteRepositories = request.getRemoteRepositories();
75
76 if ( !request.isOffline() )
77 {
78 Date localCopyLastModified = null;
79 if ( metadata.getBaseVersion() != null )
80 {
81 localCopyLastModified = getLocalCopyLastModified( localRepository, metadata );
82 }
83
84 for ( ArtifactRepository repository : remoteRepositories )
85 {
86 ArtifactRepositoryPolicy policy = metadata.getPolicy( repository );
87
88 File file =
89 new File( localRepository.getBasedir(), localRepository.pathOfLocalRepositoryMetadata( metadata,
90 repository ) );
91 boolean update;
92
93 if ( !policy.isEnabled() )
94 {
95 update = false;
96
97 if ( getLogger().isDebugEnabled() )
98 {
99 getLogger().debug(
100 "Skipping update check for " + metadata.getKey() + " (" + file
101 + ") from disabled repository " + repository.getId() + " ("
102 + repository.getUrl() + ")" );
103 }
104 }
105 else if ( request.isForceUpdate() )
106 {
107 update = true;
108 }
109 else if ( localCopyLastModified != null && !policy.checkOutOfDate( localCopyLastModified ) )
110 {
111 update = false;
112
113 if ( getLogger().isDebugEnabled() )
114 {
115 getLogger().debug(
116 "Skipping update check for " + metadata.getKey() + " (" + file
117 + ") from repository " + repository.getId() + " (" + repository.getUrl()
118 + ") in favor of local copy" );
119 }
120 }
121 else if ( updateCheckManager.isUpdateRequired( metadata, repository, file ) )
122 {
123 update = true;
124 }
125 else
126 {
127 update = false;
128 }
129
130 if ( update )
131 {
132 getLogger().info( metadata.getKey() + ": checking for updates from " + repository.getId() );
133 try
134 {
135 wagonManager.getArtifactMetadata( metadata, repository, file, policy.getChecksumPolicy() );
136 }
137 catch ( ResourceDoesNotExistException e )
138 {
139 getLogger().debug( metadata + " could not be found on repository: " + repository.getId() );
140
141
142 if ( file.exists() )
143 {
144 file.delete();
145 }
146 }
147 catch ( TransferFailedException e )
148 {
149 getLogger().warn( metadata + " could not be retrieved from repository: " + repository.getId()
150 + " due to an error: " + e.getMessage() );
151 getLogger().debug( "Exception", e );
152 }
153 finally
154 {
155 updateCheckManager.touch( metadata, repository, file );
156 }
157 }
158
159
160
161 if ( file.exists() )
162 {
163 file.setLastModified( System.currentTimeMillis() );
164 }
165 }
166 }
167
168 try
169 {
170 mergeMetadata( metadata, remoteRepositories, localRepository );
171 }
172 catch ( RepositoryMetadataStoreException e )
173 {
174 throw new RepositoryMetadataResolutionException( "Unable to store local copy of metadata: " + e.getMessage(), e );
175 }
176 }
177
178 private Date getLocalCopyLastModified( ArtifactRepository localRepository, RepositoryMetadata metadata )
179 {
180 String metadataPath = localRepository.pathOfLocalRepositoryMetadata( metadata, localRepository );
181 File metadataFile = new File( localRepository.getBasedir(), metadataPath );
182 return metadataFile.isFile() ? new Date( metadataFile.lastModified() ) : null;
183 }
184
185 private void mergeMetadata( RepositoryMetadata metadata, List<ArtifactRepository> remoteRepositories, ArtifactRepository localRepository )
186 throws RepositoryMetadataStoreException
187 {
188
189
190
191
192
193 Map<ArtifactRepository, Metadata> previousMetadata = new HashMap<ArtifactRepository, Metadata>();
194 ArtifactRepository selected = null;
195 for ( ArtifactRepository repository : remoteRepositories )
196 {
197 ArtifactRepositoryPolicy policy = metadata.getPolicy( repository );
198
199 if ( policy.isEnabled() && loadMetadata( metadata, repository, localRepository, previousMetadata ) )
200 {
201 metadata.setRepository( repository );
202 selected = repository;
203 }
204 }
205 if ( loadMetadata( metadata, localRepository, localRepository, previousMetadata ) )
206 {
207 metadata.setRepository( null );
208 selected = localRepository;
209 }
210
211 updateSnapshotMetadata( metadata, previousMetadata, selected, localRepository );
212 }
213
214 private void updateSnapshotMetadata( RepositoryMetadata metadata, Map<ArtifactRepository, Metadata> previousMetadata, ArtifactRepository selected, ArtifactRepository localRepository )
215 throws RepositoryMetadataStoreException
216 {
217
218 if ( metadata.isSnapshot() )
219 {
220 Metadata prevMetadata = metadata.getMetadata();
221
222 for ( ArtifactRepository repository : previousMetadata.keySet() )
223 {
224 Metadata m = previousMetadata.get( repository );
225 if ( repository.equals( selected ) )
226 {
227 if ( m.getVersioning() == null )
228 {
229 m.setVersioning( new Versioning() );
230 }
231
232 if ( m.getVersioning().getSnapshot() == null )
233 {
234 m.getVersioning().setSnapshot( new Snapshot() );
235 }
236 }
237 else
238 {
239 if ( ( m.getVersioning() != null ) && ( m.getVersioning().getSnapshot() != null ) && m.getVersioning().getSnapshot().isLocalCopy() )
240 {
241 m.getVersioning().getSnapshot().setLocalCopy( false );
242 metadata.setMetadata( m );
243 metadata.storeInLocalRepository( localRepository, repository );
244 }
245 }
246 }
247
248 metadata.setMetadata( prevMetadata );
249 }
250 }
251
252 private boolean loadMetadata( RepositoryMetadata repoMetadata, ArtifactRepository remoteRepository, ArtifactRepository localRepository, Map<ArtifactRepository, Metadata> previousMetadata )
253 {
254 boolean setRepository = false;
255
256 File metadataFile = new File( localRepository.getBasedir(), localRepository.pathOfLocalRepositoryMetadata( repoMetadata, remoteRepository ) );
257
258 if ( metadataFile.exists() )
259 {
260 Metadata metadata;
261
262 try
263 {
264 metadata = readMetadata( metadataFile );
265 }
266 catch ( RepositoryMetadataReadException e )
267 {
268 if ( getLogger().isDebugEnabled() )
269 {
270 getLogger().warn( e.getMessage(), e );
271 }
272 else
273 {
274 getLogger().warn( e.getMessage() );
275 }
276 return setRepository;
277 }
278
279 if ( repoMetadata.isSnapshot() && ( previousMetadata != null ) )
280 {
281 previousMetadata.put( remoteRepository, metadata );
282 }
283
284 if ( repoMetadata.getMetadata() != null )
285 {
286 setRepository = repoMetadata.getMetadata().merge( metadata );
287 }
288 else
289 {
290 repoMetadata.setMetadata( metadata );
291 setRepository = true;
292 }
293 }
294 return setRepository;
295 }
296
297
298 protected Metadata readMetadata( File mappingFile )
299 throws RepositoryMetadataReadException
300 {
301 Metadata result;
302
303 Reader reader = null;
304 try
305 {
306 reader = ReaderFactory.newXmlReader( mappingFile );
307
308 MetadataXpp3Reader mappingReader = new MetadataXpp3Reader();
309
310 result = mappingReader.read( reader, false );
311 }
312 catch ( FileNotFoundException e )
313 {
314 throw new RepositoryMetadataReadException( "Cannot read metadata from '" + mappingFile + "'", e );
315 }
316 catch ( IOException e )
317 {
318 throw new RepositoryMetadataReadException( "Cannot read metadata from '" + mappingFile + "': " + e.getMessage(), e );
319 }
320 catch ( XmlPullParserException e )
321 {
322 throw new RepositoryMetadataReadException( "Cannot read metadata from '" + mappingFile + "': " + e.getMessage(), e );
323 }
324 finally
325 {
326 IOUtil.close( reader );
327 }
328
329 return result;
330 }
331
332
333
334
335
336 private void fixTimestamp( File metadataFile, Metadata metadata, Metadata reference )
337 {
338 boolean changed = false;
339
340 if ( metadata != null && reference != null )
341 {
342 Versioning versioning = metadata.getVersioning();
343 Versioning versioningRef = reference.getVersioning();
344 if ( versioning != null && versioningRef != null )
345 {
346 String lastUpdated = versioning.getLastUpdated();
347 String now = versioningRef.getLastUpdated();
348 if ( lastUpdated != null && now != null && now.compareTo( lastUpdated ) < 0 )
349 {
350 getLogger().warn(
351 "The last updated timestamp in " + metadataFile + " refers to the future (now = "
352 + now + ", lastUpdated = " + lastUpdated
353 + "). Please verify that the clocks of all"
354 + " deploying machines are reasonably synchronized." );
355 versioning.setLastUpdated( now );
356 changed = true;
357 }
358 }
359 }
360
361 if ( changed )
362 {
363 getLogger().debug( "Repairing metadata in " + metadataFile );
364
365 Writer writer = null;
366 try
367 {
368 writer = WriterFactory.newXmlWriter( metadataFile );
369 new MetadataXpp3Writer().write( writer, metadata );
370 }
371 catch ( IOException e )
372 {
373 String msg = "Could not write fixed metadata to " + metadataFile + ": " + e.getMessage();
374 if ( getLogger().isDebugEnabled() )
375 {
376 getLogger().warn( msg, e );
377 }
378 else
379 {
380 getLogger().warn( msg );
381 }
382 }
383 finally
384 {
385 IOUtil.close( writer );
386 }
387 }
388 }
389
390 public void resolveAlways( RepositoryMetadata metadata, ArtifactRepository localRepository, ArtifactRepository remoteRepository )
391 throws RepositoryMetadataResolutionException
392 {
393 File file;
394 try
395 {
396 file = getArtifactMetadataFromDeploymentRepository( metadata, localRepository, remoteRepository );
397 }
398 catch ( TransferFailedException e )
399 {
400 throw new RepositoryMetadataResolutionException( metadata + " could not be retrieved from repository: " + remoteRepository.getId() + " due to an error: " + e.getMessage(), e );
401 }
402
403 try
404 {
405 if ( file.exists() )
406 {
407 Metadata prevMetadata = readMetadata( file );
408 metadata.setMetadata( prevMetadata );
409 }
410 }
411 catch ( RepositoryMetadataReadException e )
412 {
413 throw new RepositoryMetadataResolutionException( e.getMessage(), e );
414 }
415 }
416
417 private File getArtifactMetadataFromDeploymentRepository( ArtifactMetadata metadata, ArtifactRepository localRepository, ArtifactRepository remoteRepository )
418 throws TransferFailedException
419 {
420 File file = new File( localRepository.getBasedir(), localRepository.pathOfLocalRepositoryMetadata( metadata, remoteRepository ) );
421
422 try
423 {
424 wagonManager.getArtifactMetadataFromDeploymentRepository( metadata, remoteRepository, file, ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN );
425 }
426 catch ( ResourceDoesNotExistException e )
427 {
428 getLogger().info( metadata + " could not be found on repository: " + remoteRepository.getId() + ", so will be created" );
429
430
431 if ( file.exists() )
432 {
433 file.delete();
434 }
435 }
436 finally
437 {
438 if ( metadata instanceof RepositoryMetadata )
439 {
440 updateCheckManager.touch( (RepositoryMetadata) metadata, remoteRepository, file );
441 }
442 }
443 return file;
444 }
445
446 public void deploy( ArtifactMetadata metadata, ArtifactRepository localRepository, ArtifactRepository deploymentRepository )
447 throws RepositoryMetadataDeploymentException
448 {
449 File file;
450 if ( metadata instanceof RepositoryMetadata )
451 {
452 getLogger().info( "Retrieving previous metadata from " + deploymentRepository.getId() );
453 try
454 {
455 file = getArtifactMetadataFromDeploymentRepository( metadata, localRepository, deploymentRepository );
456 }
457 catch ( TransferFailedException e )
458 {
459 throw new RepositoryMetadataDeploymentException( metadata + " could not be retrieved from repository: " + deploymentRepository.getId() + " due to an error: " + e.getMessage(), e );
460 }
461
462 if ( file.isFile() )
463 {
464 try
465 {
466 fixTimestamp( file, readMetadata( file ), ( (RepositoryMetadata) metadata ).getMetadata() );
467 }
468 catch ( RepositoryMetadataReadException e )
469 {
470
471 }
472 }
473 }
474 else
475 {
476
477 file = new File( localRepository.getBasedir(), localRepository.pathOfLocalRepositoryMetadata( metadata, deploymentRepository ) );
478 }
479
480 try
481 {
482 metadata.storeInLocalRepository( localRepository, deploymentRepository );
483 }
484 catch ( RepositoryMetadataStoreException e )
485 {
486 throw new RepositoryMetadataDeploymentException( "Error installing metadata: " + e.getMessage(), e );
487 }
488
489 try
490 {
491 wagonManager.putArtifactMetadata( file, metadata, deploymentRepository );
492 }
493 catch ( TransferFailedException e )
494 {
495 throw new RepositoryMetadataDeploymentException( "Error while deploying metadata: " + e.getMessage(), e );
496 }
497 }
498
499 public void install( ArtifactMetadata metadata, ArtifactRepository localRepository )
500 throws RepositoryMetadataInstallationException
501 {
502 try
503 {
504 metadata.storeInLocalRepository( localRepository, localRepository );
505 }
506 catch ( RepositoryMetadataStoreException e )
507 {
508 throw new RepositoryMetadataInstallationException( "Error installing metadata: " + e.getMessage(), e );
509 }
510 }
511
512 }