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.metadata.model.facets.AuditEvent; 028import org.apache.archiva.checksum.ChecksumAlgorithm; 029import org.apache.archiva.checksum.ChecksummedFile; 030import org.apache.archiva.common.utils.VersionComparator; 031import org.apache.archiva.common.utils.VersionUtil; 032import org.apache.archiva.maven2.metadata.MavenMetadataReader; 033import org.apache.archiva.model.ArchivaRepositoryMetadata; 034import org.apache.archiva.model.ArtifactReference; 035import org.apache.archiva.model.SnapshotVersion; 036import org.apache.archiva.redback.components.taskqueue.TaskQueueException; 037import org.apache.archiva.repository.ManagedRepositoryContent; 038import org.apache.archiva.repository.RepositoryContentFactory; 039import org.apache.archiva.repository.RepositoryException; 040import org.apache.archiva.repository.RepositoryNotFoundException; 041import org.apache.archiva.repository.metadata.MetadataTools; 042import org.apache.archiva.repository.metadata.RepositoryMetadataException; 043import org.apache.archiva.repository.metadata.RepositoryMetadataWriter; 044import org.apache.archiva.rest.api.services.ArchivaRestServiceException; 045import org.apache.archiva.rest.services.AbstractRestService; 046import org.apache.archiva.scheduler.ArchivaTaskScheduler; 047import org.apache.archiva.scheduler.repository.model.RepositoryTask; 048import org.apache.archiva.web.model.FileMetadata; 049import org.apache.archiva.xml.XMLException; 050import org.apache.commons.io.FilenameUtils; 051import org.apache.commons.io.IOUtils; 052import org.apache.commons.lang.BooleanUtils; 053import org.apache.commons.lang.StringEscapeUtils; 054import org.apache.commons.lang.StringUtils; 055import org.apache.commons.lang.SystemUtils; 056import org.apache.cxf.jaxrs.ext.multipart.Attachment; 057import org.apache.cxf.jaxrs.ext.multipart.MultipartBody; 058import org.apache.maven.model.Model; 059import org.apache.maven.model.io.xpp3.MavenXpp3Writer; 060import org.slf4j.Logger; 061import org.slf4j.LoggerFactory; 062import org.springframework.stereotype.Service; 063 064import javax.inject.Inject; 065import javax.inject.Named; 066import javax.servlet.http.HttpServletRequest; 067import javax.ws.rs.core.Context; 068import javax.ws.rs.core.Response; 069import java.io.File; 070import java.io.FileOutputStream; 071import java.io.FileWriter; 072import java.io.IOException; 073import java.net.URLDecoder; 074import java.nio.file.*; 075import java.text.DateFormat; 076import java.text.SimpleDateFormat; 077import java.util.ArrayList; 078import java.util.Calendar; 079import java.util.Collections; 080import java.util.Date; 081import java.util.Iterator; 082import java.util.List; 083import java.util.TimeZone; 084import java.util.concurrent.CopyOnWriteArrayList; 085 086/** 087 * @author Olivier Lamy 088 */ 089@Service("fileUploadService#rest") 090public class DefaultFileUploadService 091 extends AbstractRestService 092 implements FileUploadService 093{ 094 private Logger log = LoggerFactory.getLogger( getClass() ); 095 096 @Context 097 private HttpServletRequest httpServletRequest; 098 099 @Inject 100 private ManagedRepositoryAdmin managedRepositoryAdmin; 101 102 @Inject 103 private RepositoryContentFactory repositoryFactory; 104 105 @Inject 106 private ArchivaAdministration archivaAdministration; 107 108 private ChecksumAlgorithm[] algorithms = new ChecksumAlgorithm[]{ ChecksumAlgorithm.SHA1, ChecksumAlgorithm.MD5 }; 109 110 private final String FS = FileSystems.getDefault().getSeparator(); 111 112 @Inject 113 @Named(value = "archivaTaskScheduler#repository") 114 private ArchivaTaskScheduler scheduler; 115 116 private String getStringValue( MultipartBody multipartBody, String attachmentId ) 117 throws IOException 118 { 119 Attachment attachment = multipartBody.getAttachment( attachmentId ); 120 return attachment == null ? "" : 121 StringUtils.trim(URLDecoder.decode(IOUtils.toString( attachment.getDataHandler().getInputStream() ), "UTF-8")); 122 } 123 124 @Override 125 public FileMetadata post( MultipartBody multipartBody ) 126 throws ArchivaRestServiceException 127 { 128 129 try 130 { 131 132 String classifier = getStringValue( multipartBody, "classifier" ); 133 String packaging = getStringValue( multipartBody, "packaging" ); 134 135 checkParamChars( "classifier", classifier ); 136 checkParamChars( "packaging", packaging); 137 138 // skygo: http header form pomFile was once sending 1 for true and void for false 139 // leading to permanent false value for pomFile if using toBoolean(); use , "1", "" 140 141 boolean pomFile = false; 142 try 143 { 144 pomFile = BooleanUtils.toBoolean( getStringValue( multipartBody, "pomFile" ) ); 145 } 146 catch ( IllegalArgumentException ex ) 147 { 148 ArchivaRestServiceException e = new ArchivaRestServiceException("Bad value for boolean pomFile field.", null); 149 e.setHttpErrorCode(422); 150 e.setFieldName( "pomFile" ); 151 e.setErrorKey("fileupload.malformed.pomFile"); 152 throw e; 153 } 154 155 Attachment file = multipartBody.getAttachment( "files[]" ); 156 157 //Content-Disposition: form-data; name="files[]"; filename="org.apache.karaf.features.command-2.2.2.jar" 158 String fileName = file.getContentDisposition().getParameter( "filename" ); 159 Path fileNamePath = Paths.get(fileName); 160 if (!fileName.equals(fileNamePath.getFileName().toString())) { 161 ArchivaRestServiceException e = new ArchivaRestServiceException("Bad filename in upload content: " + fileName + " - File traversal chars (..|/) are not allowed" 162 , null); 163 e.setHttpErrorCode(422); 164 e.setErrorKey("fileupload.malformed.filename"); 165 throw e; 166 } 167 168 File tmpFile = File.createTempFile( "upload-artifact", ".tmp" ); 169 tmpFile.deleteOnExit(); 170 IOUtils.copy( file.getDataHandler().getInputStream(), new FileOutputStream( tmpFile ) ); 171 FileMetadata fileMetadata = new FileMetadata( fileName, tmpFile.length(), "theurl" ); 172 fileMetadata.setServerFileName( tmpFile.getPath() ); 173 fileMetadata.setClassifier( classifier ); 174 fileMetadata.setDeleteUrl( tmpFile.getName() ); 175 fileMetadata.setPomFile( pomFile ); 176 fileMetadata.setPackaging( packaging ); 177 178 log.info( "uploading file: {}", fileMetadata ); 179 180 List<FileMetadata> fileMetadatas = getSessionFilesList(); 181 182 fileMetadatas.add( fileMetadata ); 183 184 return fileMetadata; 185 } 186 catch ( IOException e ) 187 { 188 throw new ArchivaRestServiceException( e.getMessage(), 189 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e ); 190 } 191 192 } 193 194 /** 195 * FIXME must be per session synchronized not globally 196 * 197 * @return 198 */ 199 protected synchronized List<FileMetadata> getSessionFilesList() 200 { 201 List<FileMetadata> fileMetadatas = 202 (List<FileMetadata>) httpServletRequest.getSession().getAttribute( FILES_SESSION_KEY ); 203 if ( fileMetadatas == null ) 204 { 205 fileMetadatas = new CopyOnWriteArrayList<>(); 206 httpServletRequest.getSession().setAttribute( FILES_SESSION_KEY, fileMetadatas ); 207 } 208 return fileMetadatas; 209 } 210 211 @Override 212 public Boolean deleteFile( String fileName ) 213 throws ArchivaRestServiceException 214 { 215 // we make sure, that there are no other path components in the filename: 216 String checkedFileName = Paths.get(fileName).getFileName().toString(); 217 File file = new File( SystemUtils.getJavaIoTmpDir(), checkedFileName ); 218 log.debug( "delete file:{},exists:{}", file.getPath(), file.exists() ); 219 boolean removed = getSessionFileMetadatas().remove( new FileMetadata( fileName ) ); 220 // try with full name as ui only know the file name 221 if ( !removed ) 222 { 223 removed = getSessionFileMetadatas().remove( new FileMetadata( file.getPath() ) ); 224 } 225 if (removed && file.exists() ) 226 { 227 return file.delete(); 228 } 229 return Boolean.FALSE; 230 } 231 232 @Override 233 public Boolean clearUploadedFiles() 234 throws ArchivaRestServiceException 235 { 236 List<FileMetadata> fileMetadatas = new ArrayList( getSessionFileMetadatas() ); 237 for ( FileMetadata fileMetadata : fileMetadatas ) 238 { 239 deleteFile( new File( fileMetadata.getServerFileName() ).getPath() ); 240 } 241 getSessionFileMetadatas().clear(); 242 return Boolean.TRUE; 243 } 244 245 @Override 246 public List<FileMetadata> getSessionFileMetadatas() 247 throws ArchivaRestServiceException 248 { 249 List<FileMetadata> fileMetadatas = 250 (List<FileMetadata>) httpServletRequest.getSession().getAttribute( FILES_SESSION_KEY ); 251 252 return fileMetadatas == null ? Collections.<FileMetadata>emptyList() : fileMetadatas; 253 } 254 255 private boolean hasValidChars(String checkString) { 256 if (checkString.contains(FS)) { 257 return false; 258 } 259 if (checkString.contains("../")) { 260 return false; 261 } 262 if (checkString.contains("/..")) { 263 return false; 264 } 265 if (checkString.contains("<")) { 266 return false; 267 } 268 if (checkString.contains(">")) { 269 return false; 270 } 271 if (checkString.contains("&")) { 272 return false; 273 } 274 return true; 275 } 276 277 private void checkParamChars(String param, String value) throws ArchivaRestServiceException { 278 if (!hasValidChars(value)) { 279 ArchivaRestServiceException e = new ArchivaRestServiceException("Bad characters in " + param, null); 280 e.setHttpErrorCode(422); 281 e.setErrorKey("fileupload.malformed.param"); 282 e.setFieldName(param); 283 throw e; 284 } 285 } 286 287 @Override 288 public Boolean save( String repositoryId, String groupId, String artifactId, String version, String packaging, 289 boolean generatePom ) 290 throws ArchivaRestServiceException 291 { 292 repositoryId = StringEscapeUtils.escapeHtml( StringUtils.trim( repositoryId ) ); 293 groupId = StringEscapeUtils.escapeHtml( StringUtils.trim( groupId ) ); 294 artifactId = StringEscapeUtils.escapeHtml( StringUtils.trim( artifactId ) ); 295 version = StringEscapeUtils.escapeHtml( StringUtils.trim( version ) ); 296 packaging = StringEscapeUtils.escapeHtml( StringUtils.trim( packaging ) ); 297 298 checkParamChars("repositoryId", repositoryId); 299 checkParamChars("groupId", groupId); 300 checkParamChars("artifactId", artifactId); 301 checkParamChars( "version", version); 302 checkParamChars("packaging", packaging); 303 304 305 List<FileMetadata> fileMetadatas = getSessionFilesList(); 306 if ( fileMetadatas == null || fileMetadatas.isEmpty() ) 307 { 308 return Boolean.FALSE; 309 } 310 311 try 312 { 313 ManagedRepository managedRepository = managedRepositoryAdmin.getManagedRepository( repositoryId ); 314 315 if ( managedRepository == null ) 316 { 317 // TODO i18n ? 318 throw new ArchivaRestServiceException( "Cannot find managed repository with id " + repositoryId, 319 Response.Status.BAD_REQUEST.getStatusCode(), null ); 320 } 321 322 if ( VersionUtil.isSnapshot( version ) && !managedRepository.isSnapshots() ) 323 { 324 // TODO i18n ? 325 throw new ArchivaRestServiceException( 326 "Managed repository with id " + repositoryId + " do not accept snapshots", 327 Response.Status.BAD_REQUEST.getStatusCode(), null ); 328 } 329 } 330 catch ( RepositoryAdminException e ) 331 { 332 throw new ArchivaRestServiceException( e.getMessage(), 333 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e ); 334 } 335 336 // get from the session file with groupId/artifactId 337 338 Iterable<FileMetadata> filesToAdd = Iterables.filter( fileMetadatas, new Predicate<FileMetadata>() 339 { 340 public boolean apply( FileMetadata fileMetadata ) 341 { 342 return fileMetadata != null && !fileMetadata.isPomFile(); 343 } 344 } ); 345 Iterator<FileMetadata> iterator = filesToAdd.iterator(); 346 boolean pomGenerated = false; 347 while ( iterator.hasNext() ) 348 { 349 FileMetadata fileMetadata = iterator.next(); 350 log.debug( "fileToAdd: {}", fileMetadata ); 351 saveFile( repositoryId, fileMetadata, generatePom && !pomGenerated, groupId, artifactId, version, 352 packaging ); 353 pomGenerated = true; 354 deleteFile( fileMetadata.getServerFileName() ); 355 } 356 357 filesToAdd = Iterables.filter( fileMetadatas, new Predicate<FileMetadata>() 358 { 359 @Override 360 public boolean apply( FileMetadata fileMetadata ) 361 { 362 return fileMetadata != null && fileMetadata.isPomFile(); 363 } 364 } ); 365 366 iterator = filesToAdd.iterator(); 367 while ( iterator.hasNext() ) 368 { 369 FileMetadata fileMetadata = iterator.next(); 370 log.debug( "fileToAdd: {}", fileMetadata ); 371 savePomFile( repositoryId, fileMetadata, groupId, artifactId, version, packaging ); 372 deleteFile( fileMetadata.getServerFileName() ); 373 } 374 375 return Boolean.TRUE; 376 } 377 378 protected void savePomFile( String repositoryId, FileMetadata fileMetadata, String groupId, String artifactId, 379 String version, String packaging ) 380 throws ArchivaRestServiceException 381 { 382 383 try 384 { 385 boolean fixChecksums = 386 !( archivaAdministration.getKnownContentConsumers().contains( "create-missing-checksums" ) ); 387 388 ManagedRepository repoConfig = managedRepositoryAdmin.getManagedRepository( repositoryId ); 389 390 repositoryId = StringEscapeUtils.escapeHtml( StringUtils.trim( repositoryId ) ); 391 groupId = StringEscapeUtils.escapeHtml( StringUtils.trim( groupId ) ); 392 artifactId = StringEscapeUtils.escapeHtml( StringUtils.trim( artifactId ) ); 393 version = StringEscapeUtils.escapeHtml( StringUtils.trim( version ) ); 394 packaging = StringEscapeUtils.escapeHtml( StringUtils.trim( packaging ) ); 395 396 ArtifactReference artifactReference = new ArtifactReference(); 397 artifactReference.setArtifactId( artifactId ); 398 artifactReference.setGroupId( groupId ); 399 artifactReference.setVersion( version ); 400 artifactReference.setClassifier( fileMetadata.getClassifier() ); 401 artifactReference.setType( packaging ); 402 403 ManagedRepositoryContent repository = repositoryFactory.getManagedRepositoryContent( repositoryId ); 404 405 String artifactPath = repository.toPath( artifactReference ); 406 407 int lastIndex = artifactPath.lastIndexOf( '/' ); 408 409 String path = artifactPath.substring( 0, lastIndex ); 410 File targetPath = new File( repoConfig.getLocation(), path ); 411 412 String pomFilename = artifactPath.substring( lastIndex + 1 ); 413 if ( StringUtils.isNotEmpty( fileMetadata.getClassifier() ) ) 414 { 415 pomFilename = StringUtils.remove( pomFilename, "-" + fileMetadata.getClassifier() ); 416 } 417 pomFilename = FilenameUtils.removeExtension( pomFilename ) + ".pom"; 418 419 copyFile( new File( fileMetadata.getServerFileName() ), targetPath, pomFilename, fixChecksums ); 420 triggerAuditEvent( repoConfig.getId(), path + "/" + pomFilename, AuditEvent.UPLOAD_FILE ); 421 queueRepositoryTask( repoConfig.getId(), new File( targetPath, pomFilename ) ); 422 } 423 catch ( IOException ie ) 424 { 425 throw new ArchivaRestServiceException( "Error encountered while uploading pom file: " + ie.getMessage(), 426 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), ie ); 427 } 428 catch ( RepositoryException rep ) 429 { 430 throw new ArchivaRestServiceException( "Repository exception: " + rep.getMessage(), 431 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), rep ); 432 } 433 catch ( RepositoryAdminException e ) 434 { 435 throw new ArchivaRestServiceException( "RepositoryAdmin exception: " + e.getMessage(), 436 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e ); 437 } 438 } 439 440 protected void saveFile( String repositoryId, FileMetadata fileMetadata, boolean generatePom, String groupId, 441 String artifactId, String version, String packaging ) 442 throws ArchivaRestServiceException 443 { 444 try 445 { 446 447 ManagedRepository repoConfig = managedRepositoryAdmin.getManagedRepository( repositoryId ); 448 449 ArtifactReference artifactReference = new ArtifactReference(); 450 artifactReference.setArtifactId( artifactId ); 451 artifactReference.setGroupId( groupId ); 452 artifactReference.setVersion( version ); 453 artifactReference.setClassifier( fileMetadata.getClassifier() ); 454 artifactReference.setType( 455 StringUtils.isEmpty( fileMetadata.getPackaging() ) ? packaging : fileMetadata.getPackaging() ); 456 457 ManagedRepositoryContent repository = repositoryFactory.getManagedRepositoryContent( repositoryId ); 458 459 String artifactPath = repository.toPath( artifactReference ); 460 461 int lastIndex = artifactPath.lastIndexOf( '/' ); 462 463 String path = artifactPath.substring( 0, lastIndex ); 464 File targetPath = new File( repoConfig.getLocation(), path ); 465 466 log.debug( "artifactPath: {} found targetPath: {}", artifactPath, targetPath ); 467 468 Date lastUpdatedTimestamp = Calendar.getInstance().getTime(); 469 int newBuildNumber = -1; 470 String timestamp = null; 471 472 File versionMetadataFile = new File( targetPath, MetadataTools.MAVEN_METADATA ); 473 ArchivaRepositoryMetadata versionMetadata = getMetadata( versionMetadataFile ); 474 475 if ( VersionUtil.isSnapshot( version ) ) 476 { 477 TimeZone timezone = TimeZone.getTimeZone( "UTC" ); 478 DateFormat fmt = new SimpleDateFormat( "yyyyMMdd.HHmmss" ); 479 fmt.setTimeZone( timezone ); 480 timestamp = fmt.format( lastUpdatedTimestamp ); 481 if ( versionMetadata.getSnapshotVersion() != null ) 482 { 483 newBuildNumber = versionMetadata.getSnapshotVersion().getBuildNumber() + 1; 484 } 485 else 486 { 487 newBuildNumber = 1; 488 } 489 } 490 491 if ( !targetPath.exists() ) 492 { 493 targetPath.mkdirs(); 494 } 495 496 String filename = artifactPath.substring( lastIndex + 1 ); 497 if ( VersionUtil.isSnapshot( version ) ) 498 { 499 filename = filename.replaceAll( VersionUtil.SNAPSHOT, timestamp + "-" + newBuildNumber ); 500 } 501 502 boolean fixChecksums = 503 !( archivaAdministration.getKnownContentConsumers().contains( "create-missing-checksums" ) ); 504 505 try 506 { 507 File targetFile = new File( targetPath, filename ); 508 if ( targetFile.exists() && !VersionUtil.isSnapshot( version ) && repoConfig.isBlockRedeployments() ) 509 { 510 throw new ArchivaRestServiceException( 511 "Overwriting released artifacts in repository '" + repoConfig.getId() + "' is not allowed.", 512 Response.Status.BAD_REQUEST.getStatusCode(), null ); 513 } 514 else 515 { 516 copyFile( new File( fileMetadata.getServerFileName() ), targetPath, filename, fixChecksums ); 517 triggerAuditEvent( repository.getId(), path + "/" + filename, AuditEvent.UPLOAD_FILE ); 518 queueRepositoryTask( repository.getId(), targetFile ); 519 } 520 } 521 catch ( IOException ie ) 522 { 523 log.error( "IOException copying file: {}", ie.getMessage(), ie ); 524 throw new ArchivaRestServiceException( 525 "Overwriting released artifacts in repository '" + repoConfig.getId() + "' is not allowed.", 526 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), ie ); 527 } 528 529 if ( generatePom ) 530 { 531 String pomFilename = filename; 532 if ( StringUtils.isNotEmpty( fileMetadata.getClassifier() ) ) 533 { 534 pomFilename = StringUtils.remove( pomFilename, "-" + fileMetadata.getClassifier() ); 535 } 536 pomFilename = FilenameUtils.removeExtension( pomFilename ) + ".pom"; 537 538 try 539 { 540 File generatedPomFile = 541 createPom( targetPath, pomFilename, fileMetadata, groupId, artifactId, version, packaging ); 542 triggerAuditEvent( repoConfig.getId(), path + "/" + pomFilename, AuditEvent.UPLOAD_FILE ); 543 if ( fixChecksums ) 544 { 545 fixChecksums( generatedPomFile ); 546 } 547 queueRepositoryTask( repoConfig.getId(), generatedPomFile ); 548 } 549 catch ( IOException ie ) 550 { 551 throw new ArchivaRestServiceException( 552 "Error encountered while writing pom file: " + ie.getMessage(), 553 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), ie ); 554 } 555 } 556 557 // explicitly update only if metadata-updater consumer is not enabled! 558 if ( !archivaAdministration.getKnownContentConsumers().contains( "metadata-updater" ) ) 559 { 560 updateProjectMetadata( targetPath.getAbsolutePath(), lastUpdatedTimestamp, timestamp, newBuildNumber, 561 fixChecksums, fileMetadata, groupId, artifactId, version, packaging ); 562 563 if ( VersionUtil.isSnapshot( version ) ) 564 { 565 updateVersionMetadata( versionMetadata, versionMetadataFile, lastUpdatedTimestamp, timestamp, 566 newBuildNumber, fixChecksums, fileMetadata, groupId, artifactId, version, 567 packaging ); 568 } 569 } 570 } 571 catch ( RepositoryNotFoundException re ) 572 { 573 throw new ArchivaRestServiceException( "Target repository cannot be found: " + re.getMessage(), 574 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), re ); 575 } 576 catch ( RepositoryException rep ) 577 { 578 throw new ArchivaRestServiceException( "Repository exception: " + rep.getMessage(), 579 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), rep ); 580 } 581 catch ( RepositoryAdminException e ) 582 { 583 throw new ArchivaRestServiceException( "RepositoryAdmin exception: " + e.getMessage(), 584 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e ); 585 } 586 } 587 588 private ArchivaRepositoryMetadata getMetadata( File metadataFile ) 589 throws RepositoryMetadataException 590 { 591 ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata(); 592 if ( metadataFile.exists() ) 593 { 594 try 595 { 596 metadata = MavenMetadataReader.read( metadataFile ); 597 } 598 catch ( XMLException e ) 599 { 600 throw new RepositoryMetadataException( e.getMessage(), e ); 601 } 602 } 603 return metadata; 604 } 605 606 private File createPom( File targetPath, String filename, FileMetadata fileMetadata, String groupId, 607 String artifactId, String version, String packaging ) 608 throws IOException 609 { 610 Model projectModel = new Model(); 611 projectModel.setModelVersion( "4.0.0" ); 612 projectModel.setGroupId( groupId ); 613 projectModel.setArtifactId( artifactId ); 614 projectModel.setVersion( version ); 615 projectModel.setPackaging( packaging ); 616 617 File pomFile = new File( targetPath, filename ); 618 MavenXpp3Writer writer = new MavenXpp3Writer(); 619 620 try (FileWriter w = new FileWriter( pomFile )) 621 { 622 writer.write( w, projectModel ); 623 } 624 625 return pomFile; 626 } 627 628 private void fixChecksums( File file ) 629 { 630 ChecksummedFile checksum = new ChecksummedFile( file ); 631 checksum.fixChecksums( algorithms ); 632 } 633 634 private void queueRepositoryTask( String repositoryId, File localFile ) 635 { 636 RepositoryTask task = new RepositoryTask(); 637 task.setRepositoryId( repositoryId ); 638 task.setResourceFile( localFile ); 639 task.setUpdateRelatedArtifacts( true ); 640 task.setScanAll( false ); 641 642 try 643 { 644 scheduler.queueTask( task ); 645 } 646 catch ( TaskQueueException e ) 647 { 648 log.error( "Unable to queue repository task to execute consumers on resource file ['" + localFile.getName() 649 + "']." ); 650 } 651 } 652 653 private void copyFile( File sourceFile, File targetPath, String targetFilename, boolean fixChecksums ) 654 throws IOException 655 { 656 657 Files.copy( sourceFile.toPath(), new File( targetPath, targetFilename ).toPath(), StandardCopyOption.REPLACE_EXISTING, 658 StandardCopyOption.COPY_ATTRIBUTES ); 659 660 if ( fixChecksums ) 661 { 662 fixChecksums( new File( targetPath, targetFilename ) ); 663 } 664 } 665 666 /** 667 * Update artifact level metadata. If it does not exist, create the metadata and fix checksums if necessary. 668 */ 669 private void updateProjectMetadata( String targetPath, Date lastUpdatedTimestamp, String timestamp, int buildNumber, 670 boolean fixChecksums, FileMetadata fileMetadata, String groupId, 671 String artifactId, String version, String packaging ) 672 throws RepositoryMetadataException 673 { 674 List<String> availableVersions = new ArrayList<>(); 675 String latestVersion = version; 676 677 File projectDir = new File( targetPath ).getParentFile(); 678 File projectMetadataFile = new File( projectDir, MetadataTools.MAVEN_METADATA ); 679 680 ArchivaRepositoryMetadata projectMetadata = getMetadata( projectMetadataFile ); 681 682 if ( projectMetadataFile.exists() ) 683 { 684 availableVersions = projectMetadata.getAvailableVersions(); 685 686 Collections.sort( availableVersions, VersionComparator.getInstance() ); 687 688 if ( !availableVersions.contains( version ) ) 689 { 690 availableVersions.add( version ); 691 } 692 693 latestVersion = availableVersions.get( availableVersions.size() - 1 ); 694 } 695 else 696 { 697 availableVersions.add( version ); 698 699 projectMetadata.setGroupId( groupId ); 700 projectMetadata.setArtifactId( artifactId ); 701 } 702 703 if ( projectMetadata.getGroupId() == null ) 704 { 705 projectMetadata.setGroupId( groupId ); 706 } 707 708 if ( projectMetadata.getArtifactId() == null ) 709 { 710 projectMetadata.setArtifactId( artifactId ); 711 } 712 713 projectMetadata.setLatestVersion( latestVersion ); 714 projectMetadata.setLastUpdatedTimestamp( lastUpdatedTimestamp ); 715 projectMetadata.setAvailableVersions( availableVersions ); 716 717 if ( !VersionUtil.isSnapshot( version ) ) 718 { 719 projectMetadata.setReleasedVersion( latestVersion ); 720 } 721 722 RepositoryMetadataWriter.write( projectMetadata, projectMetadataFile ); 723 724 if ( fixChecksums ) 725 { 726 fixChecksums( projectMetadataFile ); 727 } 728 } 729 730 /** 731 * Update version level metadata for snapshot artifacts. If it does not exist, create the metadata and fix checksums 732 * if necessary. 733 */ 734 private void updateVersionMetadata( ArchivaRepositoryMetadata metadata, File metadataFile, 735 Date lastUpdatedTimestamp, String timestamp, int buildNumber, 736 boolean fixChecksums, FileMetadata fileMetadata, String groupId, 737 String artifactId, String version, String packaging ) 738 throws RepositoryMetadataException 739 { 740 if ( !metadataFile.exists() ) 741 { 742 metadata.setGroupId( groupId ); 743 metadata.setArtifactId( artifactId ); 744 metadata.setVersion( version ); 745 } 746 747 if ( metadata.getSnapshotVersion() == null ) 748 { 749 metadata.setSnapshotVersion( new SnapshotVersion() ); 750 } 751 752 metadata.getSnapshotVersion().setBuildNumber( buildNumber ); 753 metadata.getSnapshotVersion().setTimestamp( timestamp ); 754 metadata.setLastUpdatedTimestamp( lastUpdatedTimestamp ); 755 756 RepositoryMetadataWriter.write( metadata, metadataFile ); 757 758 if ( fixChecksums ) 759 { 760 fixChecksums( metadataFile ); 761 } 762 } 763 764 765}