]> source.dussan.org Git - archiva.git/blob
72df50cf59d5295170fd6248135f8f57777b972c
[archiva.git] /
1 package org.apache.archiva.web.api;
2 /*
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  */
20
21 import org.apache.archiva.admin.model.RepositoryAdminException;
22 import org.apache.archiva.admin.model.admin.ArchivaAdministration;
23 import org.apache.archiva.checksum.ChecksumAlgorithm;
24 import org.apache.archiva.checksum.ChecksumUtil;
25 import org.apache.archiva.checksum.ChecksummedFile;
26 import org.apache.archiva.common.utils.VersionComparator;
27 import org.apache.archiva.common.utils.VersionUtil;
28 import org.apache.archiva.components.taskqueue.TaskQueueException;
29 import org.apache.archiva.configuration.ArchivaConfiguration;
30 import org.apache.archiva.metadata.model.facets.AuditEvent;
31 import org.apache.archiva.model.ArchivaRepositoryMetadata;
32 import org.apache.archiva.model.SnapshotVersion;
33 import org.apache.archiva.repository.ReleaseScheme;
34 import org.apache.archiva.repository.Repository;
35 import org.apache.archiva.repository.RepositoryException;
36 import org.apache.archiva.repository.RepositoryRegistry;
37 import org.apache.archiva.repository.RepositoryType;
38 import org.apache.archiva.repository.content.ItemSelector;
39 import org.apache.archiva.repository.content.base.ArchivaItemSelector;
40 import org.apache.archiva.repository.metadata.MetadataReader;
41 import org.apache.archiva.repository.metadata.RepositoryMetadataException;
42 import org.apache.archiva.repository.metadata.base.MetadataTools;
43 import org.apache.archiva.repository.metadata.base.RepositoryMetadataWriter;
44 import org.apache.archiva.repository.storage.StorageAsset;
45 import org.apache.archiva.rest.api.services.ArchivaRestServiceException;
46 import org.apache.archiva.rest.services.AbstractRestService;
47 import org.apache.archiva.scheduler.ArchivaTaskScheduler;
48 import org.apache.archiva.scheduler.repository.model.RepositoryTask;
49 import org.apache.archiva.web.model.FileMetadata;
50 import org.apache.commons.io.FilenameUtils;
51 import org.apache.commons.io.IOUtils;
52 import org.apache.commons.lang3.BooleanUtils;
53 import org.apache.commons.lang3.StringUtils;
54 import org.apache.commons.lang3.SystemUtils;
55 import org.apache.cxf.jaxrs.ext.multipart.Attachment;
56 import org.apache.cxf.jaxrs.ext.multipart.MultipartBody;
57 import org.apache.maven.model.Model;
58 import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
61 import org.springframework.stereotype.Service;
62
63 import javax.annotation.PostConstruct;
64 import javax.inject.Inject;
65 import javax.inject.Named;
66 import javax.servlet.http.HttpServletRequest;
67 import javax.servlet.http.HttpSession;
68 import javax.ws.rs.core.Context;
69 import javax.ws.rs.core.Response;
70 import java.io.FileOutputStream;
71 import java.io.IOException;
72 import java.io.OutputStreamWriter;
73 import java.io.Writer;
74 import java.net.URLDecoder;
75 import java.nio.file.FileSystems;
76 import java.nio.file.Files;
77 import java.nio.file.Path;
78 import java.nio.file.Paths;
79 import java.text.DateFormat;
80 import java.text.SimpleDateFormat;
81 import java.util.ArrayList;
82 import java.util.Calendar;
83 import java.util.Collections;
84 import java.util.Date;
85 import java.util.Iterator;
86 import java.util.List;
87 import java.util.TimeZone;
88 import java.util.concurrent.CopyOnWriteArrayList;
89
90 /**
91  *
92  * Service for uploading files to the repository.
93  *
94  * @author Olivier Lamy
95  * @author Martin Stockhammer
96  */
97 @Service("fileUploadService#rest")
98 public class DefaultFileUploadService
99         extends AbstractRestService
100         implements FileUploadService {
101     private Logger log = LoggerFactory.getLogger(getClass());
102
103     @Context
104     private HttpServletRequest httpServletRequest;
105
106     @Inject
107     private ArchivaAdministration archivaAdministration;
108
109     @Inject
110     ArchivaConfiguration configuration;
111
112     private List<ChecksumAlgorithm> algorithms;
113
114     private final String FS = FileSystems.getDefault().getSeparator();
115
116     @Inject
117     @Named(value = "archivaTaskScheduler#repository")
118     private ArchivaTaskScheduler<RepositoryTask> scheduler;
119
120     @Inject
121     private RepositoryRegistry repositoryRegistry;
122
123     private String getStringValue(MultipartBody multipartBody, String attachmentId)
124             throws IOException {
125         Attachment attachment = multipartBody.getAttachment(attachmentId);
126         return attachment == null ? "" :
127                 StringUtils.trim(URLDecoder.decode(IOUtils.toString(attachment.getDataHandler().getInputStream(), "UTF-8"), "UTF-8"));
128     }
129
130     @PostConstruct
131     private void initialize() {
132         algorithms = ChecksumUtil.getAlgorithms(configuration.getConfiguration().getArchivaRuntimeConfiguration().getChecksumTypes());
133     }
134
135     @Override
136     public FileMetadata post(MultipartBody multipartBody)
137             throws ArchivaRestServiceException {
138
139         try {
140
141             String classifier = getStringValue(multipartBody, "classifier");
142             String packaging = getStringValue(multipartBody, "packaging");
143
144             checkParamChars("classifier", classifier);
145             checkParamChars("packaging", packaging);
146
147             // skygo: http header form pomFile was once sending 1 for true and void for false
148             // leading to permanent false value for pomFile if using toBoolean(); use , "1", ""
149
150             boolean pomFile = false;
151             try {
152                 pomFile = BooleanUtils.toBoolean(getStringValue(multipartBody, "pomFile"));
153             } catch (IllegalArgumentException ex) {
154                 ArchivaRestServiceException e = new ArchivaRestServiceException("Bad value for boolean pomFile field.", null);
155                 e.setHttpErrorCode(422);
156                 e.setFieldName("pomFile");
157                 e.setErrorKey("fileupload.malformed.pomFile");
158                 throw e;
159             }
160
161             Attachment file = multipartBody.getAttachment("files[]");
162
163             //Content-Disposition: form-data; name="files[]"; filename="org.apache.karaf.features.command-2.2.2.jar"
164             String fileName = file.getContentDisposition().getParameter("filename");
165             Path fileNamePath = Paths.get(fileName);
166             if (!fileName.equals(fileNamePath.getFileName().toString())) {
167                 ArchivaRestServiceException e = new ArchivaRestServiceException("Bad filename in upload content: " + fileName + " - File traversal chars (..|/) are not allowed"
168                         , null);
169                 e.setHttpErrorCode(422);
170                 e.setErrorKey("fileupload.malformed.filename");
171                 throw e;
172             }
173
174             Path tmpFile = Files.createTempFile("upload-artifact", ".tmp");
175             tmpFile.toFile().deleteOnExit();
176             IOUtils.copy(file.getDataHandler().getInputStream(), new FileOutputStream(tmpFile.toFile()));
177             FileMetadata fileMetadata = new FileMetadata(fileName, Files.size(tmpFile), "theurl");
178             fileMetadata.setServerFileName(tmpFile.toString());
179             fileMetadata.setClassifier(classifier);
180             fileMetadata.setDeleteUrl(tmpFile.getFileName().toString());
181             fileMetadata.setPomFile(pomFile);
182             fileMetadata.setPackaging(packaging);
183
184             log.info("uploading file: {}", fileMetadata);
185
186             List<FileMetadata> fileMetadatas = getSessionFilesList();
187
188             fileMetadatas.add(fileMetadata);
189
190             return fileMetadata;
191         } catch (IOException e) {
192             throw new ArchivaRestServiceException(e.getMessage(),
193                     Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e);
194         }
195
196     }
197
198     /**
199      * @return The file list from the session.
200      */
201     @SuppressWarnings("unchecked")
202     protected List<FileMetadata> getSessionFilesList() {
203         final HttpSession session = httpServletRequest.getSession();
204         List<FileMetadata> fileMetadata = (List<FileMetadata>) session.getAttribute(FILES_SESSION_KEY);
205         // Double check with synchronization, we assume, that httpServletRequest is
206         // fully initialized (no volatile)
207         if (fileMetadata == null) {
208             synchronized (session) {
209                 fileMetadata = (List<FileMetadata>) session.getAttribute(FILES_SESSION_KEY);
210                 if (fileMetadata == null) {
211                     fileMetadata = new CopyOnWriteArrayList<>();
212                     session.setAttribute(FILES_SESSION_KEY, fileMetadata);
213                 }
214             }
215         }
216         return fileMetadata;
217     }
218
219     @Override
220     public Boolean deleteFile(String fileName)
221             throws ArchivaRestServiceException {
222         log.debug("Deleting file {}", fileName);
223         // we make sure, that there are no other path components in the filename:
224         String checkedFileName = Paths.get(fileName).getFileName().toString();
225         Path file = SystemUtils.getJavaIoTmpDir().toPath().resolve(checkedFileName);
226         log.debug("delete file:{},exists:{}", file, Files.exists(file));
227         boolean removed = getSessionFileMetadatas().remove(new FileMetadata(fileName));
228         // try with full name as ui only know the file name
229         if (!removed) {
230             removed = getSessionFileMetadatas().remove(new FileMetadata(file.toString()));
231         }
232         if (removed) {
233             try {
234                 Files.deleteIfExists(file);
235                 return Boolean.TRUE;
236             } catch (IOException e) {
237                 log.error("Could not delete file {}: {}", file, e.getMessage(), e);
238             }
239         }
240         return Boolean.FALSE;
241     }
242
243     @Override
244     public Boolean clearUploadedFiles()
245             throws ArchivaRestServiceException {
246         List<FileMetadata> fileMetadatas = new ArrayList<>(getSessionFileMetadatas());
247         for (FileMetadata fileMetadata : fileMetadatas) {
248             deleteFile(Paths.get(fileMetadata.getServerFileName()).toString());
249         }
250         getSessionFileMetadatas().clear();
251         return Boolean.TRUE;
252     }
253
254     @Override
255     public List<FileMetadata> getSessionFileMetadatas()
256             throws ArchivaRestServiceException {
257         return getSessionFilesList();
258     }
259
260
261     private boolean hasValidChars(String checkString) {
262         if (checkString.contains(FS)) {
263             return false;
264         }
265         if (checkString.contains("../")) {
266             return false;
267         }
268         if (checkString.contains("/..")) {
269             return false;
270         }
271         return true;
272     }
273
274     private void checkParamChars(String param, String value) throws ArchivaRestServiceException {
275         if (!hasValidChars(value)) {
276             ArchivaRestServiceException e = new ArchivaRestServiceException("Bad characters in " + param, null);
277             e.setHttpErrorCode(422);
278             e.setErrorKey("fileupload.malformed.param");
279             e.setFieldName(param);
280             throw e;
281         }
282     }
283
284     @Override
285     public Boolean save(String repositoryId, String groupId, String artifactId, String version, String packaging,
286                         boolean generatePom)
287             throws ArchivaRestServiceException {
288         repositoryId = StringUtils.trim(repositoryId);
289         groupId = StringUtils.trim(groupId);
290         artifactId = StringUtils.trim(artifactId);
291         version = StringUtils.trim(version);
292         packaging = StringUtils.trim(packaging);
293
294         checkParamChars("repositoryId", repositoryId);
295         checkParamChars("groupId", groupId);
296         checkParamChars("artifactId", artifactId);
297         checkParamChars("version", version);
298         checkParamChars("packaging", packaging);
299
300
301         List<FileMetadata> fileMetadatas = getSessionFilesList();
302         if (fileMetadatas == null || fileMetadatas.isEmpty()) {
303             return Boolean.FALSE;
304         }
305
306         org.apache.archiva.repository.ManagedRepository repository = repositoryRegistry.getManagedRepository(repositoryId);
307         if (repository == null) {
308             // TODO i18n ?
309             throw new ArchivaRestServiceException("Cannot find managed repository with id " + repositoryId,
310                     Response.Status.BAD_REQUEST.getStatusCode(), null);
311         }
312
313         if (VersionUtil.isSnapshot(version) && !repository.getActiveReleaseSchemes().contains( ReleaseScheme.SNAPSHOT )) {
314             // TODO i18n ?
315             throw new ArchivaRestServiceException(
316                     "Managed repository with id " + repositoryId + " do not accept snapshots",
317                     Response.Status.BAD_REQUEST.getStatusCode(), null);
318         }
319
320         // get from the session file with groupId/artifactId
321
322         Iterator<FileMetadata> iterator = fileMetadatas.stream( )
323             .filter( fileMetadata -> fileMetadata != null && !fileMetadata.isPomFile( ) )
324             .iterator( );
325         boolean pomGenerated = false;
326         while (iterator.hasNext()) {
327             FileMetadata fileMetadata = iterator.next();
328             log.debug("fileToAdd: {}", fileMetadata);
329             saveFile(repositoryId, fileMetadata, generatePom && !pomGenerated, groupId, artifactId, version,
330                     packaging);
331             pomGenerated = true;
332             deleteFile(fileMetadata.getServerFileName());
333         }
334
335         iterator = fileMetadatas.stream( ).filter( fileMetadata -> fileMetadata != null && fileMetadata.isPomFile( ) )
336             .iterator( );
337         while (iterator.hasNext()) {
338             FileMetadata fileMetadata = iterator.next();
339             log.debug("fileToAdd: {}", fileMetadata);
340             savePomFile(repositoryId, fileMetadata, groupId, artifactId, version, packaging);
341             deleteFile(fileMetadata.getServerFileName());
342         }
343
344         return Boolean.TRUE;
345     }
346
347     protected void savePomFile(String repositoryId, FileMetadata fileMetadata, String groupId, String artifactId,
348                                String version, String packaging)
349             throws ArchivaRestServiceException {
350
351         log.debug("Saving POM");
352         try {
353             boolean fixChecksums =
354                     !(archivaAdministration.getKnownContentConsumers().contains("create-missing-checksums"));
355
356             org.apache.archiva.repository.ManagedRepository repository = repositoryRegistry.getManagedRepository(repositoryId);
357             ItemSelector selector = ArchivaItemSelector.builder( )
358                 .withNamespace( groupId )
359                 .withProjectId( artifactId )
360                 .withArtifactId( artifactId )
361                 .withArtifactVersion( version )
362                 .withExtension( packaging ).build();
363
364             StorageAsset pomPath = repository.getContent( ).getItem( selector ).getAsset();
365             StorageAsset targetPath = pomPath.getParent();
366
367             String pomFilename = pomPath.getName();
368             if (StringUtils.isNotEmpty(fileMetadata.getClassifier())) {
369                 pomFilename = StringUtils.remove(pomFilename, "-" + fileMetadata.getClassifier());
370             }
371             pomFilename = FilenameUtils.removeExtension(pomFilename) + ".pom";
372
373             copyFile(Paths.get(fileMetadata.getServerFileName()), targetPath, pomFilename, fixChecksums);
374             triggerAuditEvent(repository.getId(), targetPath.resolve(pomFilename).toString(), AuditEvent.UPLOAD_FILE);
375             queueRepositoryTask(repository.getId(), targetPath.resolve(pomFilename));
376             log.debug("Finished Saving POM");
377         } catch (IOException ie) {
378             log.error("IOException for POM {}", ie.getMessage());
379             throw new ArchivaRestServiceException("Error encountered while uploading pom file: " + ie.getMessage(),
380                     Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), ie);
381         }
382         catch (RepositoryAdminException e) {
383             log.error("RepositoryAdminException for POM {}", e.getMessage());
384             throw new ArchivaRestServiceException("RepositoryAdmin exception: " + e.getMessage(),
385                     Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e);
386         }
387     }
388
389     protected void saveFile(String repositoryId, FileMetadata fileMetadata, boolean generatePom, String groupId,
390                             String artifactId, String version, String packaging)
391             throws ArchivaRestServiceException {
392         log.debug("Saving file");
393         try {
394
395             org.apache.archiva.repository.ManagedRepository repository = repositoryRegistry.getManagedRepository(repositoryId);
396
397             log.debug( "Finding artifact path for {}, {}, {}, {}", groupId, artifactId, version, packaging );
398             ItemSelector selector = ArchivaItemSelector.builder( )
399                 .withNamespace( groupId )
400                 .withProjectId( artifactId )
401                 .withArtifactId( artifactId )
402                 .withArtifactVersion( version )
403                 .withExtension( packaging ).build();
404
405             StorageAsset artifactPath = repository.getContent( ).getItem( selector ).getAsset();
406             StorageAsset targetPath = artifactPath.getParent();
407
408             log.debug("artifactPath: {} found targetPath: {}", artifactPath, targetPath);
409
410             Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
411             int newBuildNumber = -1;
412             String timestamp = null;
413
414             StorageAsset versionMetadataFile = targetPath.resolve(MetadataTools.MAVEN_METADATA);
415             ArchivaRepositoryMetadata versionMetadata = getMetadata(versionMetadataFile);
416
417             if (VersionUtil.isSnapshot(version)) {
418                 TimeZone timezone = TimeZone.getTimeZone("UTC");
419                 DateFormat fmt = new SimpleDateFormat("yyyyMMdd.HHmmss");
420                 fmt.setTimeZone(timezone);
421                 timestamp = fmt.format(lastUpdatedTimestamp);
422                 if (versionMetadata.getSnapshotVersion() != null) {
423                     newBuildNumber = versionMetadata.getSnapshotVersion().getBuildNumber() + 1;
424                 } else {
425                     newBuildNumber = 1;
426                 }
427             }
428
429             if (!targetPath.exists()) {
430                 targetPath.create();
431             }
432
433             String filename = artifactPath.getName().toString();
434             if (VersionUtil.isSnapshot(version)) {
435                 filename = filename.replaceAll(VersionUtil.SNAPSHOT, timestamp + "-" + newBuildNumber);
436             }
437
438             // We always fix checksums for newly uploaded files, even if the content consumer is active.
439             boolean fixChecksums = true;
440             // !(archivaAdministration.getKnownContentConsumers().contains("create-missing-checksums"));
441
442             try {
443                 StorageAsset targetFile = targetPath.resolve(filename);
444                 if (targetFile.exists() && !VersionUtil.isSnapshot(version) && repository.blocksRedeployments()) {
445                     throw new ArchivaRestServiceException(
446                             "Overwriting released artifacts in repository '" + repository.getId() + "' is not allowed.",
447                             Response.Status.BAD_REQUEST.getStatusCode(), null);
448                 } else {
449                     copyFile(Paths.get(fileMetadata.getServerFileName()), targetPath, filename, fixChecksums);
450                     triggerAuditEvent(repository.getId(), artifactPath.toString(), AuditEvent.UPLOAD_FILE);
451                     queueRepositoryTask(repository.getId(), targetFile);
452                 }
453             } catch (IOException ie) {
454                 log.error("IOException copying file: {}", ie.getMessage(), ie);
455                 throw new ArchivaRestServiceException(
456                         "Overwriting released artifacts in repository '" + repository.getId() + "' is not allowed.",
457                         Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), ie);
458             }
459
460             if (generatePom) {
461                 String pomFilename = filename;
462                 if (StringUtils.isNotEmpty(fileMetadata.getClassifier())) {
463                     pomFilename = StringUtils.remove(pomFilename, "-" + fileMetadata.getClassifier());
464                 }
465                 pomFilename = FilenameUtils.removeExtension(pomFilename) + ".pom";
466
467                 try {
468                     StorageAsset generatedPomFile =
469                             createPom(targetPath, pomFilename, fileMetadata, groupId, artifactId, version, packaging);
470                     triggerAuditEvent(repository.getId(), targetPath.resolve(pomFilename).toString(), AuditEvent.UPLOAD_FILE);
471                     if (fixChecksums) {
472                         fixChecksums(generatedPomFile);
473                     }
474                     queueRepositoryTask(repository.getId(), generatedPomFile);
475                 } catch (IOException ie) {
476                     throw new ArchivaRestServiceException(
477                             "Error encountered while writing pom file: " + ie.getMessage(),
478                             Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), ie);
479                 }
480             }
481
482             // explicitly update only if metadata-updater consumer is not enabled!
483             if (!archivaAdministration.getKnownContentConsumers().contains("metadata-updater")) {
484                 updateProjectMetadata(targetPath, lastUpdatedTimestamp, timestamp, newBuildNumber,
485                         fixChecksums, fileMetadata, groupId, artifactId, version, packaging);
486
487                 if (VersionUtil.isSnapshot(version)) {
488                     updateVersionMetadata(versionMetadata, versionMetadataFile, lastUpdatedTimestamp, timestamp,
489                             newBuildNumber, fixChecksums, fileMetadata, groupId, artifactId, version,
490                             packaging);
491                 }
492             }
493         }
494         catch (RepositoryException rep) {
495             log.error("RepositoryException during save {}", rep.getMessage());
496             throw new ArchivaRestServiceException("Repository exception: " + rep.getMessage(),
497                     Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), rep);
498         } catch (RepositoryAdminException e) {
499             log.error("RepositoryAdminException during save {}", e.getMessage());
500             throw new ArchivaRestServiceException("RepositoryAdmin exception: " + e.getMessage(),
501                     Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e);
502         } catch (IOException e) {
503             log.error("IOException during save {}", e.getMessage());
504             throw new ArchivaRestServiceException("Repository exception " + e.getMessage(),
505                     Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e);
506         }
507     }
508
509     private ArchivaRepositoryMetadata getMetadata(StorageAsset metadataFile)
510             throws RepositoryMetadataException {
511         ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
512         if (metadataFile.exists()) {
513             Repository repo = repositoryRegistry.getRepositoryOfAsset( metadataFile );
514             RepositoryType type = repo == null ? RepositoryType.MAVEN : repo.getType( );
515             MetadataReader metadataReader = repositoryRegistry.getMetadataReader( type );
516             metadata = metadataReader.read(metadataFile);
517         }
518         return metadata;
519     }
520
521     private StorageAsset createPom(StorageAsset targetPath, String filename, FileMetadata fileMetadata, String groupId,
522                            String artifactId, String version, String packaging)
523             throws IOException {
524         Model projectModel = new Model();
525         projectModel.setModelVersion("4.0.0");
526         projectModel.setGroupId(groupId);
527         projectModel.setArtifactId(artifactId);
528         projectModel.setVersion(version);
529         projectModel.setPackaging(packaging);
530
531         StorageAsset pomFile = targetPath.resolve(filename);
532         MavenXpp3Writer writer = new MavenXpp3Writer();
533
534         try (Writer w = new OutputStreamWriter(pomFile.getWriteStream(true))) {
535             writer.write(w, projectModel);
536         }
537
538         return pomFile;
539     }
540
541     private void fixChecksums(StorageAsset file) {
542         ChecksummedFile checksum = new ChecksummedFile(file.getFilePath());
543         checksum.fixChecksums(algorithms);
544     }
545
546     private void queueRepositoryTask(String repositoryId, StorageAsset localFile) {
547         RepositoryTask task = new RepositoryTask();
548         task.setRepositoryId(repositoryId);
549         task.setResourceFile(localFile);
550         task.setUpdateRelatedArtifacts(true);
551         task.setScanAll(false);
552
553         try {
554             scheduler.queueTask(task);
555         } catch (TaskQueueException e) {
556             log.error("Unable to queue repository task to execute consumers on resource file ['{}"
557                     + "'].", localFile.getName());
558         }
559     }
560
561     private void copyFile(Path sourceFile, StorageAsset targetPath, String targetFilename, boolean fixChecksums)
562             throws IOException {
563
564         targetPath.resolve(targetFilename).replaceDataFromFile(sourceFile);
565
566         if (fixChecksums) {
567             fixChecksums(targetPath.resolve(targetFilename));
568         }
569     }
570
571     /**
572      * Update artifact level metadata. If it does not exist, create the metadata and fix checksums if necessary.
573      */
574     private void updateProjectMetadata(StorageAsset targetPath, Date lastUpdatedTimestamp, String timestamp, int buildNumber,
575                                        boolean fixChecksums, FileMetadata fileMetadata, String groupId,
576                                        String artifactId, String version, String packaging)
577             throws RepositoryMetadataException {
578         List<String> availableVersions = new ArrayList<>();
579         String latestVersion = version;
580
581         StorageAsset projectDir = targetPath.getParent();
582         StorageAsset projectMetadataFile = projectDir.resolve(MetadataTools.MAVEN_METADATA);
583
584         ArchivaRepositoryMetadata projectMetadata = getMetadata(projectMetadataFile);
585
586         if (projectMetadataFile.exists()) {
587             availableVersions = projectMetadata.getAvailableVersions();
588
589             Collections.sort(availableVersions, VersionComparator.getInstance());
590
591             if (!availableVersions.contains(version)) {
592                 availableVersions.add(version);
593             }
594
595             latestVersion = availableVersions.get(availableVersions.size() - 1);
596         } else {
597             availableVersions.add(version);
598
599             projectMetadata.setGroupId(groupId);
600             projectMetadata.setArtifactId(artifactId);
601         }
602
603         if (projectMetadata.getGroupId() == null) {
604             projectMetadata.setGroupId(groupId);
605         }
606
607         if (projectMetadata.getArtifactId() == null) {
608             projectMetadata.setArtifactId(artifactId);
609         }
610
611         projectMetadata.setLatestVersion(latestVersion);
612         projectMetadata.setLastUpdatedTimestamp(lastUpdatedTimestamp);
613         projectMetadata.setAvailableVersions(availableVersions);
614
615         if (!VersionUtil.isSnapshot(version)) {
616             projectMetadata.setReleasedVersion(latestVersion);
617         }
618
619         RepositoryMetadataWriter.write(projectMetadata, projectMetadataFile);
620
621         if (fixChecksums) {
622             fixChecksums(projectMetadataFile);
623         }
624     }
625
626     /**
627      * Update version level metadata for snapshot artifacts. If it does not exist, create the metadata and fix checksums
628      * if necessary.
629      */
630     private void updateVersionMetadata(ArchivaRepositoryMetadata metadata, StorageAsset metadataFile,
631                                        Date lastUpdatedTimestamp, String timestamp, int buildNumber,
632                                        boolean fixChecksums, FileMetadata fileMetadata, String groupId,
633                                        String artifactId, String version, String packaging)
634             throws RepositoryMetadataException {
635         if (!metadataFile.exists()) {
636             metadata.setGroupId(groupId);
637             metadata.setArtifactId(artifactId);
638             metadata.setVersion(version);
639         }
640
641         if (metadata.getSnapshotVersion() == null) {
642             metadata.setSnapshotVersion(new SnapshotVersion());
643         }
644
645         metadata.getSnapshotVersion().setBuildNumber(buildNumber);
646         metadata.getSnapshotVersion().setTimestamp(timestamp);
647         metadata.setLastUpdatedTimestamp(lastUpdatedTimestamp);
648
649         RepositoryMetadataWriter.write(metadata, metadataFile);
650
651         if (fixChecksums) {
652             fixChecksums(metadataFile);
653         }
654     }
655
656
657 }