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 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;
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;
92 * Service for uploading files to the repository.
94 * @author Olivier Lamy
95 * @author Martin Stockhammer
97 @Service("fileUploadService#rest")
98 public class DefaultFileUploadService
99 extends AbstractRestService
100 implements FileUploadService {
101 private Logger log = LoggerFactory.getLogger(getClass());
104 private HttpServletRequest httpServletRequest;
107 private ArchivaAdministration archivaAdministration;
110 ArchivaConfiguration configuration;
112 private List<ChecksumAlgorithm> algorithms;
114 private final String FS = FileSystems.getDefault().getSeparator();
117 @Named(value = "archivaTaskScheduler#repository")
118 private ArchivaTaskScheduler<RepositoryTask> scheduler;
121 private RepositoryRegistry repositoryRegistry;
123 private String getStringValue(MultipartBody multipartBody, String attachmentId)
125 Attachment attachment = multipartBody.getAttachment(attachmentId);
126 return attachment == null ? "" :
127 StringUtils.trim(URLDecoder.decode(IOUtils.toString(attachment.getDataHandler().getInputStream(), "UTF-8"), "UTF-8"));
131 private void initialize() {
132 algorithms = ChecksumUtil.getAlgorithms(configuration.getConfiguration().getArchivaRuntimeConfiguration().getChecksumTypes());
136 public FileMetadata post(MultipartBody multipartBody)
137 throws ArchivaRestServiceException {
141 String classifier = getStringValue(multipartBody, "classifier");
142 String packaging = getStringValue(multipartBody, "packaging");
144 checkParamChars("classifier", classifier);
145 checkParamChars("packaging", packaging);
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", ""
150 boolean pomFile = false;
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");
161 Attachment file = multipartBody.getAttachment("files[]");
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"
169 e.setHttpErrorCode(422);
170 e.setErrorKey("fileupload.malformed.filename");
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);
184 log.info("uploading file: {}", fileMetadata);
186 List<FileMetadata> fileMetadatas = getSessionFilesList();
188 fileMetadatas.add(fileMetadata);
191 } catch (IOException e) {
192 throw new ArchivaRestServiceException(e.getMessage(),
193 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e);
199 * @return The file list from the session.
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);
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
230 removed = getSessionFileMetadatas().remove(new FileMetadata(file.toString()));
234 Files.deleteIfExists(file);
236 } catch (IOException e) {
237 log.error("Could not delete file {}: {}", file, e.getMessage(), e);
240 return Boolean.FALSE;
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());
250 getSessionFileMetadatas().clear();
255 public List<FileMetadata> getSessionFileMetadatas()
256 throws ArchivaRestServiceException {
257 return getSessionFilesList();
261 private boolean hasValidChars(String checkString) {
262 if (checkString.contains(FS)) {
265 if (checkString.contains("../")) {
268 if (checkString.contains("/..")) {
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);
285 public Boolean save(String repositoryId, String groupId, String artifactId, String version, String packaging,
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);
294 checkParamChars("repositoryId", repositoryId);
295 checkParamChars("groupId", groupId);
296 checkParamChars("artifactId", artifactId);
297 checkParamChars("version", version);
298 checkParamChars("packaging", packaging);
301 List<FileMetadata> fileMetadatas = getSessionFilesList();
302 if (fileMetadatas == null || fileMetadatas.isEmpty()) {
303 return Boolean.FALSE;
306 org.apache.archiva.repository.ManagedRepository repository = repositoryRegistry.getManagedRepository(repositoryId);
307 if (repository == null) {
309 throw new ArchivaRestServiceException("Cannot find managed repository with id " + repositoryId,
310 Response.Status.BAD_REQUEST.getStatusCode(), null);
313 if (VersionUtil.isSnapshot(version) && !repository.getActiveReleaseSchemes().contains( ReleaseScheme.SNAPSHOT )) {
315 throw new ArchivaRestServiceException(
316 "Managed repository with id " + repositoryId + " do not accept snapshots",
317 Response.Status.BAD_REQUEST.getStatusCode(), null);
320 // get from the session file with groupId/artifactId
322 Iterator<FileMetadata> iterator = fileMetadatas.stream( )
323 .filter( fileMetadata -> fileMetadata != null && !fileMetadata.isPomFile( ) )
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,
332 deleteFile(fileMetadata.getServerFileName());
335 iterator = fileMetadatas.stream( ).filter( fileMetadata -> fileMetadata != null && fileMetadata.isPomFile( ) )
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());
347 protected void savePomFile(String repositoryId, FileMetadata fileMetadata, String groupId, String artifactId,
348 String version, String packaging)
349 throws ArchivaRestServiceException {
351 log.debug("Saving POM");
353 boolean fixChecksums =
354 !(archivaAdministration.getKnownContentConsumers().contains("create-missing-checksums"));
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();
364 StorageAsset pomPath = repository.getContent( ).getItem( selector ).getAsset();
365 StorageAsset targetPath = pomPath.getParent();
367 String pomFilename = pomPath.getName();
368 if (StringUtils.isNotEmpty(fileMetadata.getClassifier())) {
369 pomFilename = StringUtils.remove(pomFilename, "-" + fileMetadata.getClassifier());
371 pomFilename = FilenameUtils.removeExtension(pomFilename) + ".pom";
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);
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);
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");
395 org.apache.archiva.repository.ManagedRepository repository = repositoryRegistry.getManagedRepository(repositoryId);
397 ItemSelector selector = ArchivaItemSelector.builder( )
398 .withNamespace( groupId )
399 .withProjectId( artifactId )
400 .withArtifactId( artifactId )
401 .withArtifactVersion( version )
402 .withExtension( packaging ).build();
404 StorageAsset artifactPath = repository.getContent( ).getItem( selector ).getAsset();
405 StorageAsset targetPath = artifactPath.getParent();
407 log.debug("artifactPath: {} found targetPath: {}", artifactPath, targetPath);
409 Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
410 int newBuildNumber = -1;
411 String timestamp = null;
413 StorageAsset versionMetadataFile = targetPath.resolve(MetadataTools.MAVEN_METADATA);
414 ArchivaRepositoryMetadata versionMetadata = getMetadata(versionMetadataFile);
416 if (VersionUtil.isSnapshot(version)) {
417 TimeZone timezone = TimeZone.getTimeZone("UTC");
418 DateFormat fmt = new SimpleDateFormat("yyyyMMdd.HHmmss");
419 fmt.setTimeZone(timezone);
420 timestamp = fmt.format(lastUpdatedTimestamp);
421 if (versionMetadata.getSnapshotVersion() != null) {
422 newBuildNumber = versionMetadata.getSnapshotVersion().getBuildNumber() + 1;
428 if (!targetPath.exists()) {
432 String filename = artifactPath.getName().toString();
433 if (VersionUtil.isSnapshot(version)) {
434 filename = filename.replaceAll(VersionUtil.SNAPSHOT, timestamp + "-" + newBuildNumber);
437 // We always fix checksums for newly uploaded files, even if the content consumer is active.
438 boolean fixChecksums = true;
439 // !(archivaAdministration.getKnownContentConsumers().contains("create-missing-checksums"));
442 StorageAsset targetFile = targetPath.resolve(filename);
443 if (targetFile.exists() && !VersionUtil.isSnapshot(version) && repository.blocksRedeployments()) {
444 throw new ArchivaRestServiceException(
445 "Overwriting released artifacts in repository '" + repository.getId() + "' is not allowed.",
446 Response.Status.BAD_REQUEST.getStatusCode(), null);
448 copyFile(Paths.get(fileMetadata.getServerFileName()), targetPath, filename, fixChecksums);
449 triggerAuditEvent(repository.getId(), artifactPath.toString(), AuditEvent.UPLOAD_FILE);
450 queueRepositoryTask(repository.getId(), targetFile);
452 } catch (IOException ie) {
453 log.error("IOException copying file: {}", ie.getMessage(), ie);
454 throw new ArchivaRestServiceException(
455 "Overwriting released artifacts in repository '" + repository.getId() + "' is not allowed.",
456 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), ie);
460 String pomFilename = filename;
461 if (StringUtils.isNotEmpty(fileMetadata.getClassifier())) {
462 pomFilename = StringUtils.remove(pomFilename, "-" + fileMetadata.getClassifier());
464 pomFilename = FilenameUtils.removeExtension(pomFilename) + ".pom";
467 StorageAsset generatedPomFile =
468 createPom(targetPath, pomFilename, fileMetadata, groupId, artifactId, version, packaging);
469 triggerAuditEvent(repository.getId(), targetPath.resolve(pomFilename).toString(), AuditEvent.UPLOAD_FILE);
471 fixChecksums(generatedPomFile);
473 queueRepositoryTask(repository.getId(), generatedPomFile);
474 } catch (IOException ie) {
475 throw new ArchivaRestServiceException(
476 "Error encountered while writing pom file: " + ie.getMessage(),
477 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), ie);
481 // explicitly update only if metadata-updater consumer is not enabled!
482 if (!archivaAdministration.getKnownContentConsumers().contains("metadata-updater")) {
483 updateProjectMetadata(targetPath, lastUpdatedTimestamp, timestamp, newBuildNumber,
484 fixChecksums, fileMetadata, groupId, artifactId, version, packaging);
486 if (VersionUtil.isSnapshot(version)) {
487 updateVersionMetadata(versionMetadata, versionMetadataFile, lastUpdatedTimestamp, timestamp,
488 newBuildNumber, fixChecksums, fileMetadata, groupId, artifactId, version,
493 catch (RepositoryException rep) {
494 log.error("RepositoryException during save {}", rep.getMessage());
495 throw new ArchivaRestServiceException("Repository exception: " + rep.getMessage(),
496 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), rep);
497 } catch (RepositoryAdminException e) {
498 log.error("RepositoryAdminException during save {}", e.getMessage());
499 throw new ArchivaRestServiceException("RepositoryAdmin exception: " + e.getMessage(),
500 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e);
501 } catch (IOException e) {
502 log.error("IOException during save {}", e.getMessage());
503 throw new ArchivaRestServiceException("Repository exception " + e.getMessage(),
504 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e);
508 private ArchivaRepositoryMetadata getMetadata(StorageAsset metadataFile)
509 throws RepositoryMetadataException {
510 ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
511 if (metadataFile.exists()) {
512 Repository repo = repositoryRegistry.getRepositoryOfAsset( metadataFile );
513 RepositoryType type = repo == null ? RepositoryType.MAVEN : repo.getType( );
514 MetadataReader metadataReader = repositoryRegistry.getMetadataReader( type );
515 metadata = metadataReader.read(metadataFile);
520 private StorageAsset createPom(StorageAsset targetPath, String filename, FileMetadata fileMetadata, String groupId,
521 String artifactId, String version, String packaging)
523 Model projectModel = new Model();
524 projectModel.setModelVersion("4.0.0");
525 projectModel.setGroupId(groupId);
526 projectModel.setArtifactId(artifactId);
527 projectModel.setVersion(version);
528 projectModel.setPackaging(packaging);
530 StorageAsset pomFile = targetPath.resolve(filename);
531 MavenXpp3Writer writer = new MavenXpp3Writer();
533 try (Writer w = new OutputStreamWriter(pomFile.getWriteStream(true))) {
534 writer.write(w, projectModel);
540 private void fixChecksums(StorageAsset file) {
541 ChecksummedFile checksum = new ChecksummedFile(file.getFilePath());
542 checksum.fixChecksums(algorithms);
545 private void queueRepositoryTask(String repositoryId, StorageAsset localFile) {
546 RepositoryTask task = new RepositoryTask();
547 task.setRepositoryId(repositoryId);
548 task.setResourceFile(localFile);
549 task.setUpdateRelatedArtifacts(true);
550 task.setScanAll(false);
553 scheduler.queueTask(task);
554 } catch (TaskQueueException e) {
555 log.error("Unable to queue repository task to execute consumers on resource file ['{}"
556 + "'].", localFile.getName());
560 private void copyFile(Path sourceFile, StorageAsset targetPath, String targetFilename, boolean fixChecksums)
563 targetPath.resolve(targetFilename).replaceDataFromFile(sourceFile);
566 fixChecksums(targetPath.resolve(targetFilename));
571 * Update artifact level metadata. If it does not exist, create the metadata and fix checksums if necessary.
573 private void updateProjectMetadata(StorageAsset targetPath, Date lastUpdatedTimestamp, String timestamp, int buildNumber,
574 boolean fixChecksums, FileMetadata fileMetadata, String groupId,
575 String artifactId, String version, String packaging)
576 throws RepositoryMetadataException {
577 List<String> availableVersions = new ArrayList<>();
578 String latestVersion = version;
580 StorageAsset projectDir = targetPath.getParent();
581 StorageAsset projectMetadataFile = projectDir.resolve(MetadataTools.MAVEN_METADATA);
583 ArchivaRepositoryMetadata projectMetadata = getMetadata(projectMetadataFile);
585 if (projectMetadataFile.exists()) {
586 availableVersions = projectMetadata.getAvailableVersions();
588 Collections.sort(availableVersions, VersionComparator.getInstance());
590 if (!availableVersions.contains(version)) {
591 availableVersions.add(version);
594 latestVersion = availableVersions.get(availableVersions.size() - 1);
596 availableVersions.add(version);
598 projectMetadata.setGroupId(groupId);
599 projectMetadata.setArtifactId(artifactId);
602 if (projectMetadata.getGroupId() == null) {
603 projectMetadata.setGroupId(groupId);
606 if (projectMetadata.getArtifactId() == null) {
607 projectMetadata.setArtifactId(artifactId);
610 projectMetadata.setLatestVersion(latestVersion);
611 projectMetadata.setLastUpdatedTimestamp(lastUpdatedTimestamp);
612 projectMetadata.setAvailableVersions(availableVersions);
614 if (!VersionUtil.isSnapshot(version)) {
615 projectMetadata.setReleasedVersion(latestVersion);
618 RepositoryMetadataWriter.write(projectMetadata, projectMetadataFile);
621 fixChecksums(projectMetadataFile);
626 * Update version level metadata for snapshot artifacts. If it does not exist, create the metadata and fix checksums
629 private void updateVersionMetadata(ArchivaRepositoryMetadata metadata, StorageAsset metadataFile,
630 Date lastUpdatedTimestamp, String timestamp, int buildNumber,
631 boolean fixChecksums, FileMetadata fileMetadata, String groupId,
632 String artifactId, String version, String packaging)
633 throws RepositoryMetadataException {
634 if (!metadataFile.exists()) {
635 metadata.setGroupId(groupId);
636 metadata.setArtifactId(artifactId);
637 metadata.setVersion(version);
640 if (metadata.getSnapshotVersion() == null) {
641 metadata.setSnapshotVersion(new SnapshotVersion());
644 metadata.getSnapshotVersion().setBuildNumber(buildNumber);
645 metadata.getSnapshotVersion().setTimestamp(timestamp);
646 metadata.setLastUpdatedTimestamp(lastUpdatedTimestamp);
648 RepositoryMetadataWriter.write(metadata, metadataFile);
651 fixChecksums(metadataFile);