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