1 package org.apache.archiva.rest.services;
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
22 import org.apache.archiva.admin.model.RepositoryAdminException;
23 import org.apache.archiva.admin.model.admin.ArchivaAdministration;
24 import org.apache.archiva.checksum.ChecksumAlgorithm;
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.maven2.model.Artifact;
29 import org.apache.archiva.metadata.model.ArtifactMetadata;
30 import org.apache.archiva.metadata.model.facets.AuditEvent;
31 import org.apache.archiva.metadata.maven.model.MavenArtifactFacet;
32 import org.apache.archiva.metadata.repository.*;
33 import org.apache.archiva.model.ArchivaRepositoryMetadata;
34 import org.apache.archiva.model.ArtifactReference;
35 import org.apache.archiva.model.VersionedReference;
36 import org.apache.archiva.redback.authentication.AuthenticationResult;
37 import org.apache.archiva.redback.authorization.AuthorizationException;
38 import org.apache.archiva.components.cache.Cache;
39 import org.apache.archiva.components.taskqueue.TaskQueueException;
40 import org.apache.archiva.redback.system.DefaultSecuritySession;
41 import org.apache.archiva.redback.system.SecuritySession;
42 import org.apache.archiva.redback.system.SecuritySystem;
43 import org.apache.archiva.redback.users.User;
44 import org.apache.archiva.redback.users.UserManagerException;
45 import org.apache.archiva.redback.users.UserNotFoundException;
46 import org.apache.archiva.repository.ContentNotFoundException;
47 import org.apache.archiva.repository.ManagedRepositoryContent;
48 import org.apache.archiva.repository.LayoutException;
49 import org.apache.archiva.repository.ManagedRepository;
50 import org.apache.archiva.repository.BaseRepositoryContentLayout;
51 import org.apache.archiva.repository.RepositoryException;
52 import org.apache.archiva.repository.RepositoryNotFoundException;
53 import org.apache.archiva.repository.RepositoryRegistry;
54 import org.apache.archiva.repository.RepositoryType;
55 import org.apache.archiva.repository.content.ContentItem;
56 import org.apache.archiva.repository.content.ItemNotFoundException;
57 import org.apache.archiva.repository.content.Version;
58 import org.apache.archiva.repository.content.base.ArchivaItemSelector;
59 import org.apache.archiva.repository.storage.fs.FsStorageUtil;
60 import org.apache.archiva.repository.storage.RepositoryStorage;
61 import org.apache.archiva.repository.storage.StorageAsset;
62 import org.apache.archiva.metadata.audit.RepositoryListener;
63 import org.apache.archiva.repository.metadata.base.MetadataTools;
64 import org.apache.archiva.repository.metadata.RepositoryMetadataException;
65 import org.apache.archiva.repository.metadata.base.RepositoryMetadataWriter;
66 import org.apache.archiva.repository.scanner.RepositoryScanStatistics;
67 import org.apache.archiva.repository.scanner.RepositoryScanner;
68 import org.apache.archiva.repository.scanner.RepositoryScannerException;
69 import org.apache.archiva.repository.scanner.RepositoryScannerInstance;
70 import org.apache.archiva.rest.api.model.ArtifactTransferRequest;
71 import org.apache.archiva.rest.api.model.StringList;
72 import org.apache.archiva.rest.api.services.ArchivaRestServiceException;
73 import org.apache.archiva.rest.api.services.RepositoriesService;
74 import org.apache.archiva.scheduler.ArchivaTaskScheduler;
75 import org.apache.archiva.scheduler.indexing.maven.ArchivaIndexingTaskExecutor;
76 import org.apache.archiva.scheduler.indexing.ArtifactIndexingTask;
77 import org.apache.archiva.scheduler.indexing.DownloadRemoteIndexException;
78 import org.apache.archiva.scheduler.indexing.DownloadRemoteIndexScheduler;
79 import org.apache.archiva.scheduler.repository.model.RepositoryTask;
80 import org.apache.archiva.security.ArchivaSecurityException;
81 import org.apache.archiva.security.common.ArchivaRoleConstants;
82 import org.apache.commons.io.FilenameUtils;
83 import org.apache.commons.lang3.StringUtils;
84 import org.slf4j.Logger;
85 import org.slf4j.LoggerFactory;
86 import org.springframework.beans.factory.annotation.Autowired;
87 import org.springframework.stereotype.Service;
89 import javax.inject.Inject;
90 import javax.inject.Named;
91 import javax.ws.rs.core.Response;
92 import java.io.IOException;
93 import java.io.OutputStreamWriter;
94 import java.nio.file.Path;
95 import java.text.DateFormat;
96 import java.text.SimpleDateFormat;
97 import java.util.ArrayList;
98 import java.util.Arrays;
99 import java.util.Calendar;
100 import java.util.Collection;
101 import java.util.Collections;
102 import java.util.Date;
103 import java.util.List;
104 import java.util.TimeZone;
107 * @author Olivier Lamy
110 @Service("repositoriesService#rest")
111 public class DefaultRepositoriesService
112 extends AbstractRestService
113 implements RepositoriesService
115 private Logger log = LoggerFactory.getLogger( getClass() );
118 @Named(value = "taskExecutor#indexing")
119 private ArchivaIndexingTaskExecutor archivaIndexingTaskExecutor;
122 private RepositoryRegistry repositoryRegistry;
125 private SecuritySystem securitySystem;
128 @Named(value = "archivaTaskScheduler#repository")
129 private ArchivaTaskScheduler<RepositoryTask> scheduler;
132 private DownloadRemoteIndexScheduler downloadRemoteIndexScheduler;
135 @Named(value = "repositorySessionFactory")
136 protected RepositorySessionFactory repositorySessionFactory;
139 @Autowired(required = false)
140 protected List<RepositoryListener> listeners = new ArrayList<RepositoryListener>();
143 private RepositoryScanner repoScanner;
146 * Cache used for namespaces
149 @Named(value = "cache#namespaces")
150 private Cache<String, Collection<String>> namespacesCache;
152 private List<ChecksumAlgorithm> algorithms = Arrays.asList(ChecksumAlgorithm.SHA256, ChecksumAlgorithm.SHA1, ChecksumAlgorithm.MD5 );
155 public Boolean scanRepository( String repositoryId, boolean fullScan )
157 return doScanRepository( repositoryId, fullScan );
161 public Boolean alreadyScanning( String repositoryId )
163 // check queue first to make sure it doesn't get dequeued between calls
164 if ( repositoryTaskScheduler.isProcessingRepositoryTask( repositoryId ) )
168 for ( RepositoryScannerInstance scan : repoScanner.getInProgressScans() )
170 if ( scan.getRepository().getId().equals( repositoryId ) )
179 public Boolean removeScanningTaskFromQueue( String repositoryId )
181 RepositoryTask task = new RepositoryTask();
182 task.setRepositoryId( repositoryId );
185 return repositoryTaskScheduler.unQueueTask( task );
187 catch ( TaskQueueException e )
189 log.error( "failed to unschedule scanning of repo with id {}", repositoryId, e );
194 private ManagedRepositoryContent getManagedRepositoryContent( String id) throws RepositoryException
196 org.apache.archiva.repository.ManagedRepository repo = repositoryRegistry.getManagedRepository( id );
198 throw new RepositoryException( "Repository not found "+id );
200 return repo.getContent();
204 public Boolean scanRepositoryNow( String repositoryId, boolean fullScan )
205 throws ArchivaRestServiceException
211 org.apache.archiva.repository.ManagedRepository repository = repositoryRegistry.getManagedRepository( repositoryId );
214 ArtifactIndexingTask task =
215 new ArtifactIndexingTask( repository, null, ArtifactIndexingTask.Action.FINISH, repository.getIndexingContext() );
217 task.setExecuteOnEntireRepo( true );
218 task.setOnlyUpdate( !fullScan );
220 archivaIndexingTaskExecutor.executeTask( task );
222 scheduler.queueTask( new RepositoryTask( repositoryId, fullScan ) );
226 catch ( Exception e )
228 log.error( e.getMessage(), e );
229 throw new ArchivaRestServiceException( e.getMessage(), e );
234 public Boolean scheduleDownloadRemoteIndex( String repositoryId, boolean now, boolean fullDownload )
235 throws ArchivaRestServiceException
239 downloadRemoteIndexScheduler.scheduleDownloadRemote( repositoryId, now, fullDownload );
241 catch ( DownloadRemoteIndexException e )
243 log.error( e.getMessage(), e );
244 throw new ArchivaRestServiceException( e.getMessage(), e );
250 public Boolean copyArtifact( ArtifactTransferRequest artifactTransferRequest )
251 throws ArchivaRestServiceException
254 String userName = getAuditInformation().getUser().getUsername();
255 if ( StringUtils.isBlank( userName ) )
257 throw new ArchivaRestServiceException( "copyArtifact call: userName not found", null );
260 if ( StringUtils.isBlank( artifactTransferRequest.getRepositoryId() ) )
262 throw new ArchivaRestServiceException( "copyArtifact call: sourceRepositoryId cannot be null", null );
265 if ( StringUtils.isBlank( artifactTransferRequest.getTargetRepositoryId() ) )
267 throw new ArchivaRestServiceException( "copyArtifact call: targetRepositoryId cannot be null", null );
270 ManagedRepository source = null;
271 source = repositoryRegistry.getManagedRepository( artifactTransferRequest.getRepositoryId() );
273 if ( source == null )
275 throw new ArchivaRestServiceException(
276 "cannot find repository with id " + artifactTransferRequest.getRepositoryId(), null );
279 ManagedRepository target = null;
280 target = repositoryRegistry.getManagedRepository( artifactTransferRequest.getTargetRepositoryId() );
282 if ( target == null )
284 throw new ArchivaRestServiceException(
285 "cannot find repository with id " + artifactTransferRequest.getTargetRepositoryId(), null );
288 if ( StringUtils.isBlank( artifactTransferRequest.getGroupId() ) )
290 throw new ArchivaRestServiceException( "groupId is mandatory", null );
293 if ( StringUtils.isBlank( artifactTransferRequest.getArtifactId() ) )
295 throw new ArchivaRestServiceException( "artifactId is mandatory", null );
298 if ( StringUtils.isBlank( artifactTransferRequest.getVersion() ) )
300 throw new ArchivaRestServiceException( "version is mandatory", null );
303 if ( VersionUtil.isSnapshot( artifactTransferRequest.getVersion() ) )
305 throw new ArchivaRestServiceException( "copy of SNAPSHOT not supported", null );
308 // end check parameters
313 user = securitySystem.getUserManager().findUser( userName );
315 catch ( UserNotFoundException e )
317 throw new ArchivaRestServiceException( "user " + userName + " not found", e );
319 catch ( UserManagerException e )
321 throw new ArchivaRestServiceException( "ArchivaRestServiceException:" + e.getMessage(), e );
324 // check karma on source : read
325 AuthenticationResult authn = new AuthenticationResult( true, userName, null );
326 SecuritySession securitySession = new DefaultSecuritySession( authn, user );
330 securitySystem.isAuthorized( securitySession, ArchivaRoleConstants.OPERATION_REPOSITORY_ACCESS,
331 artifactTransferRequest.getRepositoryId() );
334 throw new ArchivaRestServiceException(
335 "not authorized to access repo:" + artifactTransferRequest.getRepositoryId(), null );
338 catch ( AuthorizationException e )
340 log.error( "error reading permission: {}", e.getMessage(), e );
341 throw new ArchivaRestServiceException( e.getMessage(), e );
344 // check karma on target: write
348 securitySystem.isAuthorized( securitySession, ArchivaRoleConstants.OPERATION_REPOSITORY_UPLOAD,
349 artifactTransferRequest.getTargetRepositoryId() );
352 throw new ArchivaRestServiceException(
353 "not authorized to write to repo:" + artifactTransferRequest.getTargetRepositoryId(), null );
356 catch ( AuthorizationException e )
358 log.error( "error reading permission: {}", e.getMessage(), e );
359 throw new ArchivaRestServiceException( e.getMessage(), e );
362 // sounds good we can continue !
364 ArtifactReference artifactReference = new ArtifactReference();
365 artifactReference.setArtifactId( artifactTransferRequest.getArtifactId() );
366 artifactReference.setGroupId( artifactTransferRequest.getGroupId() );
367 artifactReference.setVersion( artifactTransferRequest.getVersion() );
368 artifactReference.setClassifier( artifactTransferRequest.getClassifier() );
369 String packaging = StringUtils.trim( artifactTransferRequest.getPackaging() );
370 artifactReference.setType( StringUtils.isEmpty( packaging ) ? "jar" : packaging );
375 ManagedRepositoryContent sourceRepository =
376 getManagedRepositoryContent( artifactTransferRequest.getRepositoryId() );
377 BaseRepositoryContentLayout layout = sourceRepository.getLayout( BaseRepositoryContentLayout.class );
378 String artifactSourcePath = sourceRepository.toPath( artifactReference );
380 if ( StringUtils.isEmpty( artifactSourcePath ) )
382 log.error( "cannot find artifact {}", artifactTransferRequest );
383 throw new ArchivaRestServiceException( "cannot find artifact " + artifactTransferRequest.toString(),
387 StorageAsset artifactFile = source.getAsset( artifactSourcePath );
389 if ( !artifactFile.exists() )
391 log.error( "cannot find artifact {}", artifactTransferRequest );
392 throw new ArchivaRestServiceException( "cannot find artifact " + artifactTransferRequest.toString(),
396 ManagedRepositoryContent targetRepository =
397 getManagedRepositoryContent( artifactTransferRequest.getTargetRepositoryId() );
399 String artifactPath = sourceRepository.toPath( artifactReference );
401 int lastIndex = artifactPath.lastIndexOf( '/' );
403 String path = artifactPath.substring( 0, lastIndex );
404 StorageAsset targetDir = target.getAsset( path );
406 Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
407 int newBuildNumber = 1;
408 String timestamp = null;
410 StorageAsset versionMetadataFile = target.getAsset(path + "/" + MetadataTools.MAVEN_METADATA );
411 /* unused */ getMetadata( targetRepository.getRepository().getType(), versionMetadataFile );
413 if ( !targetDir.exists() )
415 targetDir = target.addAsset(targetDir.getPath(), true);
419 String filename = artifactPath.substring( lastIndex + 1 );
421 boolean fixChecksums =
422 !( archivaAdministration.getKnownContentConsumers().contains( "create-missing-checksums" ) );
424 StorageAsset targetFile = target.getAsset(targetDir.getPath() + "/" + filename );
425 if ( targetFile.exists() && target.blocksRedeployments())
427 throw new ArchivaRestServiceException(
428 "artifact already exists in target repo: " + artifactTransferRequest.getTargetRepositoryId()
429 + " and redeployment blocked", null
434 copyFile(artifactFile, targetFile, fixChecksums );
435 queueRepositoryTask( target.getId(), targetFile );
438 // copy source pom to target repo
439 String pomFilename = filename;
440 if ( StringUtils.isNotBlank( artifactTransferRequest.getClassifier() ) )
442 pomFilename = StringUtils.remove( pomFilename, "-" + artifactTransferRequest.getClassifier() );
444 pomFilename = FilenameUtils.removeExtension( pomFilename ) + ".pom";
446 StorageAsset pomFile = source.getAsset(
447 artifactSourcePath.substring( 0, artifactPath.lastIndexOf( '/' ) )+"/"+ pomFilename );
449 if ( pomFile != null && pomFile.exists() )
451 StorageAsset targetPomFile = target.getAsset( targetDir.getPath() + "/" + pomFilename );
452 copyFile(pomFile, targetPomFile, fixChecksums );
453 queueRepositoryTask( target.getId(), targetPomFile );
458 // explicitly update only if metadata-updater consumer is not enabled!
459 if ( !archivaAdministration.getKnownContentConsumers().contains( "metadata-updater" ) )
461 updateProjectMetadata( target.getType(), target, targetDir, lastUpdatedTimestamp, timestamp, newBuildNumber,
462 fixChecksums, artifactTransferRequest );
468 "Artifact \'" + artifactTransferRequest.getGroupId() + ":" + artifactTransferRequest.getArtifactId()
469 + ":" + artifactTransferRequest.getVersion() + "\' was successfully deployed to repository \'"
470 + artifactTransferRequest.getTargetRepositoryId() + "\'";
471 log.debug("copyArtifact {}", msg);
474 catch ( RepositoryException | LayoutException e )
476 log.error( "RepositoryException: {}", e.getMessage(), e );
477 throw new ArchivaRestServiceException( e.getMessage(), e );
479 catch ( RepositoryAdminException e )
481 log.error( "RepositoryAdminException: {}", e.getMessage(), e );
482 throw new ArchivaRestServiceException( e.getMessage(), e );
484 catch ( IOException e )
486 log.error( "IOException: {}", e.getMessage(), e );
487 throw new ArchivaRestServiceException( e.getMessage(), e );
492 private void queueRepositoryTask( String repositoryId, StorageAsset localFile )
495 RepositoryTask task = new RepositoryTask();
496 task.setRepositoryId( repositoryId );
497 task.setResourceFile( localFile );
498 task.setUpdateRelatedArtifacts( true );
499 //task.setScanAll( true );
503 scheduler.queueTask( task );
505 catch ( TaskQueueException e )
507 log.error( "Unable to queue repository task to execute consumers on resource file ['{}"
508 + "'].", localFile.getName());
512 private ArchivaRepositoryMetadata getMetadata( RepositoryType repositoryType, StorageAsset metadataFile )
513 throws RepositoryMetadataException
515 ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
516 if ( metadataFile.exists() )
518 metadata = repositoryRegistry.getMetadataReader( repositoryType ).read( metadataFile );
523 private StorageAsset getMetadata( RepositoryStorage storage, String targetPath )
525 return storage.getAsset( targetPath + "/" + MetadataTools.MAVEN_METADATA );
530 * Copies the asset to the new target.
532 private void copyFile(StorageAsset sourceFile, StorageAsset targetPath, boolean fixChecksums)
536 FsStorageUtil.copyAsset( sourceFile, targetPath, true );
539 fixChecksums( targetPath );
543 private void fixChecksums( StorageAsset file )
545 Path destinationFile = file.getFilePath();
546 if (destinationFile!=null)
548 ChecksummedFile checksum = new ChecksummedFile( destinationFile );
549 checksum.fixChecksums( algorithms );
553 private void updateProjectMetadata( RepositoryType repositoryType, RepositoryStorage storage, StorageAsset targetPath, Date lastUpdatedTimestamp, String timestamp, int buildNumber,
554 boolean fixChecksums, ArtifactTransferRequest artifactTransferRequest )
555 throws RepositoryMetadataException
557 List<String> availableVersions = new ArrayList<>();
558 String latestVersion = artifactTransferRequest.getVersion();
560 StorageAsset projectDir = targetPath.getParent();
561 StorageAsset projectMetadataFile = storage.getAsset( projectDir.getPath()+"/"+MetadataTools.MAVEN_METADATA );
563 ArchivaRepositoryMetadata projectMetadata = getMetadata( repositoryType, projectMetadataFile );
565 if ( projectMetadataFile.exists() )
567 availableVersions = projectMetadata.getAvailableVersions();
569 Collections.sort( availableVersions, VersionComparator.getInstance() );
571 if ( !availableVersions.contains( artifactTransferRequest.getVersion() ) )
573 availableVersions.add( artifactTransferRequest.getVersion() );
576 latestVersion = availableVersions.get( availableVersions.size() - 1 );
580 availableVersions.add( artifactTransferRequest.getVersion() );
582 projectMetadata.setGroupId( artifactTransferRequest.getGroupId() );
583 projectMetadata.setArtifactId( artifactTransferRequest.getArtifactId() );
586 if ( projectMetadata.getGroupId() == null )
588 projectMetadata.setGroupId( artifactTransferRequest.getGroupId() );
591 if ( projectMetadata.getArtifactId() == null )
593 projectMetadata.setArtifactId( artifactTransferRequest.getArtifactId() );
596 projectMetadata.setLatestVersion( latestVersion );
597 projectMetadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
598 projectMetadata.setAvailableVersions( availableVersions );
600 if ( !VersionUtil.isSnapshot( artifactTransferRequest.getVersion() ) )
602 projectMetadata.setReleasedVersion( latestVersion );
605 try(OutputStreamWriter writer = new OutputStreamWriter(projectMetadataFile.getWriteStream(true))) {
606 RepositoryMetadataWriter.write(projectMetadata, writer);
607 } catch (IOException e) {
608 throw new RepositoryMetadataException(e);
613 fixChecksums( projectMetadataFile );
618 public Boolean removeProjectVersion( String repositoryId, String namespace, String projectId, String version )
619 throws ArchivaRestServiceException
621 // if not a generic we can use the standard way to delete artifact
622 if ( !VersionUtil.isGenericSnapshot( version ) )
624 Artifact artifact = new Artifact( namespace, projectId, version );
625 artifact.setRepositoryId( repositoryId );
626 artifact.setContext( repositoryId );
627 return deleteArtifact( artifact );
630 if ( StringUtils.isEmpty( repositoryId ) )
632 throw new ArchivaRestServiceException( "repositoryId cannot be null", 400, null );
635 if ( !isAuthorizedToDeleteArtifacts( repositoryId ) )
637 throw new ArchivaRestServiceException( "not authorized to delete artifacts", 403, null );
640 if ( StringUtils.isEmpty( namespace ) )
642 throw new ArchivaRestServiceException( "groupId cannot be null", 400, null );
645 if ( StringUtils.isEmpty( projectId ) )
647 throw new ArchivaRestServiceException( "artifactId cannot be null", 400, null );
650 if ( StringUtils.isEmpty( version ) )
652 throw new ArchivaRestServiceException( "version cannot be null", 400, null );
655 RepositorySession repositorySession = null;
658 repositorySession = repositorySessionFactory.createSession();
660 catch ( MetadataRepositoryException e )
662 e.printStackTrace( );
667 ManagedRepositoryContent repository = getManagedRepositoryContent( repositoryId );
668 BaseRepositoryContentLayout layout = repository.getLayout( BaseRepositoryContentLayout.class );
670 ArchivaItemSelector selector = ArchivaItemSelector.builder( )
671 .withNamespace( namespace )
672 .withProjectId( projectId )
673 .withVersion( version )
675 Version versionItem = layout.getVersion( selector );
676 if (versionItem!=null && versionItem.exists()) {
677 repository.deleteItem( versionItem );
680 MetadataRepository metadataRepository = repositorySession.getRepository();
682 Collection<ArtifactMetadata> artifacts =
683 metadataRepository.getArtifacts(repositorySession , repositoryId, namespace, projectId, version );
685 for ( ArtifactMetadata artifactMetadata : artifacts )
687 metadataRepository.removeTimestampedArtifact(repositorySession , artifactMetadata, version );
690 metadataRepository.removeProjectVersion(repositorySession , repositoryId, namespace, projectId, version );
692 catch ( MetadataRepositoryException | MetadataResolutionException | RepositoryException | ItemNotFoundException | LayoutException e )
694 throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
700 repositorySession.save();
701 } catch (MetadataSessionException e) {
702 log.error("Session save failed {}", e.getMessage());
705 repositorySession.close();
713 public Boolean deleteArtifact( Artifact artifact )
714 throws ArchivaRestServiceException
717 String repositoryId = artifact.getContext();
718 // some rest call can use context or repositoryId
720 if ( StringUtils.isEmpty( repositoryId ) )
722 repositoryId = artifact.getRepositoryId();
724 if ( StringUtils.isEmpty( repositoryId ) )
726 throw new ArchivaRestServiceException( "repositoryId cannot be null", 400, null );
729 if ( !isAuthorizedToDeleteArtifacts( repositoryId ) )
731 throw new ArchivaRestServiceException( "not authorized to delete artifacts", 403, null );
734 if ( artifact == null )
736 throw new ArchivaRestServiceException( "artifact cannot be null", 400, null );
739 if ( StringUtils.isEmpty( artifact.getGroupId() ) )
741 throw new ArchivaRestServiceException( "artifact.groupId cannot be null", 400, null );
744 if ( StringUtils.isEmpty( artifact.getArtifactId() ) )
746 throw new ArchivaRestServiceException( "artifact.artifactId cannot be null", 400, null );
749 // TODO more control on artifact fields
751 boolean snapshotVersion =
752 VersionUtil.isSnapshot( artifact.getVersion() ) | VersionUtil.isGenericSnapshot( artifact.getVersion() );
754 RepositorySession repositorySession = null;
757 repositorySession = repositorySessionFactory.createSession();
759 catch ( MetadataRepositoryException e )
761 e.printStackTrace( );
765 Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
767 TimeZone timezone = TimeZone.getTimeZone( "UTC" );
768 DateFormat fmt = new SimpleDateFormat( "yyyyMMdd.HHmmss" );
769 fmt.setTimeZone( timezone );
770 ManagedRepository repo = repositoryRegistry.getManagedRepository( repositoryId );
772 ManagedRepositoryContent repository = getManagedRepositoryContent( repositoryId );
773 BaseRepositoryContentLayout layout = repository.getLayout( BaseRepositoryContentLayout.class );
775 ArchivaItemSelector versionSelector = ArchivaItemSelector.builder( ).withNamespace( artifact.getGroupId( ) )
776 .withProjectId( artifact.getArtifactId( ) )
777 .withVersion( artifact.getVersion( ) ).build( );
779 Version version1 = layout.getVersion( versionSelector );
780 String path = repository.toPath( version1 );
782 ArtifactReference artifactReference = new ArtifactReference();
783 artifactReference.setArtifactId( artifact.getArtifactId() );
784 artifactReference.setGroupId( artifact.getGroupId() );
785 artifactReference.setVersion( artifact.getVersion() );
786 artifactReference.setClassifier( artifact.getClassifier() );
787 artifactReference.setType( artifact.getType() );
789 ArchivaItemSelector selector = ArchivaItemSelector.builder( )
790 .withNamespace( artifact.getGroupId( ) )
791 .withProjectId( artifact.getArtifactId( ) )
792 .withVersion( artifact.getVersion( ) )
793 .withClassifier( artifact.getClassifier( ) )
794 .withArtifactId( artifact.getArtifactId( ) )
795 .withType( artifact.getType( ) )
796 .includeRelatedArtifacts()
799 MetadataRepository metadataRepository = repositorySession.getRepository();
801 if ( StringUtils.isNotBlank( artifact.getClassifier() ) )
803 if ( StringUtils.isBlank( artifact.getPackaging() ) )
805 throw new ArchivaRestServiceException( "You must configure a type/packaging when using classifier",
808 List<? extends org.apache.archiva.repository.content.Artifact> artifactItems = layout.getArtifacts( selector );
809 for ( org.apache.archiva.repository.content.Artifact aRef : artifactItems ) {
812 repository.deleteItem( aRef );
814 catch ( ItemNotFoundException e )
816 log.error( "Could not delete item, seems to be deleted by other thread. {}, {} ", aRef, e.getMessage( ) );
824 int index = path.lastIndexOf( '/' );
825 path = path.substring( 0, index );
826 StorageAsset targetPath = repo.getAsset( path );
828 if ( !targetPath.exists() )
830 //throw new ContentNotFoundException(
831 // artifact.getNamespace() + ":" + artifact.getArtifactId() + ":" + artifact.getVersion() );
832 log.warn( "targetPath {} not found skip file deletion", targetPath );
836 // TODO: this should be in the storage mechanism so that it is all tied together
837 // delete from file system
838 if ( !snapshotVersion && version1.exists() )
842 repository.deleteItem( version1 );
844 catch ( ItemNotFoundException e )
846 log.error( "Could not delete version item {}", e.getMessage( ) );
851 // We are deleting all version related artifacts for a snapshot version
852 VersionedReference versionRef = layout.toVersion( artifactReference );
853 List<ArtifactReference> related = layout.getRelatedArtifacts( versionRef );
854 log.debug( "related: {}", related );
855 for ( ArtifactReference artifactRef : related )
859 layout.deleteArtifact( artifactRef );
860 } catch (ContentNotFoundException e) {
861 log.warn( "Artifact that should be deleted, was not found: {}", artifactRef );
864 StorageAsset metadataFile = getMetadata( repo, targetPath.getPath() );
865 ArchivaRepositoryMetadata metadata = getMetadata( repository.getRepository().getType(), metadataFile );
867 updateMetadata( metadata, metadataFile, lastUpdatedTimestamp, artifact );
870 Collection<ArtifactMetadata> artifacts = Collections.emptyList();
872 if ( snapshotVersion )
874 String baseVersion = VersionUtil.getBaseVersion( artifact.getVersion() );
876 metadataRepository.getArtifacts(repositorySession , repositoryId, artifact.getGroupId(),
877 artifact.getArtifactId(), baseVersion );
882 metadataRepository.getArtifacts(repositorySession , repositoryId, artifact.getGroupId(),
883 artifact.getArtifactId(), artifact.getVersion() );
886 log.debug( "artifacts: {}", artifacts );
888 if ( artifacts.isEmpty() )
890 if ( !snapshotVersion )
892 // verify metata repository doesn't contains anymore the version
893 Collection<String> projectVersions =
894 metadataRepository.getProjectVersions(repositorySession , repositoryId,
895 artifact.getGroupId(), artifact.getArtifactId() );
897 if ( projectVersions.contains( artifact.getVersion() ) )
899 log.warn( "artifact not found when deleted but version still here ! so force cleanup" );
900 metadataRepository.removeProjectVersion(repositorySession , repositoryId,
901 artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion() );
907 for ( ArtifactMetadata artifactMetadata : artifacts )
910 // TODO: mismatch between artifact (snapshot) version and project (base) version here
911 if ( artifactMetadata.getVersion().equals( artifact.getVersion() ) )
913 if ( StringUtils.isNotBlank( artifact.getClassifier() ) )
915 if ( StringUtils.isBlank( artifact.getPackaging() ) )
917 throw new ArchivaRestServiceException(
918 "You must configure a type/packaging when using classifier", 400, null );
920 // cleanup facet which contains classifier information
921 MavenArtifactFacet mavenArtifactFacet =
922 (MavenArtifactFacet) artifactMetadata.getFacet( MavenArtifactFacet.FACET_ID );
924 if ( StringUtils.equals( artifact.getClassifier(), mavenArtifactFacet.getClassifier() ) )
926 artifactMetadata.removeFacet( MavenArtifactFacet.FACET_ID );
927 String groupId = artifact.getGroupId(), artifactId = artifact.getArtifactId(), version =
928 artifact.getVersion();
929 MavenArtifactFacet mavenArtifactFacetToCompare = new MavenArtifactFacet();
930 mavenArtifactFacetToCompare.setClassifier( artifact.getClassifier() );
931 metadataRepository.removeFacetFromArtifact(repositorySession , repositoryId, groupId, artifactId,
932 version, mavenArtifactFacetToCompare );
933 repositorySession.save();
939 if ( snapshotVersion )
941 metadataRepository.removeTimestampedArtifact(repositorySession ,
942 artifactMetadata, VersionUtil.getBaseVersion( artifact.getVersion() ) );
946 metadataRepository.removeArtifact(repositorySession ,
947 artifactMetadata.getRepositoryId(),
948 artifactMetadata.getNamespace(), artifactMetadata.getProject(),
949 artifact.getVersion(), artifactMetadata.getId() );
952 // TODO: move into the metadata repository proper - need to differentiate attachment of
953 // repository metadata to an artifact
954 for ( RepositoryListener listener : listeners )
956 listener.deleteArtifact( metadataRepository, repository.getId(),
957 artifactMetadata.getNamespace(), artifactMetadata.getProject(),
958 artifactMetadata.getVersion(), artifactMetadata.getId() );
961 triggerAuditEvent( repositoryId, path, AuditEvent.REMOVE_FILE );
965 catch ( ContentNotFoundException e )
967 throw new ArchivaRestServiceException( "Artifact does not exist: " + e.getMessage(), 400, e );
969 catch ( RepositoryNotFoundException e )
971 throw new ArchivaRestServiceException( "Target repository cannot be found: " + e.getMessage(), 400, e );
973 catch ( RepositoryException e )
975 throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
977 catch (MetadataResolutionException | MetadataSessionException | MetadataRepositoryException | LayoutException e )
979 throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
985 repositorySession.save();
986 } catch (MetadataSessionException e) {
987 log.error("Could not save sesion {}", e.getMessage());
990 repositorySession.close();
996 public Boolean deleteGroupId( String groupId, String repositoryId )
997 throws ArchivaRestServiceException
999 if ( StringUtils.isEmpty( repositoryId ) )
1001 throw new ArchivaRestServiceException( "repositoryId cannot be null", 400, null );
1004 if ( !isAuthorizedToDeleteArtifacts( repositoryId ) )
1006 throw new ArchivaRestServiceException( "not authorized to delete artifacts", 403, null );
1009 if ( StringUtils.isEmpty( groupId ) )
1011 throw new ArchivaRestServiceException( "groupId cannot be null", 400, null );
1014 RepositorySession repositorySession = null;
1017 repositorySession = repositorySessionFactory.createSession();
1019 catch ( MetadataRepositoryException e )
1021 e.printStackTrace( );
1026 ManagedRepositoryContent repository = getManagedRepositoryContent( repositoryId );
1027 ArchivaItemSelector itemselector = ArchivaItemSelector.builder( ).withNamespace( groupId ).build();
1028 ContentItem item = repository.getItem( itemselector );
1029 repository.deleteItem( item );
1031 MetadataRepository metadataRepository = repositorySession.getRepository();
1033 metadataRepository.removeNamespace(repositorySession , repositoryId, groupId );
1035 // just invalidate cache entry
1036 String cacheKey = repositoryId + "-" + groupId;
1037 namespacesCache.remove( cacheKey );
1038 namespacesCache.remove( repositoryId );
1040 repositorySession.save();
1042 catch (MetadataRepositoryException | MetadataSessionException e )
1044 log.error( e.getMessage(), e );
1045 throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
1047 catch ( RepositoryException e )
1049 log.error( e.getMessage(), e );
1050 throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
1052 catch ( ItemNotFoundException e )
1054 log.error( "Item not found {}", e.getMessage(), e );
1055 throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
1060 repositorySession.close();
1066 public Boolean deleteProject( String groupId, String projectId, String repositoryId )
1067 throws ArchivaRestServiceException
1069 if ( StringUtils.isEmpty( repositoryId ) )
1071 throw new ArchivaRestServiceException( "repositoryId cannot be null", 400, null );
1074 if ( !isAuthorizedToDeleteArtifacts( repositoryId ) )
1076 throw new ArchivaRestServiceException( "not authorized to delete artifacts", 403, null );
1079 if ( StringUtils.isEmpty( groupId ) )
1081 throw new ArchivaRestServiceException( "groupId cannot be null", 400, null );
1084 if ( StringUtils.isEmpty( projectId ) )
1086 throw new ArchivaRestServiceException( "artifactId cannot be null", 400, null );
1089 RepositorySession repositorySession = null;
1092 repositorySession = repositorySessionFactory.createSession();
1094 catch ( MetadataRepositoryException e )
1096 e.printStackTrace( );
1101 ManagedRepositoryContent repository = getManagedRepositoryContent( repositoryId );
1102 ArchivaItemSelector itemSelector = ArchivaItemSelector.builder( ).withNamespace( groupId )
1103 .withProjectId( projectId ).build( );
1104 ContentItem item = repository.getItem( itemSelector );
1106 repository.deleteItem( item );
1108 catch ( ContentNotFoundException e )
1110 log.warn( "skip ContentNotFoundException: {}", e.getMessage() );
1112 catch ( RepositoryException e )
1114 log.error( e.getMessage(), e );
1115 throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
1117 catch ( ItemNotFoundException e )
1119 log.error( "Item not found {}", e.getMessage(), e );
1120 throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
1126 MetadataRepository metadataRepository = repositorySession.getRepository();
1128 metadataRepository.removeProject(repositorySession , repositoryId, groupId, projectId );
1130 repositorySession.save();
1132 catch (MetadataRepositoryException | MetadataSessionException e )
1134 log.error( e.getMessage(), e );
1135 throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
1140 repositorySession.close();
1147 public Boolean isAuthorizedToDeleteArtifacts( String repoId )
1148 throws ArchivaRestServiceException
1151 getAuditInformation().getUser() == null ? "guest" : getAuditInformation().getUser().getUsername();
1155 return userRepositories.isAuthorizedToDeleteArtifacts( userName, repoId );
1157 catch ( ArchivaSecurityException e )
1159 throw new ArchivaRestServiceException( e.getMessage(),
1160 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
1165 public RepositoryScanStatistics scanRepositoryDirectoriesNow( String repositoryId )
1166 throws ArchivaRestServiceException
1168 long sinceWhen = RepositoryScanner.FRESH_SCAN;
1171 return repoScanner.scan( repositoryRegistry.getManagedRepository( repositoryId ), sinceWhen );
1173 catch ( RepositoryScannerException e )
1175 log.error( e.getMessage(), e );
1176 throw new ArchivaRestServiceException( "RepositoryScannerException exception: " + e.getMessage(), 500, e );
1181 * Update artifact level metadata. Creates one if metadata does not exist after artifact deletion.
1185 private void updateMetadata( ArchivaRepositoryMetadata metadata, StorageAsset metadataFile, Date lastUpdatedTimestamp,
1187 throws RepositoryMetadataException
1189 List<String> availableVersions = new ArrayList<>();
1190 String latestVersion = "";
1192 if ( metadataFile.exists() )
1194 if ( metadata.getAvailableVersions() != null )
1196 availableVersions = metadata.getAvailableVersions();
1198 if ( availableVersions.size() > 0 )
1200 Collections.sort( availableVersions, VersionComparator.getInstance() );
1202 if ( availableVersions.contains( artifact.getVersion() ) )
1204 availableVersions.remove( availableVersions.indexOf( artifact.getVersion() ) );
1206 if ( availableVersions.size() > 0 )
1208 latestVersion = availableVersions.get( availableVersions.size() - 1 );
1214 if ( metadata.getGroupId() == null )
1216 metadata.setGroupId( artifact.getGroupId() );
1218 if ( metadata.getArtifactId() == null )
1220 metadata.setArtifactId( artifact.getArtifactId() );
1223 if ( !VersionUtil.isSnapshot( artifact.getVersion() ) )
1225 if ( metadata.getReleasedVersion() != null && metadata.getReleasedVersion().equals(
1226 artifact.getVersion() ) )
1228 metadata.setReleasedVersion( latestVersion );
1232 metadata.setLatestVersion( latestVersion );
1233 metadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
1234 metadata.setAvailableVersions( availableVersions );
1236 try (OutputStreamWriter writer = new OutputStreamWriter(metadataFile.getWriteStream(true))) {
1237 RepositoryMetadataWriter.write(metadata, writer);
1238 } catch (IOException e) {
1239 throw new RepositoryMetadataException(e);
1241 ChecksummedFile checksum = new ChecksummedFile( metadataFile.getFilePath() );
1242 checksum.fixChecksums( algorithms );
1246 public StringList getRunningRemoteDownloadIds()
1248 return new StringList( downloadRemoteIndexScheduler.getRunningRemoteDownloadIds() );
1251 public RepositorySessionFactory getRepositorySessionFactory()
1253 return repositorySessionFactory;
1256 public void setRepositorySessionFactory( RepositorySessionFactory repositorySessionFactory )
1258 this.repositorySessionFactory = repositorySessionFactory;
1261 public List<RepositoryListener> getListeners()
1266 public void setListeners( List<RepositoryListener> listeners )
1268 this.listeners = listeners;
1271 public ArchivaAdministration getArchivaAdministration()
1273 return archivaAdministration;
1276 public void setArchivaAdministration( ArchivaAdministration archivaAdministration )
1278 this.archivaAdministration = archivaAdministration;