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.Configuration;
27 import org.apache.archiva.configuration.IndeterminateConfigurationException;
28 import org.apache.archiva.configuration.ManagedRepositoryConfiguration;
29 import org.apache.archiva.configuration.ProxyConnectorConfiguration;
30 import org.apache.archiva.configuration.RepositoryGroupConfiguration;
31 import org.apache.archiva.indexer.ArchivaIndexManager;
32 import org.apache.archiva.indexer.IndexManagerFactory;
33 import org.apache.archiva.indexer.IndexUpdateFailedException;
34 import org.apache.archiva.metadata.model.facets.AuditEvent;
35 import org.apache.archiva.metadata.repository.*;
36 import org.apache.archiva.metadata.repository.stats.model.RepositoryStatisticsManager;
37 import org.apache.archiva.components.cache.Cache;
38 import org.apache.archiva.components.registry.RegistryException;
39 import org.apache.archiva.components.taskqueue.TaskQueueException;
40 import org.apache.archiva.redback.role.RoleManager;
41 import org.apache.archiva.redback.role.RoleManagerException;
42 import org.apache.archiva.repository.ReleaseScheme;
43 import org.apache.archiva.repository.Repository;
44 import org.apache.archiva.repository.RepositoryException;
45 import org.apache.archiva.repository.RepositoryRegistry;
46 import org.apache.archiva.repository.base.group.RepositoryGroupHandler;
47 import org.apache.archiva.repository.base.managed.ManagedRepositoryHandler;
48 import org.apache.archiva.repository.features.ArtifactCleanupFeature;
49 import org.apache.archiva.repository.features.IndexCreationFeature;
50 import org.apache.archiva.repository.features.StagingRepositoryFeature;
51 import org.apache.archiva.scheduler.repository.model.RepositoryArchivaTaskScheduler;
52 import org.apache.archiva.scheduler.repository.model.RepositoryTask;
53 import org.apache.archiva.security.common.ArchivaRoleConstants;
54 import org.apache.commons.lang3.StringUtils;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57 import org.springframework.stereotype.Service;
59 import javax.annotation.PostConstruct;
60 import javax.annotation.PreDestroy;
61 import javax.inject.Inject;
62 import javax.inject.Named;
63 import java.io.IOException;
64 import java.nio.file.Path;
65 import java.nio.file.Paths;
66 import java.util.ArrayList;
67 import java.util.Collection;
68 import java.util.List;
70 import java.util.stream.Collectors;
73 * FIXME review the staging mechanism to have a per user session one
75 * @author Olivier Lamy
77 @Service("managedRepositoryAdmin#default")
78 public class DefaultManagedRepositoryAdmin
79 extends AbstractRepositoryAdmin
80 implements ManagedRepositoryAdmin
83 private Logger log = LoggerFactory.getLogger( getClass() );
85 public static final String STAGE_REPO_ID_END = "-stage";
89 private RepositoryRegistry repositoryRegistry;
92 private ManagedRepositoryHandler managedRepositoryHandler;
95 private RepositoryGroupHandler repositoryGroupHandler;
98 @Named(value = "archivaTaskScheduler#repository")
99 private RepositoryArchivaTaskScheduler repositoryTaskScheduler;
102 * FIXME: this could be multiple implementations and needs to be configured.
105 private RepositorySessionFactory repositorySessionFactory;
108 private RepositoryStatisticsManager repositoryStatisticsManager;
111 protected RoleManager roleManager;
114 @Named(value = "cache#namespaces")
115 private Cache<String, Collection<String>> namespacesCache;
118 private IndexManagerFactory indexManagerFactory;
124 public void initialize()
125 throws RepositoryAdminException, RoleManagerException
127 // initialize index context on start and check roles here
128 for ( ManagedRepository managedRepository : getManagedRepositories() )
130 log.debug("Initializating {}", managedRepository.getId());
131 addRepositoryRoles( managedRepository.getId() );
137 public void shutdown()
138 throws RepositoryAdminException
143 * Conversion between the repository from the registry and the serialized DTO for the admin API
145 private ManagedRepository convertRepo( org.apache.archiva.repository.ManagedRepository repo ) {
149 ManagedRepository adminRepo = new ManagedRepository( getArchivaConfiguration().getDefaultLocale() );
150 setBaseRepoAttributes( adminRepo, repo );
151 adminRepo.setLocation( convertUriToString( repo.getLocation()) );
152 adminRepo.setReleases(repo.getActiveReleaseSchemes().contains( ReleaseScheme.RELEASE ));
153 adminRepo.setSnapshots( repo.getActiveReleaseSchemes().contains(ReleaseScheme.SNAPSHOT) );
154 adminRepo.setBlockRedeployments( repo.blocksRedeployments() );
155 adminRepo.setCronExpression( repo.getSchedulingDefinition() );
156 if (repo.supportsFeature( IndexCreationFeature.class )) {
157 IndexCreationFeature icf = repo.getFeature( IndexCreationFeature.class ).get();
158 adminRepo.setSkipPackedIndexCreation( icf.isSkipPackedIndexCreation() );
160 adminRepo.setScanned( repo.isScanned() );
161 if (repo.supportsFeature( ArtifactCleanupFeature.class) ) {
162 ArtifactCleanupFeature acf = repo.getFeature( ArtifactCleanupFeature.class ).get();
163 adminRepo.setRetentionPeriod( acf.getRetentionPeriod().getDays() );
164 adminRepo.setRetentionCount( acf.getRetentionCount() );
165 adminRepo.setDeleteReleasedSnapshots( acf.isDeleteReleasedSnapshots() );
168 if (repo.supportsFeature( StagingRepositoryFeature.class )) {
169 StagingRepositoryFeature stf = repo.getFeature( StagingRepositoryFeature.class ).get();
170 adminRepo.setStageRepoNeeded( stf.isStageRepoNeeded() );
171 if (stf.getStagingRepository()!=null) {
172 adminRepo.setStagingRepository( convertRepo( stf.getStagingRepository() ) );
178 private ManagedRepositoryConfiguration getRepositoryConfiguration(ManagedRepository repo) {
179 ManagedRepositoryConfiguration repoConfig = new ManagedRepositoryConfiguration();
180 setBaseRepoAttributes( repoConfig, repo );
181 repoConfig.setBlockRedeployments( repo.isBlockRedeployments( ) );
182 repoConfig.setReleases( repo.isReleases() );
183 repoConfig.setSnapshots( repo.isSnapshots() );
184 repoConfig.setScanned( repo.isScanned() );
185 repoConfig.setLocation( getRepositoryCommonValidator().removeExpressions( repo.getLocation() ) );
186 repoConfig.setRefreshCronExpression( repo.getCronExpression() );
187 repoConfig.setRetentionPeriod( repo.getRetentionPeriod() );
188 repoConfig.setRetentionCount( repo.getRetentionCount());
189 repoConfig.setDeleteReleasedSnapshots( repo.isDeleteReleasedSnapshots() );
190 repoConfig.setSkipPackedIndexCreation( repo.isSkipPackedIndexCreation());
191 repoConfig.setStageRepoNeeded( repo.isStageRepoNeeded() );
197 public List<ManagedRepository> getManagedRepositories()
198 throws RepositoryAdminException
201 return repositoryRegistry.getManagedRepositories().stream().map( rep -> this.convertRepo( rep ) ).collect( Collectors.toList());
205 public Map<String, ManagedRepository> getManagedRepositoriesAsMap()
206 throws RepositoryAdminException
208 return repositoryRegistry.getManagedRepositories().stream().collect( Collectors.toMap( e -> e.getId(), e -> convertRepo( e ) ) );
212 public ManagedRepository getManagedRepository( String repositoryId )
213 throws RepositoryAdminException
215 return convertRepo( repositoryRegistry.getManagedRepository( repositoryId ) );
219 public Boolean addManagedRepository( ManagedRepository managedRepository, boolean needStageRepo,
220 AuditInformation auditInformation )
221 throws RepositoryAdminException
223 log.debug("addManagedRepository {}, {}, {}", managedRepository.getId(), needStageRepo, auditInformation);
225 getRepositoryCommonValidator().basicValidation( managedRepository, false );
226 getRepositoryCommonValidator().validateManagedRepository( managedRepository );
227 triggerAuditEvent( managedRepository.getId(), null, AuditEvent.ADD_MANAGED_REPO, auditInformation );
228 ManagedRepositoryConfiguration repoConfig = getRepositoryConfiguration( managedRepository );
230 repoConfig.setStageRepoNeeded( true );
232 Configuration configuration = getArchivaConfiguration().getConfiguration();
235 org.apache.archiva.repository.ManagedRepository newRepo = repositoryRegistry.putRepository( repoConfig );
236 log.debug("Added new repository {}", newRepo.getId());
237 addRepositoryRoles( newRepo.getId() );
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 org.apache.archiva.repository.ManagedRepository stagingRepo = newRepo.getFeature( StagingRepositoryFeature.class ).get( ).getStagingRepository( );
248 if ( stagingRepo!=null)
250 if (stagingRepo.isScanned()) {
251 scanRepository( stagingRepo.getId(), true );
253 addRepositoryRoles( stagingRepo.getId( ) );
256 catch ( Exception e )
258 log.warn("Unable to scan repository [{}]: {}", newRepo.getId(), e.getMessage(), e);
261 catch ( RepositoryException e )
263 log.error("Could not add managed repository {}"+managedRepository);
264 throw new RepositoryAdminException( "Could not add repository "+e.getMessage() );
266 catch ( RoleManagerException e )
268 log.error("Could not add repository roles for repository [{}]: {}", managedRepository.getId(), e.getMessage(), e);
269 throw new RepositoryAdminException( "Could not add roles to repository "+e.getMessage() );
278 public Boolean deleteManagedRepository( String repositoryId, AuditInformation auditInformation,
279 boolean deleteContent )
280 throws RepositoryAdminException
282 Configuration config = getArchivaConfiguration().getConfiguration();
283 ManagedRepositoryConfiguration repoConfig=config.findManagedRepositoryById( repositoryId );
284 if (repoConfig!=null) {
286 log.debug("Repo location " + repoConfig.getLocation());
288 org.apache.archiva.repository.ManagedRepository repo = repositoryRegistry.getManagedRepository(repositoryId);
289 org.apache.archiva.repository.ManagedRepository stagingRepository = null;
291 if (repo.supportsFeature(StagingRepositoryFeature.class)) {
292 stagingRepository = repo.getFeature(StagingRepositoryFeature.class).get().getStagingRepository();
295 throw new RepositoryAdminException("A repository with that id does not exist");
298 triggerAuditEvent(repositoryId, null, AuditEvent.DELETE_MANAGED_REPO, auditInformation);
299 if (repoConfig != null) {
300 deleteManagedRepository(repoConfig, deleteContent, config, false);
304 // stage repo exists ?
305 if (stagingRepository != null) {
306 // do not trigger event when deleting the staged one
307 ManagedRepositoryConfiguration stagingRepositoryConfig = config.findManagedRepositoryById(stagingRepository.getId());
308 if (stagingRepositoryConfig != null) {
309 deleteManagedRepository(stagingRepositoryConfig, deleteContent, config, true);
314 saveConfiguration(config);
315 } catch (Exception e) {
316 throw new RepositoryAdminException("Error saving configuration for delete action" + e.getMessage(), e);
321 return Boolean.FALSE;
325 private Boolean deleteManagedRepository( ManagedRepositoryConfiguration repository, boolean deleteContent,
326 Configuration config, boolean stagedOne )
327 throws RepositoryAdminException
332 boolean success=false;
333 try(RepositorySession repositorySession = getRepositorySessionFactory().createSession())
335 MetadataRepository metadataRepository = repositorySession.getRepository();
336 metadataRepository.removeRepository(repositorySession , repository.getId() );
338 namespacesCache.remove( repository.getId() );
339 repositorySession.save();
342 catch ( MetadataRepositoryException e )
344 //throw new RepositoryAdminException( e.getMessage(), e );
345 log.warn( "skip error during removing repository from MetadataRepository:{}", e.getMessage(), e );
347 } catch (MetadataSessionException e) {
348 log.warn( "skip error during removing repository from MetadataRepository:{}", e.getMessage(), e );
353 log.debug( "call repositoryStatisticsManager.deleteStatistics" );
356 getRepositoryStatisticsManager( ).deleteStatistics( repository.getId( ) );
358 catch ( MetadataRepositoryException e )
360 e.printStackTrace( );
367 // olamy: copy list for reading as a unit test in webapp fail with ConcurrentModificationException
368 List<ProxyConnectorConfiguration> proxyConnectors = new ArrayList<>( config.getProxyConnectors() );
369 for ( ProxyConnectorConfiguration proxyConnector : proxyConnectors )
371 if ( StringUtils.equals( proxyConnector.getSourceRepoId(), repository.getId() ) )
373 config.removeProxyConnector( proxyConnector );
378 removeRepositoryRoles( repository );
380 catch ( RoleManagerException e )
382 throw new RepositoryAdminException(
383 "fail to remove repository roles for repository " + repository.getId() + " : " + e.getMessage(), e );
387 org.apache.archiva.repository.ManagedRepository repo = repositoryRegistry.getManagedRepository( repository.getId( ) );
390 repositoryRegistry.removeRepository( repo, config );
393 // TODO could be async ? as directory can be huge
394 Path dir = Paths.get( repository.getLocation( ) );
395 org.apache.archiva.common.utils.FileUtils.deleteQuietly( dir );
398 } catch (RepositoryException e) {
399 throw new RepositoryAdminException("Removal of repository "+repository.getId()+ " failed: "+e.getMessage());
402 saveConfiguration( config );
408 ArchivaIndexManager getIndexManager(ManagedRepository managedRepository) {
409 org.apache.archiva.repository.ManagedRepository repo = getRepositoryRegistry().getManagedRepository(managedRepository.getId());
410 return indexManagerFactory.getIndexManager(repo.getType());
414 public Boolean updateManagedRepository( ManagedRepository managedRepository, boolean needStageRepo,
415 AuditInformation auditInformation, boolean resetStats )
416 throws RepositoryAdminException
419 log.debug( "updateManagedConfiguration repo {} needStage {} resetStats {} ", managedRepository, needStageRepo,
422 // Ensure that the fields are valid.
424 getRepositoryCommonValidator().basicValidation( managedRepository, true );
426 getRepositoryCommonValidator().validateManagedRepository( managedRepository );
428 ManagedRepositoryConfiguration updatedRepoConfig = getRepositoryConfiguration( managedRepository );
429 updatedRepoConfig.setStageRepoNeeded( needStageRepo );
431 org.apache.archiva.repository.ManagedRepository oldRepo = repositoryRegistry.getManagedRepository( managedRepository.getId( ) );
432 boolean stagingExists = false;
433 if (oldRepo.supportsFeature( StagingRepositoryFeature.class ) ){
434 stagingExists = oldRepo.getFeature( StagingRepositoryFeature.class ).get().getStagingRepository() != null;
436 boolean updateIndexContext = !StringUtils.equals( updatedRepoConfig.getIndexDir(), managedRepository.getIndexDirectory() );
437 org.apache.archiva.repository.ManagedRepository newRepo;
438 // TODO remove content from old if path has changed !!!!!
441 newRepo = repositoryRegistry.putRepository( updatedRepoConfig );
442 if (newRepo.supportsFeature( StagingRepositoryFeature.class )) {
443 org.apache.archiva.repository.ManagedRepository stagingRepo = newRepo.getFeature( StagingRepositoryFeature.class ).get( ).getStagingRepository( );
444 if (stagingRepo!=null && !stagingExists)
446 triggerAuditEvent( stagingRepo.getId(), null, AuditEvent.ADD_MANAGED_REPO, auditInformation );
447 addRepositoryRoles( stagingRepo.getId( ) );
453 catch ( RepositoryException e )
455 log.error("Could not update repository {}: {}", managedRepository.getId(), e.getMessage(), e);
456 throw new RepositoryAdminException( "Could not update repository "+managedRepository.getId());
458 catch ( RoleManagerException e ) {
459 log.error("Error during role update of stage repo {}", managedRepository.getId(), e);
460 throw new RepositoryAdminException( "Could not update repository "+managedRepository.getId());
462 triggerAuditEvent( managedRepository.getId(), null, AuditEvent.MODIFY_MANAGED_REPO,
464 // Save the repository configuration.
465 RepositorySession repositorySession = null;
468 repositorySession = getRepositorySessionFactory().createSession();
470 catch ( MetadataRepositoryException e )
472 e.printStackTrace( );
480 log.debug( "call repositoryStatisticsManager.deleteStatistics" );
481 getRepositoryStatisticsManager().deleteStatistics(
482 managedRepository.getId() );
483 repositorySession.save();
487 catch (MetadataRepositoryException | MetadataSessionException e )
489 throw new RepositoryAdminException( e.getMessage(), e );
493 repositorySession.close();
496 if ( updateIndexContext )
501 repositoryRegistry.resetIndexingContext(newRepo);
502 } catch (IndexUpdateFailedException e) {
510 //--------------------------
512 //--------------------------
515 protected void addRepository( ManagedRepositoryConfiguration repository, Configuration configuration )
516 throws RepositoryAdminException, IOException
520 getRepositoryRegistry().putRepository( repository, configuration );
522 catch ( RepositoryException e )
524 throw new RepositoryAdminException( "Could not add the repository to the registry. Cause: "+e.getMessage() );
530 public Boolean scanRepository( String repositoryId, boolean fullScan )
532 if ( getRepositoryTaskScheduler().isProcessingRepositoryTask( repositoryId ) )
534 log.info( "scanning of repository with id {} already scheduled", repositoryId );
536 RepositoryTask task = new RepositoryTask();
537 task.setRepositoryId( repositoryId );
538 task.setScanAll( fullScan );
541 getRepositoryTaskScheduler().queueTask( task );
543 catch ( TaskQueueException e )
545 log.error( "failed to schedule scanning of repo with id {}", repositoryId, e );
552 private void addRepositoryRoles( String repoId )
553 throws RoleManagerException
555 // TODO: double check these are configured on start up
556 // TODO: belongs in the business logic
558 if ( !getRoleManager().templatedRoleExists( ArchivaRoleConstants.TEMPLATE_REPOSITORY_OBSERVER, repoId ) )
560 getRoleManager().createTemplatedRole( ArchivaRoleConstants.TEMPLATE_REPOSITORY_OBSERVER, repoId );
563 if ( !getRoleManager().templatedRoleExists( ArchivaRoleConstants.TEMPLATE_REPOSITORY_MANAGER, repoId ) )
565 getRoleManager().createTemplatedRole( ArchivaRoleConstants.TEMPLATE_REPOSITORY_MANAGER, repoId );
569 protected void removeRepositoryRoles( ManagedRepositoryConfiguration existingRepository )
570 throws RoleManagerException
572 String repoId = existingRepository.getId();
574 if ( getRoleManager().templatedRoleExists( ArchivaRoleConstants.TEMPLATE_REPOSITORY_MANAGER, repoId ) )
576 getRoleManager().removeTemplatedRole( ArchivaRoleConstants.TEMPLATE_REPOSITORY_MANAGER, repoId );
579 if ( getRoleManager().templatedRoleExists( ArchivaRoleConstants.TEMPLATE_REPOSITORY_OBSERVER, repoId ) )
581 getRoleManager().removeTemplatedRole( ArchivaRoleConstants.TEMPLATE_REPOSITORY_OBSERVER, repoId );
584 log.debug( "removed user roles associated with repository {}", repoId );
587 //--------------------------
589 //--------------------------
592 public RoleManager getRoleManager()
597 public void setRoleManager( RoleManager roleManager )
599 this.roleManager = roleManager;
602 public RepositoryStatisticsManager getRepositoryStatisticsManager()
604 return repositoryStatisticsManager;
607 public void setRepositoryStatisticsManager( RepositoryStatisticsManager repositoryStatisticsManager )
609 this.repositoryStatisticsManager = repositoryStatisticsManager;
612 public RepositorySessionFactory getRepositorySessionFactory()
614 return repositorySessionFactory;
617 public void setRepositorySessionFactory( RepositorySessionFactory repositorySessionFactory )
619 this.repositorySessionFactory = repositorySessionFactory;
623 public RepositoryArchivaTaskScheduler getRepositoryTaskScheduler()
625 return repositoryTaskScheduler;
628 public void setRepositoryTaskScheduler( RepositoryArchivaTaskScheduler repositoryTaskScheduler )
630 this.repositoryTaskScheduler = repositoryTaskScheduler;
634 public RepositoryRegistry getRepositoryRegistry( )
636 return repositoryRegistry;
639 public void setRepositoryRegistry( RepositoryRegistry repositoryRegistry )
641 this.repositoryRegistry = repositoryRegistry;