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.components.cache.Cache;
29 import org.apache.archiva.components.taskqueue.TaskQueueException;
30 import org.apache.archiva.maven2.model.Artifact;
31 import org.apache.archiva.metadata.audit.RepositoryListener;
32 import org.apache.archiva.metadata.maven.model.MavenArtifactFacet;
33 import org.apache.archiva.metadata.model.ArtifactMetadata;
34 import org.apache.archiva.metadata.model.facets.AuditEvent;
35 import org.apache.archiva.metadata.repository.MetadataRepository;
36 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
37 import org.apache.archiva.metadata.repository.MetadataResolutionException;
38 import org.apache.archiva.metadata.repository.MetadataSessionException;
39 import org.apache.archiva.metadata.repository.RepositorySession;
40 import org.apache.archiva.metadata.repository.RepositorySessionFactory;
41 import org.apache.archiva.model.ArchivaRepositoryMetadata;
42 import org.apache.archiva.redback.authentication.AuthenticationResult;
43 import org.apache.archiva.redback.authorization.AuthorizationException;
44 import org.apache.archiva.redback.system.DefaultSecuritySession;
45 import org.apache.archiva.redback.system.SecuritySession;
46 import org.apache.archiva.redback.system.SecuritySystem;
47 import org.apache.archiva.redback.users.User;
48 import org.apache.archiva.redback.users.UserManagerException;
49 import org.apache.archiva.redback.users.UserNotFoundException;
50 import org.apache.archiva.repository.base.RepositoryGroupHandler;
51 import org.apache.archiva.repository.content.BaseRepositoryContentLayout;
52 import org.apache.archiva.repository.content.ContentNotFoundException;
53 import org.apache.archiva.repository.content.LayoutException;
54 import org.apache.archiva.repository.ManagedRepository;
55 import org.apache.archiva.repository.ManagedRepositoryContent;
56 import org.apache.archiva.repository.RepositoryException;
57 import org.apache.archiva.repository.RepositoryNotFoundException;
58 import org.apache.archiva.repository.RepositoryRegistry;
59 import org.apache.archiva.repository.RepositoryType;
60 import org.apache.archiva.repository.content.ContentItem;
61 import org.apache.archiva.repository.content.ItemNotFoundException;
62 import org.apache.archiva.repository.content.ItemSelector;
63 import org.apache.archiva.repository.content.Version;
64 import org.apache.archiva.repository.content.base.ArchivaItemSelector;
65 import org.apache.archiva.repository.metadata.RepositoryMetadataException;
66 import org.apache.archiva.repository.metadata.base.MetadataTools;
67 import org.apache.archiva.repository.metadata.base.RepositoryMetadataWriter;
68 import org.apache.archiva.repository.scanner.RepositoryScanStatistics;
69 import org.apache.archiva.repository.scanner.RepositoryScanner;
70 import org.apache.archiva.repository.scanner.RepositoryScannerException;
71 import org.apache.archiva.repository.scanner.RepositoryScannerInstance;
72 import org.apache.archiva.repository.storage.RepositoryStorage;
73 import org.apache.archiva.repository.storage.StorageAsset;
74 import org.apache.archiva.repository.storage.fs.FsStorageUtil;
75 import org.apache.archiva.rest.api.model.ActionStatus;
76 import org.apache.archiva.rest.api.model.ArtifactTransferRequest;
77 import org.apache.archiva.rest.api.model.PermissionStatus;
78 import org.apache.archiva.rest.api.model.ScanStatus;
79 import org.apache.archiva.rest.api.model.StringList;
80 import org.apache.archiva.rest.api.services.ArchivaRestServiceException;
81 import org.apache.archiva.rest.api.services.RepositoriesService;
82 import org.apache.archiva.scheduler.ArchivaTaskScheduler;
83 import org.apache.archiva.scheduler.indexing.ArtifactIndexingTask;
84 import org.apache.archiva.scheduler.indexing.DownloadRemoteIndexException;
85 import org.apache.archiva.scheduler.indexing.DownloadRemoteIndexScheduler;
86 import org.apache.archiva.scheduler.indexing.maven.ArchivaIndexingTaskExecutor;
87 import org.apache.archiva.scheduler.repository.model.RepositoryTask;
88 import org.apache.archiva.security.ArchivaSecurityException;
89 import org.apache.archiva.security.common.ArchivaRoleConstants;
90 import org.apache.commons.io.FilenameUtils;
91 import org.apache.commons.lang3.StringUtils;
92 import org.slf4j.Logger;
93 import org.slf4j.LoggerFactory;
94 import org.springframework.beans.factory.annotation.Autowired;
95 import org.springframework.stereotype.Service;
97 import javax.inject.Inject;
98 import javax.inject.Named;
99 import javax.ws.rs.core.Response;
100 import java.io.IOException;
101 import java.io.OutputStreamWriter;
102 import java.nio.file.Path;
103 import java.text.DateFormat;
104 import java.text.SimpleDateFormat;
105 import java.util.ArrayList;
106 import java.util.Arrays;
107 import java.util.Calendar;
108 import java.util.Collection;
109 import java.util.Collections;
110 import java.util.Date;
111 import java.util.List;
112 import java.util.TimeZone;
115 * @author Olivier Lamy
118 @Service("repositoriesService#rest")
119 public class DefaultRepositoriesService
120 extends AbstractRestService
121 implements RepositoriesService
123 private Logger log = LoggerFactory.getLogger( getClass() );
126 @Named(value = "taskExecutor#indexing")
127 private ArchivaIndexingTaskExecutor archivaIndexingTaskExecutor;
130 private RepositoryRegistry repositoryRegistry;
132 @SuppressWarnings( "unused" )
134 private RepositoryGroupHandler repositoryGroupHandler;
137 private SecuritySystem securitySystem;
140 @Named(value = "archivaTaskScheduler#repository")
141 private ArchivaTaskScheduler<RepositoryTask> scheduler;
144 private DownloadRemoteIndexScheduler downloadRemoteIndexScheduler;
147 @Named(value = "repositorySessionFactory")
148 protected RepositorySessionFactory repositorySessionFactory;
151 @Autowired(required = false)
152 protected List<RepositoryListener> listeners = new ArrayList<RepositoryListener>();
155 private RepositoryScanner repoScanner;
158 * Cache used for namespaces
161 @Named(value = "cache#namespaces")
162 private Cache<String, Collection<String>> namespacesCache;
164 private List<ChecksumAlgorithm> algorithms = Arrays.asList(ChecksumAlgorithm.SHA256, ChecksumAlgorithm.SHA1, ChecksumAlgorithm.MD5 );
167 public ActionStatus scanRepository( String repositoryId, boolean fullScan )
169 return new ActionStatus( doScanRepository( repositoryId, fullScan ) );
173 public ScanStatus getScanStatus( String repositoryId )
175 // check queue first to make sure it doesn't get dequeued between calls
176 if ( repositoryTaskScheduler.isProcessingRepositoryTask( repositoryId ) )
178 return new ScanStatus( true );
180 for ( RepositoryScannerInstance scan : repoScanner.getInProgressScans() )
182 if ( scan.getRepository().getId().equals( repositoryId ) )
184 return new ScanStatus( true );
187 return new ScanStatus( false );
191 public ActionStatus removeScanningTaskFromQueue( String repositoryId )
193 RepositoryTask task = new RepositoryTask();
194 task.setRepositoryId( repositoryId );
197 return new ActionStatus( repositoryTaskScheduler.unQueueTask( task ) );
199 catch ( TaskQueueException e )
201 log.error( "failed to unschedule scanning of repo with id {}", repositoryId, e );
202 return ActionStatus.FAIL;
206 private ManagedRepositoryContent getManagedRepositoryContent( String id) throws RepositoryException
208 org.apache.archiva.repository.ManagedRepository repo = repositoryRegistry.getManagedRepository( id );
210 throw new RepositoryException( "Repository not found "+id );
212 return repo.getContent();
216 public ActionStatus scanRepositoryNow( String repositoryId, boolean fullScan )
217 throws ArchivaRestServiceException
223 org.apache.archiva.repository.ManagedRepository repository = repositoryRegistry.getManagedRepository( repositoryId );
226 ArtifactIndexingTask task =
227 new ArtifactIndexingTask( repository, null, ArtifactIndexingTask.Action.FINISH, repository.getIndexingContext() );
229 task.setExecuteOnEntireRepo( true );
230 task.setOnlyUpdate( !fullScan );
232 archivaIndexingTaskExecutor.executeTask( task );
234 scheduler.queueTask( new RepositoryTask( repositoryId, fullScan ) );
236 return ActionStatus.SUCCESS;
238 catch ( Exception e )
240 log.error( e.getMessage(), e );
241 throw new ArchivaRestServiceException( e.getMessage(), e );
246 public ActionStatus scheduleDownloadRemoteIndex( String repositoryId, boolean now, boolean fullDownload )
247 throws ArchivaRestServiceException
251 downloadRemoteIndexScheduler.scheduleDownloadRemote( repositoryId, now, fullDownload );
253 catch ( DownloadRemoteIndexException e )
255 log.error( e.getMessage(), e );
256 throw new ArchivaRestServiceException( e.getMessage(), e );
258 return ActionStatus.SUCCESS;
262 public ActionStatus copyArtifact( ArtifactTransferRequest artifactTransferRequest )
263 throws ArchivaRestServiceException
266 String userName = getAuditInformation().getUser().getUsername();
267 if ( StringUtils.isBlank( userName ) )
269 throw new ArchivaRestServiceException( "copyArtifact call: userName not found", null );
272 if ( StringUtils.isBlank( artifactTransferRequest.getRepositoryId() ) )
274 throw new ArchivaRestServiceException( "copyArtifact call: sourceRepositoryId cannot be null", null );
277 if ( StringUtils.isBlank( artifactTransferRequest.getTargetRepositoryId() ) )
279 throw new ArchivaRestServiceException( "copyArtifact call: targetRepositoryId cannot be null", null );
282 ManagedRepository source = null;
283 source = repositoryRegistry.getManagedRepository( artifactTransferRequest.getRepositoryId() );
285 if ( source == null )
287 throw new ArchivaRestServiceException(
288 "cannot find repository with id " + artifactTransferRequest.getRepositoryId(), null );
291 ManagedRepository target = null;
292 target = repositoryRegistry.getManagedRepository( artifactTransferRequest.getTargetRepositoryId() );
294 if ( target == null )
296 throw new ArchivaRestServiceException(
297 "cannot find repository with id " + artifactTransferRequest.getTargetRepositoryId(), null );
300 if ( StringUtils.isBlank( artifactTransferRequest.getGroupId() ) )
302 throw new ArchivaRestServiceException( "groupId is mandatory", null );
305 if ( StringUtils.isBlank( artifactTransferRequest.getArtifactId() ) )
307 throw new ArchivaRestServiceException( "artifactId is mandatory", null );
310 if ( StringUtils.isBlank( artifactTransferRequest.getVersion() ) )
312 throw new ArchivaRestServiceException( "version is mandatory", null );
315 if ( VersionUtil.isSnapshot( artifactTransferRequest.getVersion() ) )
317 throw new ArchivaRestServiceException( "copy of SNAPSHOT not supported", null );
320 // end check parameters
325 user = securitySystem.getUserManager().findUser( userName );
327 catch ( UserNotFoundException e )
329 throw new ArchivaRestServiceException( "user " + userName + " not found", e );
331 catch ( UserManagerException e )
333 throw new ArchivaRestServiceException( "ArchivaRestServiceException:" + e.getMessage(), e );
336 // check karma on source : read
337 AuthenticationResult authn = new AuthenticationResult( true, userName, null );
338 SecuritySession securitySession = new DefaultSecuritySession( authn, user );
342 securitySystem.isAuthorized( securitySession, ArchivaRoleConstants.OPERATION_REPOSITORY_ACCESS,
343 artifactTransferRequest.getRepositoryId() );
346 throw new ArchivaRestServiceException(
347 "not authorized to access repo:" + artifactTransferRequest.getRepositoryId(), null );
350 catch ( AuthorizationException e )
352 log.error( "error reading permission: {}", e.getMessage(), e );
353 throw new ArchivaRestServiceException( e.getMessage(), e );
356 // check karma on target: write
360 securitySystem.isAuthorized( securitySession, ArchivaRoleConstants.OPERATION_REPOSITORY_UPLOAD,
361 artifactTransferRequest.getTargetRepositoryId() );
364 throw new ArchivaRestServiceException(
365 "not authorized to write to repo:" + artifactTransferRequest.getTargetRepositoryId(), null );
368 catch ( AuthorizationException e )
370 log.error( "error reading permission: {}", e.getMessage(), e );
371 throw new ArchivaRestServiceException( e.getMessage(), e );
374 // sounds good we can continue !
376 String packaging = StringUtils.trim( artifactTransferRequest.getPackaging() );
377 ItemSelector selector = ArchivaItemSelector.builder( )
378 .withProjectId( artifactTransferRequest.getArtifactId( ) )
379 .withArtifactId( artifactTransferRequest.getArtifactId( ) )
380 .withNamespace( artifactTransferRequest.getGroupId( ) )
381 .withArtifactVersion( artifactTransferRequest.getVersion( ) )
382 .withClassifier( artifactTransferRequest.getClassifier( ) )
383 .withExtension( StringUtils.isEmpty( packaging ) ? "jar" : packaging )
390 ManagedRepositoryContent sourceRepository =
391 getManagedRepositoryContent( artifactTransferRequest.getRepositoryId() );
392 BaseRepositoryContentLayout layout = sourceRepository.getLayout( BaseRepositoryContentLayout.class );
393 // String artifactSourcePath = sourceRepository.toPath( selector );
394 org.apache.archiva.repository.content.Artifact sourceArtifact = layout.getArtifact( selector );
396 if ( !sourceArtifact.exists() )
398 log.error( "cannot find artifact {}", artifactTransferRequest );
399 throw new ArchivaRestServiceException( "cannot find artifact " + artifactTransferRequest.toString(),
403 StorageAsset artifactFile = sourceArtifact.getAsset( );
405 ManagedRepositoryContent targetRepository =
406 getManagedRepositoryContent( artifactTransferRequest.getTargetRepositoryId() );
408 String artifactPath = artifactFile.getPath( );
410 int lastIndex = artifactPath.lastIndexOf( '/' );
412 String path = artifactPath.substring( 0, lastIndex );
413 StorageAsset targetDir = target.getAsset( path );
415 Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
416 int newBuildNumber = 1;
417 String timestamp = null;
419 StorageAsset versionMetadataFile = target.getAsset(path + "/" + MetadataTools.MAVEN_METADATA );
420 /* unused */ getMetadata( targetRepository.getRepository().getType(), versionMetadataFile );
422 if ( !targetDir.exists() )
424 targetDir = target.addAsset(targetDir.getPath(), true);
428 String filename = artifactPath.substring( lastIndex + 1 );
430 boolean fixChecksums =
431 !( archivaAdministration.getKnownContentConsumers().contains( "create-missing-checksums" ) );
433 StorageAsset targetFile = target.getAsset(targetDir.getPath() + "/" + filename );
434 if ( targetFile.exists() && target.blocksRedeployments())
436 throw new ArchivaRestServiceException(
437 "artifact already exists in target repo: " + artifactTransferRequest.getTargetRepositoryId()
438 + " and redeployment blocked", null
443 copyFile(artifactFile, targetFile, fixChecksums );
444 queueRepositoryTask( target.getId(), targetFile );
447 // copy source pom to target repo
448 String pomFilename = filename;
449 if ( StringUtils.isNotBlank( artifactTransferRequest.getClassifier() ) )
451 pomFilename = StringUtils.remove( pomFilename, "-" + artifactTransferRequest.getClassifier() );
453 pomFilename = FilenameUtils.removeExtension( pomFilename ) + ".pom";
455 StorageAsset pomFile = source.getAsset(
456 artifactPath.substring( 0, artifactPath.lastIndexOf( '/' ) )+"/"+ pomFilename );
458 if ( pomFile != null && pomFile.exists() )
460 StorageAsset targetPomFile = target.getAsset( targetDir.getPath() + "/" + pomFilename );
461 copyFile(pomFile, targetPomFile, fixChecksums );
462 queueRepositoryTask( target.getId(), targetPomFile );
467 // explicitly update only if metadata-updater consumer is not enabled!
468 if ( !archivaAdministration.getKnownContentConsumers().contains( "metadata-updater" ) )
470 updateProjectMetadata( target.getType(), target, targetDir, lastUpdatedTimestamp, timestamp, newBuildNumber,
471 fixChecksums, artifactTransferRequest );
477 "Artifact \'" + artifactTransferRequest.getGroupId() + ":" + artifactTransferRequest.getArtifactId()
478 + ":" + artifactTransferRequest.getVersion() + "\' was successfully deployed to repository \'"
479 + artifactTransferRequest.getTargetRepositoryId() + "\'";
480 log.debug("copyArtifact {}", msg);
483 catch ( RepositoryException | LayoutException e )
485 log.error( "RepositoryException: {}", e.getMessage(), e );
486 throw new ArchivaRestServiceException( e.getMessage(), e );
488 catch ( RepositoryAdminException e )
490 log.error( "RepositoryAdminException: {}", e.getMessage(), e );
491 throw new ArchivaRestServiceException( e.getMessage(), e );
493 catch ( IOException e )
495 log.error( "IOException: {}", e.getMessage(), e );
496 throw new ArchivaRestServiceException( e.getMessage(), e );
498 return ActionStatus.SUCCESS;
501 private void queueRepositoryTask( String repositoryId, StorageAsset localFile )
504 RepositoryTask task = new RepositoryTask();
505 task.setRepositoryId( repositoryId );
506 task.setResourceFile( localFile );
507 task.setUpdateRelatedArtifacts( true );
508 //task.setScanAll( true );
512 scheduler.queueTask( task );
514 catch ( TaskQueueException e )
516 log.error( "Unable to queue repository task to execute consumers on resource file ['{}"
517 + "'].", localFile.getName());
521 private ArchivaRepositoryMetadata getMetadata( RepositoryType repositoryType, StorageAsset metadataFile )
522 throws RepositoryMetadataException
524 ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
525 if ( metadataFile.exists() )
527 metadata = repositoryRegistry.getMetadataReader( repositoryType ).read( metadataFile );
532 private StorageAsset getMetadata( RepositoryStorage storage, String targetPath )
534 return storage.getAsset( targetPath + "/" + MetadataTools.MAVEN_METADATA );
539 * Copies the asset to the new target.
541 private void copyFile(StorageAsset sourceFile, StorageAsset targetPath, boolean fixChecksums)
545 FsStorageUtil.copyAsset( sourceFile, targetPath, true );
548 fixChecksums( targetPath );
552 private void fixChecksums( StorageAsset file )
554 Path destinationFile = file.getFilePath();
555 if (destinationFile!=null)
557 ChecksummedFile checksum = new ChecksummedFile( destinationFile );
558 checksum.fixChecksums( algorithms );
562 private void updateProjectMetadata( RepositoryType repositoryType, RepositoryStorage storage, StorageAsset targetPath, Date lastUpdatedTimestamp, String timestamp, int buildNumber,
563 boolean fixChecksums, ArtifactTransferRequest artifactTransferRequest )
564 throws RepositoryMetadataException
566 List<String> availableVersions = new ArrayList<>();
567 String latestVersion = artifactTransferRequest.getVersion();
569 StorageAsset projectDir = targetPath.getParent();
570 StorageAsset projectMetadataFile = storage.getAsset( projectDir.getPath()+"/"+MetadataTools.MAVEN_METADATA );
572 ArchivaRepositoryMetadata projectMetadata = getMetadata( repositoryType, projectMetadataFile );
574 if ( projectMetadataFile.exists() )
576 availableVersions = projectMetadata.getAvailableVersions();
578 Collections.sort( availableVersions, VersionComparator.getInstance() );
580 if ( !availableVersions.contains( artifactTransferRequest.getVersion() ) )
582 availableVersions.add( artifactTransferRequest.getVersion() );
585 latestVersion = availableVersions.get( availableVersions.size() - 1 );
589 availableVersions.add( artifactTransferRequest.getVersion() );
591 projectMetadata.setGroupId( artifactTransferRequest.getGroupId() );
592 projectMetadata.setArtifactId( artifactTransferRequest.getArtifactId() );
595 if ( projectMetadata.getGroupId() == null )
597 projectMetadata.setGroupId( artifactTransferRequest.getGroupId() );
600 if ( projectMetadata.getArtifactId() == null )
602 projectMetadata.setArtifactId( artifactTransferRequest.getArtifactId() );
605 projectMetadata.setLatestVersion( latestVersion );
606 projectMetadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
607 projectMetadata.setAvailableVersions( availableVersions );
609 if ( !VersionUtil.isSnapshot( artifactTransferRequest.getVersion() ) )
611 projectMetadata.setReleasedVersion( latestVersion );
614 try(OutputStreamWriter writer = new OutputStreamWriter(projectMetadataFile.getWriteStream(true))) {
615 RepositoryMetadataWriter.write(projectMetadata, writer);
616 } catch (IOException e) {
617 throw new RepositoryMetadataException(e);
622 fixChecksums( projectMetadataFile );
627 public ActionStatus removeProjectVersion( String repositoryId, String namespace, String projectId, String version )
628 throws ArchivaRestServiceException
630 // if not a generic we can use the standard way to delete artifact
631 if ( !VersionUtil.isGenericSnapshot( version ) )
633 Artifact artifact = new Artifact( namespace, projectId, version );
634 artifact.setRepositoryId( repositoryId );
635 artifact.setContext( repositoryId );
636 return deleteArtifact( artifact );
639 if ( StringUtils.isEmpty( repositoryId ) )
641 throw new ArchivaRestServiceException( "repositoryId cannot be null", 400, null );
644 if ( !getPermissionStatus( repositoryId ).isAuthorizedToDeleteArtifacts() )
646 throw new ArchivaRestServiceException( "not authorized to delete artifacts", 403, null );
649 if ( StringUtils.isEmpty( namespace ) )
651 throw new ArchivaRestServiceException( "groupId cannot be null", 400, null );
654 if ( StringUtils.isEmpty( projectId ) )
656 throw new ArchivaRestServiceException( "artifactId cannot be null", 400, null );
659 if ( StringUtils.isEmpty( version ) )
661 throw new ArchivaRestServiceException( "version cannot be null", 400, null );
664 RepositorySession repositorySession = null;
667 repositorySession = repositorySessionFactory.createSession();
669 catch ( MetadataRepositoryException e )
671 e.printStackTrace( );
676 ManagedRepositoryContent repository = getManagedRepositoryContent( repositoryId );
677 BaseRepositoryContentLayout layout = repository.getLayout( BaseRepositoryContentLayout.class );
679 ArchivaItemSelector selector = ArchivaItemSelector.builder( )
680 .withNamespace( namespace )
681 .withProjectId( projectId )
682 .withVersion( version )
684 Version versionItem = layout.getVersion( selector );
685 if (versionItem!=null && versionItem.exists()) {
686 repository.deleteItem( versionItem );
689 MetadataRepository metadataRepository = repositorySession.getRepository();
691 Collection<ArtifactMetadata> artifacts =
692 metadataRepository.getArtifacts(repositorySession , repositoryId, namespace, projectId, version );
694 for ( ArtifactMetadata artifactMetadata : artifacts )
696 metadataRepository.removeTimestampedArtifact(repositorySession , artifactMetadata, version );
699 metadataRepository.removeProjectVersion(repositorySession , repositoryId, namespace, projectId, version );
701 catch ( MetadataRepositoryException | MetadataResolutionException | RepositoryException | ItemNotFoundException | LayoutException e )
703 throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
709 repositorySession.save();
710 } catch (MetadataSessionException e) {
711 log.error("Session save failed {}", e.getMessage());
714 repositorySession.close();
718 return ActionStatus.SUCCESS;
722 public ActionStatus deleteArtifact( Artifact artifact )
723 throws ArchivaRestServiceException
726 String repositoryId = artifact.getContext();
727 // some rest call can use context or repositoryId
729 if ( StringUtils.isEmpty( repositoryId ) )
731 repositoryId = artifact.getRepositoryId();
733 if ( StringUtils.isEmpty( repositoryId ) )
735 throw new ArchivaRestServiceException( "repositoryId cannot be null", 400, null );
738 if ( !getPermissionStatus( repositoryId ).isAuthorizedToDeleteArtifacts() )
740 throw new ArchivaRestServiceException( "not authorized to delete artifacts", 403, null );
743 if ( artifact == null )
745 throw new ArchivaRestServiceException( "artifact cannot be null", 400, null );
748 if ( StringUtils.isEmpty( artifact.getGroupId() ) )
750 throw new ArchivaRestServiceException( "artifact.groupId cannot be null", 400, null );
753 if ( StringUtils.isEmpty( artifact.getArtifactId() ) )
755 throw new ArchivaRestServiceException( "artifact.artifactId cannot be null", 400, null );
758 // TODO more control on artifact fields
760 boolean snapshotVersion =
761 VersionUtil.isSnapshot( artifact.getVersion() ) | VersionUtil.isGenericSnapshot( artifact.getVersion() );
762 String baseVersion = VersionUtil.getBaseVersion( artifact.getVersion( ) );
764 RepositorySession repositorySession = null;
767 repositorySession = repositorySessionFactory.createSession();
769 catch ( MetadataRepositoryException e )
771 e.printStackTrace( );
775 Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
777 TimeZone timezone = TimeZone.getTimeZone( "UTC" );
778 DateFormat fmt = new SimpleDateFormat( "yyyyMMdd.HHmmss" );
779 fmt.setTimeZone( timezone );
780 ManagedRepository repo = repositoryRegistry.getManagedRepository( repositoryId );
782 ManagedRepositoryContent repository = getManagedRepositoryContent( repositoryId );
783 BaseRepositoryContentLayout layout = repository.getLayout( BaseRepositoryContentLayout.class );
785 ArchivaItemSelector versionSelector = ArchivaItemSelector.builder( ).withNamespace( artifact.getGroupId( ) )
786 .withProjectId( artifact.getArtifactId( ) )
787 .withVersion( baseVersion ).build( );
789 Version version1 = layout.getVersion( versionSelector );
790 String path = repository.toPath( version1 );
792 ArchivaItemSelector selector = ArchivaItemSelector.builder( )
793 .withNamespace( artifact.getGroupId( ) )
794 .withProjectId( artifact.getArtifactId( ) )
795 .withVersion( baseVersion )
796 .withClassifier( artifact.getClassifier( ) )
797 .withArtifactId( artifact.getArtifactId( ) )
798 .withType( artifact.getType( ) )
799 .includeRelatedArtifacts()
802 MetadataRepository metadataRepository = repositorySession.getRepository();
804 if ( StringUtils.isNotBlank( artifact.getClassifier() ) )
806 if ( StringUtils.isBlank( artifact.getPackaging() ) )
808 throw new ArchivaRestServiceException( "You must configure a type/packaging when using classifier",
811 List<? extends org.apache.archiva.repository.content.Artifact> artifactItems = layout.getArtifacts( selector );
812 for ( org.apache.archiva.repository.content.Artifact aRef : artifactItems ) {
815 repository.deleteItem( aRef );
817 catch ( ItemNotFoundException e )
819 log.error( "Could not delete item, seems to be deleted by other thread. {}, {} ", aRef, e.getMessage( ) );
827 int index = path.lastIndexOf( '/' );
828 path = path.substring( 0, index );
829 StorageAsset targetPath = repo.getAsset( path );
831 if ( !targetPath.exists() )
833 //throw new ContentNotFoundException(
834 // artifact.getNamespace() + ":" + artifact.getArtifactId() + ":" + artifact.getVersion() );
835 log.warn( "targetPath {} not found skip file deletion", targetPath );
836 return ActionStatus.FAIL;
839 // TODO: this should be in the storage mechanism so that it is all tied together
840 // delete from file system
841 if ( !snapshotVersion && version1.exists() )
845 repository.deleteItem( version1 );
847 catch ( ItemNotFoundException e )
849 log.error( "Could not delete version item {}", e.getMessage( ) );
854 // We are deleting all version related artifacts for a snapshot version
855 for ( org.apache.archiva.repository.content.Artifact delArtifact : layout.getArtifacts( selector )) {
858 repository.deleteItem( delArtifact );
860 catch ( ItemNotFoundException e )
862 log.warn( "Artifact that should be deleted, was not found: {}", delArtifact );
866 StorageAsset metadataFile = getMetadata( repo, targetPath.getPath() );
867 ArchivaRepositoryMetadata metadata = getMetadata( repository.getRepository().getType(), metadataFile );
868 updateMetadata( metadata, metadataFile, lastUpdatedTimestamp, artifact );
871 Collection<ArtifactMetadata> artifacts = Collections.emptyList();
873 if ( snapshotVersion )
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();
992 return ActionStatus.SUCCESS;
996 public ActionStatus 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 ( !getPermissionStatus( repositoryId ).isAuthorizedToDeleteArtifacts() )
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();
1062 return ActionStatus.SUCCESS;
1066 public ActionStatus 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 ( !getPermissionStatus( repositoryId ).isAuthorizedToDeleteArtifacts() )
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();
1142 return ActionStatus.SUCCESS;
1147 public PermissionStatus getPermissionStatus( String repoId )
1148 throws ArchivaRestServiceException
1151 getAuditInformation().getUser() == null ? "guest" : getAuditInformation().getUser().getUsername();
1155 return new PermissionStatus( 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;