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