001package org.apache.archiva.web.api; 002/* 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, 014 * software distributed under the License is distributed on an 015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 016 * KIND, either express or implied. See the License for the 017 * specific language governing permissions and limitations 018 * under the License. 019 */ 020 021import com.google.common.base.Predicate; 022import com.google.common.collect.Iterables; 023import org.apache.archiva.admin.model.RepositoryAdminException; 024import org.apache.archiva.admin.model.admin.ArchivaAdministration; 025import org.apache.archiva.admin.model.beans.ManagedRepository; 026import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin; 027import org.apache.archiva.checksum.ChecksumAlgorithm; 028import org.apache.archiva.checksum.ChecksumUtil; 029import org.apache.archiva.checksum.ChecksummedFile; 030import org.apache.archiva.common.utils.VersionComparator; 031import org.apache.archiva.common.utils.VersionUtil; 032import org.apache.archiva.configuration.ArchivaConfiguration; 033import org.apache.archiva.maven2.metadata.MavenMetadataReader; 034import org.apache.archiva.metadata.model.facets.AuditEvent; 035import org.apache.archiva.model.ArchivaRepositoryMetadata; 036import org.apache.archiva.model.ArtifactReference; 037import org.apache.archiva.model.SnapshotVersion; 038import org.apache.archiva.components.taskqueue.TaskQueueException; 039import org.apache.archiva.repository.RepositoryException; 040import org.apache.archiva.repository.RepositoryNotFoundException; 041import org.apache.archiva.repository.content.base.ArtifactUtil; 042import org.apache.archiva.repository.metadata.base.MetadataTools; 043import org.apache.archiva.repository.metadata.RepositoryMetadataException; 044import org.apache.archiva.repository.metadata.base.RepositoryMetadataWriter; 045import org.apache.archiva.repository.storage.StorageAsset; 046import org.apache.archiva.rest.api.services.ArchivaRestServiceException; 047import org.apache.archiva.rest.services.AbstractRestService; 048import org.apache.archiva.scheduler.ArchivaTaskScheduler; 049import org.apache.archiva.scheduler.repository.model.RepositoryTask; 050import org.apache.archiva.web.model.FileMetadata; 051import org.apache.archiva.xml.XMLException; 052import org.apache.commons.io.FilenameUtils; 053import org.apache.commons.io.IOUtils; 054import org.apache.commons.lang3.BooleanUtils; 055import org.apache.commons.lang3.StringUtils; 056import org.apache.commons.lang3.SystemUtils; 057import org.apache.cxf.jaxrs.ext.multipart.Attachment; 058import org.apache.cxf.jaxrs.ext.multipart.MultipartBody; 059import org.apache.maven.model.Model; 060import org.apache.maven.model.io.xpp3.MavenXpp3Writer; 061import org.slf4j.Logger; 062import org.slf4j.LoggerFactory; 063import org.springframework.stereotype.Service; 064 065import javax.annotation.PostConstruct; 066import javax.inject.Inject; 067import javax.inject.Named; 068import javax.servlet.http.HttpServletRequest; 069import javax.servlet.http.HttpSession; 070import javax.ws.rs.core.Context; 071import javax.ws.rs.core.Response; 072import java.io.*; 073import java.net.URLDecoder; 074import java.nio.file.*; 075import java.text.DateFormat; 076import java.text.SimpleDateFormat; 077import java.util.*; 078import java.util.concurrent.CopyOnWriteArrayList; 079 080/** 081 * 082 * Service for uploading files to the repository. 083 * 084 * @author Olivier Lamy 085 * @author Martin Stockhammer 086 */ 087@Service("fileUploadService#rest") 088public class DefaultFileUploadService 089 extends AbstractRestService 090 implements FileUploadService { 091 private Logger log = LoggerFactory.getLogger(getClass()); 092 093 @Context 094 private HttpServletRequest httpServletRequest; 095 096 @Inject 097 private ManagedRepositoryAdmin managedRepositoryAdmin; 098 099 @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 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 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 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 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 = 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 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 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 ChecksummedFile checksum = new ChecksummedFile(file.getFilePath()); 561 checksum.fixChecksums(algorithms); 562 } 563 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); 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}