1 package org.apache.archiva.web.api;
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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
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.redback.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;
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;
73 import java.net.URLDecoder;
74 import java.nio.file.*;
75 import java.text.DateFormat;
76 import java.text.SimpleDateFormat;
78 import java.util.concurrent.CopyOnWriteArrayList;
82 * Service for uploading files to the repository.
84 * @author Olivier Lamy
85 * @author Martin Stockhammer
87 @Service("fileUploadService#rest")
88 public class DefaultFileUploadService
89 extends AbstractRestService
90 implements FileUploadService {
91 private Logger log = LoggerFactory.getLogger(getClass());
94 private HttpServletRequest httpServletRequest;
97 private ManagedRepositoryAdmin managedRepositoryAdmin;
100 private ArtifactUtil artifactUtil;
103 private ArchivaAdministration archivaAdministration;
106 ArchivaConfiguration configuration;
108 private List<ChecksumAlgorithm> algorithms;
110 private final String FS = FileSystems.getDefault().getSeparator();
113 @Named(value = "archivaTaskScheduler#repository")
114 private ArchivaTaskScheduler<RepositoryTask> scheduler;
116 private String getStringValue(MultipartBody multipartBody, String attachmentId)
118 Attachment attachment = multipartBody.getAttachment(attachmentId);
119 return attachment == null ? "" :
120 StringUtils.trim(URLDecoder.decode(IOUtils.toString(attachment.getDataHandler().getInputStream(), "UTF-8"), "UTF-8"));
124 private void initialize() {
125 algorithms = ChecksumUtil.getAlgorithms(configuration.getConfiguration().getArchivaRuntimeConfiguration().getChecksumTypes());
129 public FileMetadata post(MultipartBody multipartBody)
130 throws ArchivaRestServiceException {
134 String classifier = getStringValue(multipartBody, "classifier");
135 String packaging = getStringValue(multipartBody, "packaging");
137 checkParamChars("classifier", classifier);
138 checkParamChars("packaging", packaging);
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", ""
143 boolean pomFile = false;
145 pomFile = BooleanUtils.toBoolean(getStringValue(multipartBody, "pomFile"));
146 } catch (IllegalArgumentException ex) {
147 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");
154 Attachment file = multipartBody.getAttachment("files[]");
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 ArchivaRestServiceException e = new ArchivaRestServiceException("Bad filename in upload content: " + fileName + " - File traversal chars (..|/) are not allowed"
162 e.setHttpErrorCode(422);
163 e.setErrorKey("fileupload.malformed.filename");
167 Path tmpFile = Files.createTempFile("upload-artifact", ".tmp");
168 tmpFile.toFile().deleteOnExit();
169 IOUtils.copy(file.getDataHandler().getInputStream(), new FileOutputStream(tmpFile.toFile()));
170 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);
177 log.info("uploading file: {}", fileMetadata);
179 List<FileMetadata> fileMetadatas = getSessionFilesList();
181 fileMetadatas.add(fileMetadata);
184 } catch (IOException e) {
185 throw new ArchivaRestServiceException(e.getMessage(),
186 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e);
192 * @return The file list from the session.
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);
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
223 removed = getSessionFileMetadatas().remove(new FileMetadata(file.toString()));
227 Files.deleteIfExists(file);
229 } catch (IOException e) {
230 log.error("Could not delete file {}: {}", file, e.getMessage(), e);
233 return Boolean.FALSE;
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());
243 getSessionFileMetadatas().clear();
248 public List<FileMetadata> getSessionFileMetadatas()
249 throws ArchivaRestServiceException {
250 return getSessionFilesList();
254 private boolean hasValidChars(String checkString) {
255 if (checkString.contains(FS)) {
258 if (checkString.contains("../")) {
261 if (checkString.contains("/..")) {
267 private void checkParamChars(String param, String value) throws ArchivaRestServiceException {
268 if (!hasValidChars(value)) {
269 ArchivaRestServiceException e = new ArchivaRestServiceException("Bad characters in " + param, null);
270 e.setHttpErrorCode(422);
271 e.setErrorKey("fileupload.malformed.param");
272 e.setFieldName(param);
278 public Boolean save(String repositoryId, String groupId, String artifactId, String version, String packaging,
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);
287 checkParamChars("repositoryId", repositoryId);
288 checkParamChars("groupId", groupId);
289 checkParamChars("artifactId", artifactId);
290 checkParamChars("version", version);
291 checkParamChars("packaging", packaging);
294 List<FileMetadata> fileMetadatas = getSessionFilesList();
295 if (fileMetadatas == null || fileMetadatas.isEmpty()) {
296 return Boolean.FALSE;
300 ManagedRepository managedRepository = managedRepositoryAdmin.getManagedRepository(repositoryId);
302 if (managedRepository == null) {
304 throw new ArchivaRestServiceException("Cannot find managed repository with id " + repositoryId,
305 Response.Status.BAD_REQUEST.getStatusCode(), null);
308 if (VersionUtil.isSnapshot(version) && !managedRepository.isSnapshots()) {
310 throw new ArchivaRestServiceException(
311 "Managed repository with id " + repositoryId + " do not accept snapshots",
312 Response.Status.BAD_REQUEST.getStatusCode(), null);
314 } catch (RepositoryAdminException e) {
315 throw new ArchivaRestServiceException(e.getMessage(),
316 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e);
319 // get from the session file with groupId/artifactId
321 Iterable<FileMetadata> filesToAdd = Iterables.filter(fileMetadatas, new Predicate<FileMetadata>() {
322 public boolean apply(FileMetadata fileMetadata) {
323 return fileMetadata != null && !fileMetadata.isPomFile();
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,
334 deleteFile(fileMetadata.getServerFileName());
337 filesToAdd = Iterables.filter(fileMetadatas, new Predicate<FileMetadata>() {
339 public boolean apply(FileMetadata fileMetadata) {
340 return fileMetadata != null && fileMetadata.isPomFile();
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());
355 protected void savePomFile(String repositoryId, FileMetadata fileMetadata, String groupId, String artifactId,
356 String version, String packaging)
357 throws ArchivaRestServiceException {
359 log.debug("Saving POM");
361 boolean fixChecksums =
362 !(archivaAdministration.getKnownContentConsumers().contains("create-missing-checksums"));
364 org.apache.archiva.repository.ManagedRepository repoConfig = repositoryRegistry.getManagedRepository(repositoryId);
366 ArtifactReference artifactReference = createArtifactRef(fileMetadata, groupId, artifactId, version);
367 artifactReference.setType(packaging);
369 StorageAsset pomPath = artifactUtil.getArtifactAsset(repoConfig, artifactReference);
370 StorageAsset targetPath = pomPath.getParent();
372 String pomFilename = pomPath.getName();
373 if (StringUtils.isNotEmpty(fileMetadata.getClassifier())) {
374 pomFilename = StringUtils.remove(pomFilename, "-" + fileMetadata.getClassifier());
376 pomFilename = FilenameUtils.removeExtension(pomFilename) + ".pom";
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);
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");
403 org.apache.archiva.repository.ManagedRepository repoConfig = repositoryRegistry.getManagedRepository(repositoryId);
405 ArtifactReference artifactReference = createArtifactRef(fileMetadata, groupId, artifactId, version);
406 artifactReference.setType(
407 StringUtils.isEmpty(fileMetadata.getPackaging()) ? packaging : fileMetadata.getPackaging());
409 StorageAsset artifactPath = artifactUtil.getArtifactAsset(repoConfig, artifactReference);
410 StorageAsset targetPath = artifactPath.getParent();
412 log.debug("artifactPath: {} found targetPath: {}", artifactPath, targetPath);
414 Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
415 int newBuildNumber = -1;
416 String timestamp = null;
418 StorageAsset versionMetadataFile = targetPath.resolve(MetadataTools.MAVEN_METADATA);
419 ArchivaRepositoryMetadata versionMetadata = getMetadata(versionMetadataFile);
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;
433 if (!targetPath.exists()) {
437 String filename = artifactPath.getName().toString();
438 if (VersionUtil.isSnapshot(version)) {
439 filename = filename.replaceAll(VersionUtil.SNAPSHOT, timestamp + "-" + newBuildNumber);
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"));
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);
453 copyFile(Paths.get(fileMetadata.getServerFileName()), targetPath, filename, fixChecksums);
454 triggerAuditEvent(repoConfig.getId(), artifactPath.toString(), AuditEvent.UPLOAD_FILE);
455 queueRepositoryTask(repoConfig.getId(), targetFile);
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);
465 String pomFilename = filename;
466 if (StringUtils.isNotEmpty(fileMetadata.getClassifier())) {
467 pomFilename = StringUtils.remove(pomFilename, "-" + fileMetadata.getClassifier());
469 pomFilename = FilenameUtils.removeExtension(pomFilename) + ".pom";
472 StorageAsset generatedPomFile =
473 createPom(targetPath, pomFilename, fileMetadata, groupId, artifactId, version, packaging);
474 triggerAuditEvent(repoConfig.getId(), targetPath.resolve(pomFilename).toString(), AuditEvent.UPLOAD_FILE);
476 fixChecksums(generatedPomFile);
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);
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);
491 if (VersionUtil.isSnapshot(version)) {
492 updateVersionMetadata(versionMetadata, versionMetadataFile, lastUpdatedTimestamp, timestamp,
493 newBuildNumber, fixChecksums, fileMetadata, groupId, artifactId, version,
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);
517 private ArtifactReference createArtifactRef(FileMetadata fileMetadata, String groupId, String artifactId, String version) {
518 ArtifactReference artifactReference = new ArtifactReference();
519 artifactReference.setArtifactId(artifactId);
520 artifactReference.setGroupId(groupId);
521 artifactReference.setVersion(version);
522 artifactReference.setClassifier(fileMetadata.getClassifier());
523 return artifactReference;
526 private ArchivaRepositoryMetadata getMetadata(StorageAsset metadataFile)
527 throws RepositoryMetadataException {
528 ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
529 if (metadataFile.exists()) {
531 metadata = MavenMetadataReader.read(metadataFile);
532 } catch (XMLException | IOException e) {
533 throw new RepositoryMetadataException(e.getMessage(), e);
539 private StorageAsset createPom(StorageAsset targetPath, String filename, FileMetadata fileMetadata, String groupId,
540 String artifactId, String version, String packaging)
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);
549 StorageAsset pomFile = targetPath.resolve(filename);
550 MavenXpp3Writer writer = new MavenXpp3Writer();
552 try (Writer w = new OutputStreamWriter(pomFile.getWriteStream(true))) {
553 writer.write(w, projectModel);
559 private void fixChecksums(StorageAsset file) {
560 ChecksummedFile checksum = new ChecksummedFile(file.getFilePath());
561 checksum.fixChecksums(algorithms);
564 private void queueRepositoryTask(String repositoryId, StorageAsset localFile) {
565 RepositoryTask task = new RepositoryTask();
566 task.setRepositoryId(repositoryId);
567 task.setResourceFile(localFile);
568 task.setUpdateRelatedArtifacts(true);
569 task.setScanAll(false);
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());
579 private void copyFile(Path sourceFile, StorageAsset targetPath, String targetFilename, boolean fixChecksums)
582 targetPath.resolve(targetFilename).replaceDataFromFile(sourceFile);
585 fixChecksums(targetPath.resolve(targetFilename));
590 * Update artifact level metadata. If it does not exist, create the metadata and fix checksums if necessary.
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;
599 StorageAsset projectDir = targetPath.getParent();
600 StorageAsset projectMetadataFile = projectDir.resolve(MetadataTools.MAVEN_METADATA);
602 ArchivaRepositoryMetadata projectMetadata = getMetadata(projectMetadataFile);
604 if (projectMetadataFile.exists()) {
605 availableVersions = projectMetadata.getAvailableVersions();
607 Collections.sort(availableVersions, VersionComparator.getInstance());
609 if (!availableVersions.contains(version)) {
610 availableVersions.add(version);
613 latestVersion = availableVersions.get(availableVersions.size() - 1);
615 availableVersions.add(version);
617 projectMetadata.setGroupId(groupId);
618 projectMetadata.setArtifactId(artifactId);
621 if (projectMetadata.getGroupId() == null) {
622 projectMetadata.setGroupId(groupId);
625 if (projectMetadata.getArtifactId() == null) {
626 projectMetadata.setArtifactId(artifactId);
629 projectMetadata.setLatestVersion(latestVersion);
630 projectMetadata.setLastUpdatedTimestamp(lastUpdatedTimestamp);
631 projectMetadata.setAvailableVersions(availableVersions);
633 if (!VersionUtil.isSnapshot(version)) {
634 projectMetadata.setReleasedVersion(latestVersion);
637 RepositoryMetadataWriter.write(projectMetadata, projectMetadataFile);
640 fixChecksums(projectMetadataFile);
645 * Update version level metadata for snapshot artifacts. If it does not exist, create the metadata and fix checksums
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);
659 if (metadata.getSnapshotVersion() == null) {
660 metadata.setSnapshotVersion(new SnapshotVersion());
663 metadata.getSnapshotVersion().setBuildNumber(buildNumber);
664 metadata.getSnapshotVersion().setTimestamp(timestamp);
665 metadata.setLastUpdatedTimestamp(lastUpdatedTimestamp);
667 RepositoryMetadataWriter.write(metadata, metadataFile);
670 fixChecksums(metadataFile);