]> source.dussan.org Git - archiva.git/blob
3b3fe4ed27ce31b3b072502905974a9030eaaa25
[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 com.google.common.base.Predicate;
22 import com.google.common.collect.Iterables;
23 import org.apache.archiva.admin.model.RepositoryAdminException;
24 import org.apache.archiva.admin.model.admin.ArchivaAdministration;
25 import org.apache.archiva.admin.model.beans.ManagedRepository;
26 import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin;
27 import org.apache.archiva.checksum.ChecksumAlgorithm;
28 import org.apache.archiva.checksum.ChecksumUtil;
29 import org.apache.archiva.checksum.ChecksummedFile;
30 import org.apache.archiva.common.utils.VersionComparator;
31 import org.apache.archiva.common.utils.VersionUtil;
32 import org.apache.archiva.configuration.ArchivaConfiguration;
33 import org.apache.archiva.maven2.metadata.MavenMetadataReader;
34 import org.apache.archiva.metadata.model.facets.AuditEvent;
35 import org.apache.archiva.model.ArchivaRepositoryMetadata;
36 import org.apache.archiva.model.ArtifactReference;
37 import org.apache.archiva.model.SnapshotVersion;
38 import org.apache.archiva.components.taskqueue.TaskQueueException;
39 import org.apache.archiva.repository.Repository;
40 import org.apache.archiva.repository.RepositoryException;
41 import org.apache.archiva.repository.RepositoryNotFoundException;
42 import org.apache.archiva.repository.RepositoryRegistry;
43 import org.apache.archiva.repository.RepositoryType;
44 import org.apache.archiva.repository.content.base.ArtifactUtil;
45 import org.apache.archiva.repository.metadata.MetadataReader;
46 import org.apache.archiva.repository.metadata.base.MetadataTools;
47 import org.apache.archiva.repository.metadata.RepositoryMetadataException;
48 import org.apache.archiva.repository.metadata.base.RepositoryMetadataWriter;
49 import org.apache.archiva.repository.storage.StorageAsset;
50 import org.apache.archiva.rest.api.services.ArchivaRestServiceException;
51 import org.apache.archiva.rest.services.AbstractRestService;
52 import org.apache.archiva.scheduler.ArchivaTaskScheduler;
53 import org.apache.archiva.scheduler.repository.model.RepositoryTask;
54 import org.apache.archiva.web.model.FileMetadata;
55 import org.apache.archiva.xml.XMLException;
56 import org.apache.commons.io.FilenameUtils;
57 import org.apache.commons.io.IOUtils;
58 import org.apache.commons.lang3.BooleanUtils;
59 import org.apache.commons.lang3.StringUtils;
60 import org.apache.commons.lang3.SystemUtils;
61 import org.apache.cxf.jaxrs.ext.multipart.Attachment;
62 import org.apache.cxf.jaxrs.ext.multipart.MultipartBody;
63 import org.apache.maven.model.Model;
64 import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
65 import org.slf4j.Logger;
66 import org.slf4j.LoggerFactory;
67 import org.springframework.stereotype.Service;
68
69 import javax.annotation.PostConstruct;
70 import javax.inject.Inject;
71 import javax.inject.Named;
72 import javax.servlet.http.HttpServletRequest;
73 import javax.servlet.http.HttpSession;
74 import javax.ws.rs.core.Context;
75 import javax.ws.rs.core.Response;
76 import java.io.*;
77 import java.net.URLDecoder;
78 import java.nio.file.*;
79 import java.text.DateFormat;
80 import java.text.SimpleDateFormat;
81 import java.util.*;
82 import java.util.concurrent.CopyOnWriteArrayList;
83
84 /**
85  *
86  * Service for uploading files to the repository.
87  *
88  * @author Olivier Lamy
89  * @author Martin Stockhammer
90  */
91 @Service("fileUploadService#rest")
92 public class DefaultFileUploadService
93         extends AbstractRestService
94         implements FileUploadService {
95     private Logger log = LoggerFactory.getLogger(getClass());
96
97     @Context
98     private HttpServletRequest httpServletRequest;
99
100     @Inject
101     private ManagedRepositoryAdmin managedRepositoryAdmin;
102
103     @Inject
104     private ArtifactUtil artifactUtil;
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         try {
307             ManagedRepository managedRepository = managedRepositoryAdmin.getManagedRepository(repositoryId);
308
309             if (managedRepository == null) {
310                 // TODO i18n ?
311                 throw new ArchivaRestServiceException("Cannot find managed repository with id " + repositoryId,
312                         Response.Status.BAD_REQUEST.getStatusCode(), null);
313             }
314
315             if (VersionUtil.isSnapshot(version) && !managedRepository.isSnapshots()) {
316                 // TODO i18n ?
317                 throw new ArchivaRestServiceException(
318                         "Managed repository with id " + repositoryId + " do not accept snapshots",
319                         Response.Status.BAD_REQUEST.getStatusCode(), null);
320             }
321         } catch (RepositoryAdminException e) {
322             throw new ArchivaRestServiceException(e.getMessage(),
323                     Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e);
324         }
325
326         // get from the session file with groupId/artifactId
327
328         Iterable<FileMetadata> filesToAdd = Iterables.filter(fileMetadatas, new Predicate<FileMetadata>() {
329             public boolean apply(FileMetadata fileMetadata) {
330                 return fileMetadata != null && !fileMetadata.isPomFile();
331             }
332         });
333         Iterator<FileMetadata> iterator = filesToAdd.iterator();
334         boolean pomGenerated = false;
335         while (iterator.hasNext()) {
336             FileMetadata fileMetadata = iterator.next();
337             log.debug("fileToAdd: {}", fileMetadata);
338             saveFile(repositoryId, fileMetadata, generatePom && !pomGenerated, groupId, artifactId, version,
339                     packaging);
340             pomGenerated = true;
341             deleteFile(fileMetadata.getServerFileName());
342         }
343
344         filesToAdd = Iterables.filter(fileMetadatas, new Predicate<FileMetadata>() {
345             @Override
346             public boolean apply(FileMetadata fileMetadata) {
347                 return fileMetadata != null && fileMetadata.isPomFile();
348             }
349         });
350
351         iterator = filesToAdd.iterator();
352         while (iterator.hasNext()) {
353             FileMetadata fileMetadata = iterator.next();
354             log.debug("fileToAdd: {}", fileMetadata);
355             savePomFile(repositoryId, fileMetadata, groupId, artifactId, version, packaging);
356             deleteFile(fileMetadata.getServerFileName());
357         }
358
359         return Boolean.TRUE;
360     }
361
362     protected void savePomFile(String repositoryId, FileMetadata fileMetadata, String groupId, String artifactId,
363                                String version, String packaging)
364             throws ArchivaRestServiceException {
365
366         log.debug("Saving POM");
367         try {
368             boolean fixChecksums =
369                     !(archivaAdministration.getKnownContentConsumers().contains("create-missing-checksums"));
370
371             org.apache.archiva.repository.ManagedRepository repoConfig = repositoryRegistry.getManagedRepository(repositoryId);
372
373             ArtifactReference artifactReference = createArtifactRef(fileMetadata, groupId, artifactId, version);
374             artifactReference.setType(packaging);
375
376             StorageAsset pomPath = artifactUtil.getArtifactAsset(repoConfig, artifactReference);
377             StorageAsset targetPath = pomPath.getParent();
378
379             String pomFilename = pomPath.getName();
380             if (StringUtils.isNotEmpty(fileMetadata.getClassifier())) {
381                 pomFilename = StringUtils.remove(pomFilename, "-" + fileMetadata.getClassifier());
382             }
383             pomFilename = FilenameUtils.removeExtension(pomFilename) + ".pom";
384
385             copyFile(Paths.get(fileMetadata.getServerFileName()), targetPath, pomFilename, fixChecksums);
386             triggerAuditEvent(repoConfig.getId(), targetPath.resolve(pomFilename).toString(), AuditEvent.UPLOAD_FILE);
387             queueRepositoryTask(repoConfig.getId(), targetPath.resolve(pomFilename));
388             log.debug("Finished Saving POM");
389         } catch (IOException ie) {
390             log.error("IOException for POM {}", ie.getMessage());
391             throw new ArchivaRestServiceException("Error encountered while uploading pom file: " + ie.getMessage(),
392                     Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), ie);
393         } catch (RepositoryException rep) {
394             log.error("RepositoryException for POM {}", rep.getMessage());
395             throw new ArchivaRestServiceException("Repository exception: " + rep.getMessage(),
396                     Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), rep);
397         } catch (RepositoryAdminException e) {
398             log.error("RepositoryAdminException for POM {}", e.getMessage());
399             throw new ArchivaRestServiceException("RepositoryAdmin exception: " + e.getMessage(),
400                     Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e);
401         }
402     }
403
404     protected void saveFile(String repositoryId, FileMetadata fileMetadata, boolean generatePom, String groupId,
405                             String artifactId, String version, String packaging)
406             throws ArchivaRestServiceException {
407         log.debug("Saving file");
408         try {
409
410             org.apache.archiva.repository.ManagedRepository repoConfig = repositoryRegistry.getManagedRepository(repositoryId);
411
412             ArtifactReference artifactReference = createArtifactRef(fileMetadata, groupId, artifactId, version);
413             artifactReference.setType(
414                     StringUtils.isEmpty(fileMetadata.getPackaging()) ? packaging : fileMetadata.getPackaging());
415
416             StorageAsset artifactPath = artifactUtil.getArtifactAsset(repoConfig, artifactReference);
417             StorageAsset targetPath = artifactPath.getParent();
418
419             log.debug("artifactPath: {} found targetPath: {}", artifactPath, targetPath);
420
421             Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
422             int newBuildNumber = -1;
423             String timestamp = null;
424
425             StorageAsset versionMetadataFile = targetPath.resolve(MetadataTools.MAVEN_METADATA);
426             ArchivaRepositoryMetadata versionMetadata = getMetadata(versionMetadataFile);
427
428             if (VersionUtil.isSnapshot(version)) {
429                 TimeZone timezone = TimeZone.getTimeZone("UTC");
430                 DateFormat fmt = new SimpleDateFormat("yyyyMMdd.HHmmss");
431                 fmt.setTimeZone(timezone);
432                 timestamp = fmt.format(lastUpdatedTimestamp);
433                 if (versionMetadata.getSnapshotVersion() != null) {
434                     newBuildNumber = versionMetadata.getSnapshotVersion().getBuildNumber() + 1;
435                 } else {
436                     newBuildNumber = 1;
437                 }
438             }
439
440             if (!targetPath.exists()) {
441                 targetPath.create();
442             }
443
444             String filename = artifactPath.getName().toString();
445             if (VersionUtil.isSnapshot(version)) {
446                 filename = filename.replaceAll(VersionUtil.SNAPSHOT, timestamp + "-" + newBuildNumber);
447             }
448
449             // We always fix checksums for newly uploaded files, even if the content consumer is active.
450             boolean fixChecksums = true;
451             // !(archivaAdministration.getKnownContentConsumers().contains("create-missing-checksums"));
452
453             try {
454                 StorageAsset targetFile = targetPath.resolve(filename);
455                 if (targetFile.exists() && !VersionUtil.isSnapshot(version) && repoConfig.blocksRedeployments()) {
456                     throw new ArchivaRestServiceException(
457                             "Overwriting released artifacts in repository '" + repoConfig.getId() + "' is not allowed.",
458                             Response.Status.BAD_REQUEST.getStatusCode(), null);
459                 } else {
460                     copyFile(Paths.get(fileMetadata.getServerFileName()), targetPath, filename, fixChecksums);
461                     triggerAuditEvent(repoConfig.getId(), artifactPath.toString(), AuditEvent.UPLOAD_FILE);
462                     queueRepositoryTask(repoConfig.getId(), targetFile);
463                 }
464             } catch (IOException ie) {
465                 log.error("IOException copying file: {}", ie.getMessage(), ie);
466                 throw new ArchivaRestServiceException(
467                         "Overwriting released artifacts in repository '" + repoConfig.getId() + "' is not allowed.",
468                         Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), ie);
469             }
470
471             if (generatePom) {
472                 String pomFilename = filename;
473                 if (StringUtils.isNotEmpty(fileMetadata.getClassifier())) {
474                     pomFilename = StringUtils.remove(pomFilename, "-" + fileMetadata.getClassifier());
475                 }
476                 pomFilename = FilenameUtils.removeExtension(pomFilename) + ".pom";
477
478                 try {
479                     StorageAsset generatedPomFile =
480                             createPom(targetPath, pomFilename, fileMetadata, groupId, artifactId, version, packaging);
481                     triggerAuditEvent(repoConfig.getId(), targetPath.resolve(pomFilename).toString(), AuditEvent.UPLOAD_FILE);
482                     if (fixChecksums) {
483                         fixChecksums(generatedPomFile);
484                     }
485                     queueRepositoryTask(repoConfig.getId(), generatedPomFile);
486                 } catch (IOException ie) {
487                     throw new ArchivaRestServiceException(
488                             "Error encountered while writing pom file: " + ie.getMessage(),
489                             Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), ie);
490                 }
491             }
492
493             // explicitly update only if metadata-updater consumer is not enabled!
494             if (!archivaAdministration.getKnownContentConsumers().contains("metadata-updater")) {
495                 updateProjectMetadata(targetPath, lastUpdatedTimestamp, timestamp, newBuildNumber,
496                         fixChecksums, fileMetadata, groupId, artifactId, version, packaging);
497
498                 if (VersionUtil.isSnapshot(version)) {
499                     updateVersionMetadata(versionMetadata, versionMetadataFile, lastUpdatedTimestamp, timestamp,
500                             newBuildNumber, fixChecksums, fileMetadata, groupId, artifactId, version,
501                             packaging);
502                 }
503             }
504         } catch (RepositoryNotFoundException re) {
505             log.error("RepositoryNotFoundException during save {}", re.getMessage());
506             re.printStackTrace();
507             throw new ArchivaRestServiceException("Target repository cannot be found: " + re.getMessage(),
508                     Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), re);
509         } catch (RepositoryException rep) {
510             log.error("RepositoryException during save {}", rep.getMessage());
511             throw new ArchivaRestServiceException("Repository exception: " + rep.getMessage(),
512                     Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), rep);
513         } catch (RepositoryAdminException e) {
514             log.error("RepositoryAdminException during save {}", e.getMessage());
515             throw new ArchivaRestServiceException("RepositoryAdmin exception: " + e.getMessage(),
516                     Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e);
517         } catch (IOException e) {
518             log.error("IOException during save {}", e.getMessage());
519             throw new ArchivaRestServiceException("Repository exception " + e.getMessage(),
520                     Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e);
521         }
522     }
523
524     private ArtifactReference createArtifactRef(FileMetadata fileMetadata, String groupId, String artifactId, String version) {
525         ArtifactReference artifactReference = new ArtifactReference();
526         artifactReference.setArtifactId(artifactId);
527         artifactReference.setGroupId(groupId);
528         artifactReference.setVersion(version);
529         artifactReference.setClassifier(fileMetadata.getClassifier());
530         return artifactReference;
531     }
532
533     private ArchivaRepositoryMetadata getMetadata(StorageAsset metadataFile)
534             throws RepositoryMetadataException {
535         ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
536         if (metadataFile.exists()) {
537             Repository repo = repositoryRegistry.getRepositoryOfAsset( metadataFile );
538             RepositoryType type = repo == null ? RepositoryType.MAVEN : repo.getType( );
539             MetadataReader metadataReader = repositoryRegistry.getMetadataReader( type );
540             metadata = metadataReader.read(metadataFile);
541         }
542         return metadata;
543     }
544
545     private StorageAsset createPom(StorageAsset targetPath, String filename, FileMetadata fileMetadata, String groupId,
546                            String artifactId, String version, String packaging)
547             throws IOException {
548         Model projectModel = new Model();
549         projectModel.setModelVersion("4.0.0");
550         projectModel.setGroupId(groupId);
551         projectModel.setArtifactId(artifactId);
552         projectModel.setVersion(version);
553         projectModel.setPackaging(packaging);
554
555         StorageAsset pomFile = targetPath.resolve(filename);
556         MavenXpp3Writer writer = new MavenXpp3Writer();
557
558         try (Writer w = new OutputStreamWriter(pomFile.getWriteStream(true))) {
559             writer.write(w, projectModel);
560         }
561
562         return pomFile;
563     }
564
565     private void fixChecksums(StorageAsset file) {
566         ChecksummedFile checksum = new ChecksummedFile(file.getFilePath());
567         checksum.fixChecksums(algorithms);
568     }
569
570     private void queueRepositoryTask(String repositoryId, StorageAsset localFile) {
571         RepositoryTask task = new RepositoryTask();
572         task.setRepositoryId(repositoryId);
573         task.setResourceFile(localFile);
574         task.setUpdateRelatedArtifacts(true);
575         task.setScanAll(false);
576
577         try {
578             scheduler.queueTask(task);
579         } catch (TaskQueueException e) {
580             log.error("Unable to queue repository task to execute consumers on resource file ['{}"
581                     + "'].", localFile.getName());
582         }
583     }
584
585     private void copyFile(Path sourceFile, StorageAsset targetPath, String targetFilename, boolean fixChecksums)
586             throws IOException {
587
588         targetPath.resolve(targetFilename).replaceDataFromFile(sourceFile);
589
590         if (fixChecksums) {
591             fixChecksums(targetPath.resolve(targetFilename));
592         }
593     }
594
595     /**
596      * Update artifact level metadata. If it does not exist, create the metadata and fix checksums if necessary.
597      */
598     private void updateProjectMetadata(StorageAsset targetPath, Date lastUpdatedTimestamp, String timestamp, int buildNumber,
599                                        boolean fixChecksums, FileMetadata fileMetadata, String groupId,
600                                        String artifactId, String version, String packaging)
601             throws RepositoryMetadataException {
602         List<String> availableVersions = new ArrayList<>();
603         String latestVersion = version;
604
605         StorageAsset projectDir = targetPath.getParent();
606         StorageAsset projectMetadataFile = projectDir.resolve(MetadataTools.MAVEN_METADATA);
607
608         ArchivaRepositoryMetadata projectMetadata = getMetadata(projectMetadataFile);
609
610         if (projectMetadataFile.exists()) {
611             availableVersions = projectMetadata.getAvailableVersions();
612
613             Collections.sort(availableVersions, VersionComparator.getInstance());
614
615             if (!availableVersions.contains(version)) {
616                 availableVersions.add(version);
617             }
618
619             latestVersion = availableVersions.get(availableVersions.size() - 1);
620         } else {
621             availableVersions.add(version);
622
623             projectMetadata.setGroupId(groupId);
624             projectMetadata.setArtifactId(artifactId);
625         }
626
627         if (projectMetadata.getGroupId() == null) {
628             projectMetadata.setGroupId(groupId);
629         }
630
631         if (projectMetadata.getArtifactId() == null) {
632             projectMetadata.setArtifactId(artifactId);
633         }
634
635         projectMetadata.setLatestVersion(latestVersion);
636         projectMetadata.setLastUpdatedTimestamp(lastUpdatedTimestamp);
637         projectMetadata.setAvailableVersions(availableVersions);
638
639         if (!VersionUtil.isSnapshot(version)) {
640             projectMetadata.setReleasedVersion(latestVersion);
641         }
642
643         RepositoryMetadataWriter.write(projectMetadata, projectMetadataFile);
644
645         if (fixChecksums) {
646             fixChecksums(projectMetadataFile);
647         }
648     }
649
650     /**
651      * Update version level metadata for snapshot artifacts. If it does not exist, create the metadata and fix checksums
652      * if necessary.
653      */
654     private void updateVersionMetadata(ArchivaRepositoryMetadata metadata, StorageAsset metadataFile,
655                                        Date lastUpdatedTimestamp, String timestamp, int buildNumber,
656                                        boolean fixChecksums, FileMetadata fileMetadata, String groupId,
657                                        String artifactId, String version, String packaging)
658             throws RepositoryMetadataException {
659         if (!metadataFile.exists()) {
660             metadata.setGroupId(groupId);
661             metadata.setArtifactId(artifactId);
662             metadata.setVersion(version);
663         }
664
665         if (metadata.getSnapshotVersion() == null) {
666             metadata.setSnapshotVersion(new SnapshotVersion());
667         }
668
669         metadata.getSnapshotVersion().setBuildNumber(buildNumber);
670         metadata.getSnapshotVersion().setTimestamp(timestamp);
671         metadata.setLastUpdatedTimestamp(lastUpdatedTimestamp);
672
673         RepositoryMetadataWriter.write(metadata, metadataFile);
674
675         if (fixChecksums) {
676             fixChecksums(metadataFile);
677         }
678     }
679
680
681 }