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