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