1 package org.apache.archiva.admin.repository.managed;
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
21 import org.apache.archiva.admin.model.AuditInformation;
22 import org.apache.archiva.admin.model.RepositoryAdminException;
23 import org.apache.archiva.admin.model.beans.ManagedRepository;
24 import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin;
25 import org.apache.archiva.admin.repository.AbstractRepositoryAdmin;
26 import org.apache.archiva.configuration.*;
27 import org.apache.archiva.indexer.ArchivaIndexManager;
28 import org.apache.archiva.indexer.IndexManagerFactory;
29 import org.apache.archiva.indexer.IndexUpdateFailedException;
30 import org.apache.archiva.metadata.model.facets.AuditEvent;
31 import org.apache.archiva.metadata.repository.MetadataRepository;
32 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
33 import org.apache.archiva.metadata.repository.RepositorySession;
34 import org.apache.archiva.metadata.repository.RepositorySessionFactory;
35 import org.apache.archiva.metadata.repository.stats.model.RepositoryStatisticsManager;
36 import org.apache.archiva.redback.components.cache.Cache;
37 import org.apache.archiva.redback.components.registry.RegistryException;
38 import org.apache.archiva.redback.components.taskqueue.TaskQueueException;
39 import org.apache.archiva.redback.role.RoleManager;
40 import org.apache.archiva.redback.role.RoleManagerException;
41 import org.apache.archiva.repository.ReleaseScheme;
42 import org.apache.archiva.repository.RepositoryException;
43 import org.apache.archiva.repository.RepositoryRegistry;
44 import org.apache.archiva.repository.features.ArtifactCleanupFeature;
45 import org.apache.archiva.repository.features.IndexCreationFeature;
46 import org.apache.archiva.repository.features.StagingRepositoryFeature;
47 import org.apache.archiva.scheduler.repository.model.RepositoryArchivaTaskScheduler;
48 import org.apache.archiva.scheduler.repository.model.RepositoryTask;
49 import org.apache.archiva.security.common.ArchivaRoleConstants;
50 import org.apache.commons.lang.StringUtils;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53 import org.springframework.stereotype.Service;
55 import javax.annotation.PostConstruct;
56 import javax.annotation.PreDestroy;
57 import javax.inject.Inject;
58 import javax.inject.Named;
59 import java.io.IOException;
60 import java.nio.file.Path;
61 import java.nio.file.Paths;
62 import java.util.ArrayList;
63 import java.util.Collection;
64 import java.util.List;
66 import java.util.stream.Collectors;
69 * FIXME review the staging mechanism to have a per user session one
71 * @author Olivier Lamy
73 @Service("managedRepositoryAdmin#default")
74 public class DefaultManagedRepositoryAdmin
75 extends AbstractRepositoryAdmin
76 implements ManagedRepositoryAdmin
79 private Logger log = LoggerFactory.getLogger( getClass() );
81 public static final String STAGE_REPO_ID_END = "-stage";
85 private RepositoryRegistry repositoryRegistry;
88 @Named(value = "archivaTaskScheduler#repository")
89 private RepositoryArchivaTaskScheduler repositoryTaskScheduler;
92 * FIXME: this could be multiple implementations and needs to be configured.
95 private RepositorySessionFactory repositorySessionFactory;
98 private RepositoryStatisticsManager repositoryStatisticsManager;
101 protected RoleManager roleManager;
104 @Named(value = "cache#namespaces")
105 private Cache<String, Collection<String>> namespacesCache;
108 private IndexManagerFactory indexManagerFactory;
114 public void initialize()
115 throws RepositoryAdminException, RoleManagerException
117 // initialize index context on start and check roles here
118 for ( ManagedRepository managedRepository : getManagedRepositories() )
120 log.debug("Initializating {}", managedRepository.getId());
121 addRepositoryRoles( managedRepository.getId() );
127 public void shutdown()
128 throws RepositoryAdminException
133 * Conversion between the repository from the registry and the serialized DTO for the admin API
135 private ManagedRepository convertRepo( org.apache.archiva.repository.ManagedRepository repo ) {
139 ManagedRepository adminRepo = new ManagedRepository( getArchivaConfiguration().getDefaultLocale() );
140 setBaseRepoAttributes( adminRepo, repo );
141 adminRepo.setLocation( convertUriToString( repo.getLocation()) );
142 adminRepo.setReleases(repo.getActiveReleaseSchemes().contains( ReleaseScheme.RELEASE ));
143 adminRepo.setSnapshots( repo.getActiveReleaseSchemes().contains(ReleaseScheme.SNAPSHOT) );
144 adminRepo.setBlockRedeployments( repo.blocksRedeployments() );
145 adminRepo.setCronExpression( repo.getSchedulingDefinition() );
146 if (repo.supportsFeature( IndexCreationFeature.class )) {
147 IndexCreationFeature icf = repo.getFeature( IndexCreationFeature.class ).get();
148 adminRepo.setIndexDirectory(convertUriToString( icf.getIndexPath() ));
149 adminRepo.setSkipPackedIndexCreation( icf.isSkipPackedIndexCreation() );
151 adminRepo.setScanned( repo.isScanned() );
152 if (repo.supportsFeature( ArtifactCleanupFeature.class) ) {
153 ArtifactCleanupFeature acf = repo.getFeature( ArtifactCleanupFeature.class ).get();
154 adminRepo.setRetentionPeriod( acf.getRetentionPeriod().getDays() );
155 adminRepo.setRetentionCount( acf.getRetentionCount() );
156 adminRepo.setDeleteReleasedSnapshots( acf.isDeleteReleasedSnapshots() );
159 if (repo.supportsFeature( StagingRepositoryFeature.class )) {
160 StagingRepositoryFeature stf = repo.getFeature( StagingRepositoryFeature.class ).get();
161 adminRepo.setStageRepoNeeded( stf.isStageRepoNeeded() );
162 if (stf.getStagingRepository()!=null) {
163 adminRepo.setStagingRepository( convertRepo( stf.getStagingRepository() ) );
169 private ManagedRepositoryConfiguration getRepositoryConfiguration(ManagedRepository repo) {
170 ManagedRepositoryConfiguration repoConfig = new ManagedRepositoryConfiguration();
171 setBaseRepoAttributes( repoConfig, repo );
172 repoConfig.setBlockRedeployments( repo.isBlockRedeployments( ) );
173 repoConfig.setReleases( repo.isReleases() );
174 repoConfig.setSnapshots( repo.isSnapshots() );
175 repoConfig.setScanned( repo.isScanned() );
176 repoConfig.setLocation( getRepositoryCommonValidator().removeExpressions( repo.getLocation() ) );
177 repoConfig.setRefreshCronExpression( repo.getCronExpression() );
178 repoConfig.setRetentionPeriod( repo.getRetentionPeriod() );
179 repoConfig.setRetentionCount( repo.getRetentionCount());
180 repoConfig.setDeleteReleasedSnapshots( repo.isDeleteReleasedSnapshots() );
181 repoConfig.setSkipPackedIndexCreation( repo.isSkipPackedIndexCreation());
182 repoConfig.setStageRepoNeeded( repo.isStageRepoNeeded() );
187 public List<ManagedRepository> getManagedRepositories()
188 throws RepositoryAdminException
191 return repositoryRegistry.getManagedRepositories().stream().map( rep -> this.convertRepo( rep ) ).collect( Collectors.toList());
195 public Map<String, ManagedRepository> getManagedRepositoriesAsMap()
196 throws RepositoryAdminException
198 return repositoryRegistry.getManagedRepositories().stream().collect( Collectors.toMap( e -> e.getId(), e -> convertRepo( e ) ) );
202 public ManagedRepository getManagedRepository( String repositoryId )
203 throws RepositoryAdminException
205 return convertRepo( repositoryRegistry.getManagedRepository( repositoryId ) );
209 public Boolean addManagedRepository( ManagedRepository managedRepository, boolean needStageRepo,
210 AuditInformation auditInformation )
211 throws RepositoryAdminException
213 log.debug("addManagedRepository {}, {}, {}", managedRepository.getId(), needStageRepo, auditInformation);
215 getRepositoryCommonValidator().basicValidation( managedRepository, false );
216 getRepositoryCommonValidator().validateManagedRepository( managedRepository );
217 triggerAuditEvent( managedRepository.getId(), null, AuditEvent.ADD_MANAGED_REPO, auditInformation );
218 ManagedRepositoryConfiguration repoConfig = getRepositoryConfiguration( managedRepository );
220 repoConfig.setStageRepoNeeded( true );
222 Configuration configuration = getArchivaConfiguration().getConfiguration();
225 org.apache.archiva.repository.ManagedRepository newRepo = repositoryRegistry.putRepository( repoConfig, configuration );
226 log.debug("Added new repository {}", newRepo.getId());
227 org.apache.archiva.repository.ManagedRepository stagingRepo = null;
228 addRepositoryRoles( newRepo.getId() );
229 if ( newRepo.supportsFeature( StagingRepositoryFeature.class )) {
230 StagingRepositoryFeature stf = newRepo.getFeature( StagingRepositoryFeature.class ).get();
231 stagingRepo = stf.getStagingRepository();
232 if (stf.isStageRepoNeeded() && stagingRepo != null) {
233 addRepositoryRoles( stagingRepo.getId() );
234 triggerAuditEvent( stagingRepo.getId(), null, AuditEvent.ADD_MANAGED_REPO, auditInformation );
237 saveConfiguration( configuration );
238 //MRM-1342 Repository statistics report doesn't appear to be working correctly
239 //scan repository when adding of repository is successful
242 if ( newRepo.isScanned())
244 scanRepository( newRepo.getId(), true );
247 if ( stagingRepo!=null && stagingRepo.isScanned() )
249 scanRepository( stagingRepo.getId(), true );
252 catch ( Exception e )
254 log.warn("Unable to scan repository [{}]: {}", newRepo.getId(), e.getMessage(), e);
257 catch ( RepositoryException e )
259 log.error("Could not add managed repository {}"+managedRepository);
260 throw new RepositoryAdminException( "Could not add repository "+e.getMessage() );
262 catch ( RoleManagerException e )
264 log.error("Could not add repository roles for repository [{}]: {}", managedRepository.getId(), e.getMessage(), e);
265 throw new RepositoryAdminException( "Could not add roles to repository "+e.getMessage() );
274 public Boolean deleteManagedRepository( String repositoryId, AuditInformation auditInformation,
275 boolean deleteContent )
276 throws RepositoryAdminException
278 Configuration config = getArchivaConfiguration().getConfiguration();
279 ManagedRepositoryConfiguration repoConfig=config.findManagedRepositoryById( repositoryId );
280 if (repoConfig!=null) {
282 log.debug("Repo location " + repoConfig.getLocation());
284 org.apache.archiva.repository.ManagedRepository repo = repositoryRegistry.getManagedRepository(repositoryId);
285 org.apache.archiva.repository.ManagedRepository stagingRepository = null;
288 if (repo.supportsFeature(StagingRepositoryFeature.class)) {
289 stagingRepository = repo.getFeature(StagingRepositoryFeature.class).get().getStagingRepository();
291 repositoryRegistry.removeRepository(repo, config);
292 } catch (RepositoryException e) {
293 log.error("Removal of repository {} failed: {}", repositoryId, e.getMessage(), e);
294 throw new RepositoryAdminException("Removal of repository " + repositoryId + " failed.");
297 throw new RepositoryAdminException("A repository with that id does not exist");
300 triggerAuditEvent(repositoryId, null, AuditEvent.DELETE_MANAGED_REPO, auditInformation);
301 if (repoConfig != null) {
302 deleteManagedRepository(repoConfig, deleteContent, config, false);
306 // stage repo exists ?
307 if (stagingRepository != null) {
308 // do not trigger event when deleting the staged one
309 ManagedRepositoryConfiguration stagingRepositoryConfig = config.findManagedRepositoryById(stagingRepository.getId());
311 repositoryRegistry.removeRepository(stagingRepository);
312 if (stagingRepositoryConfig != null) {
313 deleteManagedRepository(stagingRepositoryConfig, deleteContent, config, true);
315 } catch (RepositoryException e) {
316 log.error("Removal of staging repository {} failed: {}", stagingRepository.getId(), e.getMessage(), e);
321 saveConfiguration(config);
322 } catch (Exception e) {
323 throw new RepositoryAdminException("Error saving configuration for delete action" + e.getMessage(), e);
328 return Boolean.FALSE;
332 private Boolean deleteManagedRepository( ManagedRepositoryConfiguration repository, boolean deleteContent,
333 Configuration config, boolean stagedOne )
334 throws RepositoryAdminException
339 RepositorySession repositorySession = getRepositorySessionFactory().createSession();
342 MetadataRepository metadataRepository = repositorySession.getRepository();
343 metadataRepository.removeRepository( repository.getId() );
345 namespacesCache.remove( repository.getId() );
346 log.debug( "call repositoryStatisticsManager.deleteStatistics" );
347 getRepositoryStatisticsManager().deleteStatistics( metadataRepository, repository.getId() );
348 repositorySession.save();
350 catch ( MetadataRepositoryException e )
352 //throw new RepositoryAdminException( e.getMessage(), e );
353 log.warn( "skip error during removing repository from MetadataRepository:{}", e.getMessage(), e );
357 repositorySession.close();
363 // TODO could be async ? as directory can be huge
364 Path dir = Paths.get( repository.getLocation() );
365 org.apache.archiva.common.utils.FileUtils.deleteQuietly( dir );
368 // olamy: copy list for reading as a unit test in webapp fail with ConcurrentModificationException
369 List<ProxyConnectorConfiguration> proxyConnectors = new ArrayList<>( config.getProxyConnectors() );
370 for ( ProxyConnectorConfiguration proxyConnector : proxyConnectors )
372 if ( StringUtils.equals( proxyConnector.getSourceRepoId(), repository.getId() ) )
374 config.removeProxyConnector( proxyConnector );
378 Map<String, List<String>> repoToGroupMap = config.getRepositoryToGroupMap();
379 if ( repoToGroupMap != null )
381 if ( repoToGroupMap.containsKey( repository.getId() ) )
383 List<String> repoGroups = repoToGroupMap.get( repository.getId() );
384 for ( String repoGroup : repoGroups )
386 // copy to prevent UnsupportedOperationException
387 RepositoryGroupConfiguration repositoryGroupConfiguration =
388 config.findRepositoryGroupById( repoGroup );
389 List<String> repos = new ArrayList<>( repositoryGroupConfiguration.getRepositories() );
390 config.removeRepositoryGroup( repositoryGroupConfiguration );
391 repos.remove( repository.getId() );
392 repositoryGroupConfiguration.setRepositories( repos );
393 config.addRepositoryGroup( repositoryGroupConfiguration );
400 removeRepositoryRoles( repository );
402 catch ( RoleManagerException e )
404 throw new RepositoryAdminException(
405 "fail to remove repository roles for repository " + repository.getId() + " : " + e.getMessage(), e );
409 final RepositoryRegistry reg = getRepositoryRegistry();
410 if (reg.getManagedRepository(repository.getId())!=null) {
411 reg.removeRepository(reg.getManagedRepository(repository.getId()));
413 } catch (RepositoryException e) {
414 throw new RepositoryAdminException("Removal of repository "+repository.getId()+ " failed: "+e.getMessage());
417 saveConfiguration( config );
422 ArchivaIndexManager getIndexManager(ManagedRepository managedRepository) {
423 org.apache.archiva.repository.ManagedRepository repo = getRepositoryRegistry().getManagedRepository(managedRepository.getId());
424 return indexManagerFactory.getIndexManager(repo.getType());
428 public Boolean updateManagedRepository( ManagedRepository managedRepository, boolean needStageRepo,
429 AuditInformation auditInformation, boolean resetStats )
430 throws RepositoryAdminException
433 log.debug( "updateManagedConfiguration repo {} needStage {} resetStats {} ", managedRepository, needStageRepo,
436 // Ensure that the fields are valid.
438 getRepositoryCommonValidator().basicValidation( managedRepository, true );
440 getRepositoryCommonValidator().validateManagedRepository( managedRepository );
442 Configuration configuration = getArchivaConfiguration().getConfiguration();
444 ManagedRepositoryConfiguration updatedRepoConfig = getRepositoryConfiguration( managedRepository );
445 updatedRepoConfig.setStageRepoNeeded( needStageRepo );
447 org.apache.archiva.repository.ManagedRepository oldRepo = repositoryRegistry.getManagedRepository( managedRepository.getId( ) );
448 boolean stagingExists = false;
449 if (oldRepo.supportsFeature( StagingRepositoryFeature.class ) ){
450 stagingExists = oldRepo.getFeature( StagingRepositoryFeature.class ).get().getStagingRepository() != null;
452 boolean updateIndexContext = !StringUtils.equals( updatedRepoConfig.getIndexDir(), managedRepository.getIndexDirectory() );
453 org.apache.archiva.repository.ManagedRepository newRepo;
454 // TODO remove content from old if path has changed !!!!!
457 newRepo = repositoryRegistry.putRepository( updatedRepoConfig, configuration );
458 if (newRepo.supportsFeature( StagingRepositoryFeature.class )) {
459 org.apache.archiva.repository.ManagedRepository stagingRepo = newRepo.getFeature( StagingRepositoryFeature.class ).get( ).getStagingRepository( );
460 if (stagingRepo!=null && !stagingExists)
462 triggerAuditEvent( stagingRepo.getId(), null, AuditEvent.ADD_MANAGED_REPO, auditInformation );
463 addRepositoryRoles( stagingRepo.getId( ) );
469 catch ( RepositoryException e )
471 log.error("Could not update repository {}: {}", managedRepository.getId(), e.getMessage(), e);
472 throw new RepositoryAdminException( "Could not update repository "+managedRepository.getId());
474 catch ( RoleManagerException e ) {
475 log.error("Error during role update of stage repo {}", managedRepository.getId(), e);
476 throw new RepositoryAdminException( "Could not update repository "+managedRepository.getId());
478 triggerAuditEvent( managedRepository.getId(), null, AuditEvent.MODIFY_MANAGED_REPO,
482 getArchivaConfiguration().save(configuration);
484 catch ( RegistryException | IndeterminateConfigurationException e )
486 log.error("Could not save repository configuration: {}", e.getMessage(), e);
487 throw new RepositoryAdminException( "Could not save repository configuration: "+e.getMessage() );
490 // Save the repository configuration.
491 RepositorySession repositorySession = getRepositorySessionFactory().createSession();
498 log.debug( "call repositoryStatisticsManager.deleteStatistics" );
499 getRepositoryStatisticsManager().deleteStatistics( repositorySession.getRepository(),
500 managedRepository.getId() );
501 repositorySession.save();
505 catch ( MetadataRepositoryException e )
507 throw new RepositoryAdminException( e.getMessage(), e );
511 repositorySession.close();
514 if ( updateIndexContext )
519 repositoryRegistry.resetIndexingContext(newRepo);
520 } catch (IndexUpdateFailedException e) {
528 //--------------------------
530 //--------------------------
533 protected void addRepository( ManagedRepositoryConfiguration repository, Configuration configuration )
534 throws RepositoryAdminException, IOException
538 getRepositoryRegistry().putRepository( repository, configuration );
540 catch ( RepositoryException e )
542 throw new RepositoryAdminException( "Could not add the repository to the registry. Cause: "+e.getMessage() );
548 public Boolean scanRepository( String repositoryId, boolean fullScan )
550 if ( getRepositoryTaskScheduler().isProcessingRepositoryTask( repositoryId ) )
552 log.info( "scanning of repository with id {} already scheduled", repositoryId );
554 RepositoryTask task = new RepositoryTask();
555 task.setRepositoryId( repositoryId );
556 task.setScanAll( fullScan );
559 getRepositoryTaskScheduler().queueTask( task );
561 catch ( TaskQueueException e )
563 log.error( "failed to schedule scanning of repo with id {}", repositoryId, e );
570 private void addRepositoryRoles( String repoId )
571 throws RoleManagerException
573 // TODO: double check these are configured on start up
574 // TODO: belongs in the business logic
576 if ( !getRoleManager().templatedRoleExists( ArchivaRoleConstants.TEMPLATE_REPOSITORY_OBSERVER, repoId ) )
578 getRoleManager().createTemplatedRole( ArchivaRoleConstants.TEMPLATE_REPOSITORY_OBSERVER, repoId );
581 if ( !getRoleManager().templatedRoleExists( ArchivaRoleConstants.TEMPLATE_REPOSITORY_MANAGER, repoId ) )
583 getRoleManager().createTemplatedRole( ArchivaRoleConstants.TEMPLATE_REPOSITORY_MANAGER, repoId );
587 protected void removeRepositoryRoles( ManagedRepositoryConfiguration existingRepository )
588 throws RoleManagerException
590 String repoId = existingRepository.getId();
592 if ( getRoleManager().templatedRoleExists( ArchivaRoleConstants.TEMPLATE_REPOSITORY_MANAGER, repoId ) )
594 getRoleManager().removeTemplatedRole( ArchivaRoleConstants.TEMPLATE_REPOSITORY_MANAGER, repoId );
597 if ( getRoleManager().templatedRoleExists( ArchivaRoleConstants.TEMPLATE_REPOSITORY_OBSERVER, repoId ) )
599 getRoleManager().removeTemplatedRole( ArchivaRoleConstants.TEMPLATE_REPOSITORY_OBSERVER, repoId );
602 log.debug( "removed user roles associated with repository {}", repoId );
605 //--------------------------
607 //--------------------------
610 public RoleManager getRoleManager()
615 public void setRoleManager( RoleManager roleManager )
617 this.roleManager = roleManager;
620 public RepositoryStatisticsManager getRepositoryStatisticsManager()
622 return repositoryStatisticsManager;
625 public void setRepositoryStatisticsManager( RepositoryStatisticsManager repositoryStatisticsManager )
627 this.repositoryStatisticsManager = repositoryStatisticsManager;
630 public RepositorySessionFactory getRepositorySessionFactory()
632 return repositorySessionFactory;
635 public void setRepositorySessionFactory( RepositorySessionFactory repositorySessionFactory )
637 this.repositorySessionFactory = repositorySessionFactory;
641 public RepositoryArchivaTaskScheduler getRepositoryTaskScheduler()
643 return repositoryTaskScheduler;
646 public void setRepositoryTaskScheduler( RepositoryArchivaTaskScheduler repositoryTaskScheduler )
648 this.repositoryTaskScheduler = repositoryTaskScheduler;
652 public RepositoryRegistry getRepositoryRegistry( )
654 return repositoryRegistry;
657 public void setRepositoryRegistry( RepositoryRegistry repositoryRegistry )
659 this.repositoryRegistry = repositoryRegistry;