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