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.audit.AuditEvent;
27 import org.apache.archiva.common.plexusbridge.MavenIndexerUtils;
28 import org.apache.archiva.common.plexusbridge.PlexusSisuBridge;
29 import org.apache.archiva.common.plexusbridge.PlexusSisuBridgeException;
30 import org.apache.archiva.configuration.Configuration;
31 import org.apache.archiva.configuration.ManagedRepositoryConfiguration;
32 import org.apache.archiva.configuration.ProxyConnectorConfiguration;
33 import org.apache.archiva.configuration.RepositoryGroupConfiguration;
34 import org.apache.archiva.metadata.repository.MetadataRepository;
35 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
36 import org.apache.archiva.metadata.repository.RepositorySession;
37 import org.apache.archiva.metadata.repository.RepositorySessionFactory;
38 import org.apache.archiva.metadata.repository.stats.RepositoryStatisticsManager;
39 import org.apache.archiva.scheduler.repository.RepositoryArchivaTaskScheduler;
40 import org.apache.archiva.scheduler.repository.RepositoryTask;
41 import org.apache.archiva.security.common.ArchivaRoleConstants;
42 import org.apache.commons.io.FileUtils;
43 import org.apache.commons.lang.StringUtils;
44 import org.apache.maven.index.NexusIndexer;
45 import org.apache.maven.index.context.IndexCreator;
46 import org.apache.maven.index.context.IndexingContext;
47 import org.apache.maven.index.context.UnsupportedExistingLuceneIndexException;
48 import org.codehaus.plexus.redback.role.RoleManager;
49 import org.codehaus.plexus.redback.role.RoleManagerException;
50 import org.codehaus.plexus.taskqueue.TaskQueueException;
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;
60 import java.io.IOException;
61 import java.net.MalformedURLException;
62 import java.util.ArrayList;
63 import java.util.Arrays;
64 import java.util.Collections;
65 import java.util.HashMap;
66 import java.util.List;
70 * FIXME remove all generic Exception to have usefull ones
71 * FIXME review the staging mechanism to have a per user session one
73 * @author Olivier Lamy
75 @Service( "managedRepositoryAdmin#default" )
76 public class DefaultManagedRepositoryAdmin
77 extends AbstractRepositoryAdmin
78 implements ManagedRepositoryAdmin
81 private Logger log = LoggerFactory.getLogger( getClass() );
83 public static final String STAGE_REPO_ID_END = "-stage";
86 @Named( value = "archivaTaskScheduler#repository" )
87 private RepositoryArchivaTaskScheduler repositoryTaskScheduler;
90 private RepositorySessionFactory repositorySessionFactory;
93 private RepositoryStatisticsManager repositoryStatisticsManager;
96 private PlexusSisuBridge plexusSisuBridge;
99 private MavenIndexerUtils mavenIndexerUtils;
102 protected RoleManager roleManager;
105 List<? extends IndexCreator> indexCreators;
107 NexusIndexer indexer;
110 public void initialize()
111 throws RepositoryAdminException
115 indexCreators = mavenIndexerUtils.getAllIndexCreators();
116 indexer = plexusSisuBridge.lookup( NexusIndexer.class );
118 catch ( PlexusSisuBridgeException e )
120 throw new RepositoryAdminException( e.getMessage(), e );
122 // initialize index context on start
123 for ( ManagedRepository managedRepository : getManagedRepositories() )
125 createIndexContext( managedRepository );
130 public void shutdown()
131 throws RepositoryAdminException
135 // close index on shutdown
136 for ( ManagedRepository managedRepository : getManagedRepositories() )
138 IndexingContext context = indexer.getIndexingContexts().get( managedRepository.getId() );
139 if ( context != null )
141 indexer.removeIndexingContext( context, false );
145 catch ( IOException e )
147 throw new RepositoryAdminException( e.getMessage(), e );
151 public List<ManagedRepository> getManagedRepositories()
152 throws RepositoryAdminException
154 List<ManagedRepositoryConfiguration> managedRepoConfigs =
155 getArchivaConfiguration().getConfiguration().getManagedRepositories();
157 if ( managedRepoConfigs == null )
159 return Collections.emptyList();
162 List<ManagedRepository> managedRepos = new ArrayList<ManagedRepository>( managedRepoConfigs.size() );
164 for ( ManagedRepositoryConfiguration repoConfig : managedRepoConfigs )
166 // TODO add staging repo information back too
167 ManagedRepository repo =
168 new ManagedRepository( repoConfig.getId(), repoConfig.getName(), repoConfig.getLocation(),
169 repoConfig.getLayout(), repoConfig.isSnapshots(), repoConfig.isReleases(),
170 repoConfig.isBlockRedeployments(), repoConfig.getRefreshCronExpression(),
171 repoConfig.getIndexDir(), repoConfig.isScanned(), repoConfig.getDaysOlder(),
172 repoConfig.getRetentionCount(), repoConfig.isDeleteReleasedSnapshots(), false );
174 managedRepos.add( repo );
180 public Map<String, ManagedRepository> getManagedRepositoriesAsMap()
181 throws RepositoryAdminException
183 List<ManagedRepository> managedRepositories = getManagedRepositories();
184 Map<String, ManagedRepository> repositoriesMap =
185 new HashMap<String, ManagedRepository>( managedRepositories.size() );
186 for ( ManagedRepository managedRepository : managedRepositories )
188 repositoriesMap.put( managedRepository.getId(), managedRepository );
190 return repositoriesMap;
193 public ManagedRepository getManagedRepository( String repositoryId )
194 throws RepositoryAdminException
196 List<ManagedRepository> repos = getManagedRepositories();
197 for ( ManagedRepository repo : repos )
199 if ( StringUtils.equals( repo.getId(), repositoryId ) )
207 public Boolean addManagedRepository( ManagedRepository managedRepository, boolean needStageRepo,
208 AuditInformation auditInformation )
209 throws RepositoryAdminException
212 getRepositoryCommonValidator().basicValidation( managedRepository, false );
213 getRepositoryCommonValidator().validateManagedRepository( managedRepository );
214 triggerAuditEvent( managedRepository.getId(), null, AuditEvent.ADD_MANAGED_REPO, auditInformation );
216 addManagedRepository( managedRepository.getId(), managedRepository.getLayout(), managedRepository.getName(),
217 managedRepository.getLocation(), managedRepository.isBlockRedeployments(),
218 managedRepository.isReleases(), managedRepository.isSnapshots(), needStageRepo,
219 managedRepository.getCronExpression(), managedRepository.getIndexDirectory(),
220 managedRepository.getDaysOlder(), managedRepository.getRetentionCount(),
221 managedRepository.isDeleteReleasedSnapshots(), auditInformation,
222 getArchivaConfiguration().getConfiguration() ) != null;
224 createIndexContext( managedRepository );
229 private ManagedRepositoryConfiguration addManagedRepository( String repoId, String layout, String name,
230 String location, boolean blockRedeployments,
231 boolean releasesIncluded, boolean snapshotsIncluded,
232 boolean stageRepoNeeded, String cronExpression,
233 String indexDir, int daysOlder, int retentionCount,
234 boolean deteleReleasedSnapshots,
235 AuditInformation auditInformation,
236 Configuration config )
237 throws RepositoryAdminException
240 ManagedRepositoryConfiguration repository = new ManagedRepositoryConfiguration();
242 repository.setId( repoId );
243 repository.setBlockRedeployments( blockRedeployments );
244 repository.setReleases( releasesIncluded );
245 repository.setSnapshots( snapshotsIncluded );
246 repository.setName( name );
247 repository.setLocation( getRepositoryCommonValidator().removeExpressions( location ) );
248 repository.setLayout( layout );
249 repository.setRefreshCronExpression( cronExpression );
250 repository.setIndexDir( indexDir );
251 repository.setDaysOlder( daysOlder );
252 repository.setRetentionCount( retentionCount );
253 repository.setDeleteReleasedSnapshots( deteleReleasedSnapshots );
254 repository.setIndexDir( indexDir );
258 addRepository( repository, config );
259 addRepositoryRoles( repository );
261 if ( stageRepoNeeded )
263 ManagedRepositoryConfiguration stagingRepository = getStageRepoConfig( repository );
264 addRepository( stagingRepository, config );
265 addRepositoryRoles( stagingRepository );
266 triggerAuditEvent( stagingRepository.getId(), null, AuditEvent.ADD_MANAGED_REPO, auditInformation );
269 catch ( RoleManagerException e )
271 throw new RepositoryAdminException( "failed to add repository roles " + e.getMessage(), e );
273 catch ( IOException e )
275 throw new RepositoryAdminException( "failed to add repository " + e.getMessage(), e );
278 saveConfiguration( config );
280 //MRM-1342 Repository statistics report doesn't appear to be working correctly
281 //scan repository when adding of repository is successful
284 scanRepository( repoId, true );
285 // olamy no need of scanning staged repo
287 if ( stageRepoNeeded )
289 ManagedRepositoryConfiguration stagingRepository = getStageRepoConfig( repository );
290 scanRepository( stagingRepository.getId(), true );
293 catch ( Exception e )
295 log.warn( new StringBuilder( "Unable to scan repository [" ).append( repoId ).append( "]: " ).append(
296 e.getMessage() ).toString(), e );
302 public Boolean deleteManagedRepository( String repositoryId, AuditInformation auditInformation,
303 boolean deleteContent )
304 throws RepositoryAdminException
306 Configuration config = getArchivaConfiguration().getConfiguration();
308 ManagedRepositoryConfiguration repository = config.findManagedRepositoryById( repositoryId );
310 if ( repository == null )
312 throw new RepositoryAdminException( "A repository with that id does not exist" );
315 triggerAuditEvent( repositoryId, null, AuditEvent.DELETE_MANAGED_REPO, auditInformation );
317 deleteManagedRepository( repository, deleteContent, config, false );
319 // stage repo exists ?
320 ManagedRepositoryConfiguration stagingRepository =
321 getArchivaConfiguration().getConfiguration().findManagedRepositoryById( repositoryId + STAGE_REPO_ID_END );
322 if ( stagingRepository != null )
324 // do not trigger event when deleting the staged one
325 deleteManagedRepository( stagingRepository, deleteContent, config, true );
330 saveConfiguration( config );
332 catch ( Exception e )
334 throw new RepositoryAdminException( "Error saving configuration for delete action" + e.getMessage() );
340 private Boolean deleteManagedRepository( ManagedRepositoryConfiguration repository, boolean deleteContent,
341 Configuration config, boolean stagedOne )
342 throws RepositoryAdminException
347 NexusIndexer nexusIndexer = plexusSisuBridge.lookup( NexusIndexer.class );
349 IndexingContext context = nexusIndexer.getIndexingContexts().get( repository.getId() );
350 if ( context != null )
352 // delete content only if directory exists
353 nexusIndexer.removeIndexingContext( context,
354 deleteContent && context.getIndexDirectoryFile().exists() );
357 catch ( PlexusSisuBridgeException e )
359 throw new RepositoryAdminException( e.getMessage(), e );
361 catch ( IOException e )
363 throw new RepositoryAdminException( e.getMessage(), e );
367 RepositorySession repositorySession = getRepositorySessionFactory().createSession();
370 MetadataRepository metadataRepository = repositorySession.getRepository();
371 metadataRepository.removeRepository( repository.getId() );
372 log.debug( "call repositoryStatisticsManager.deleteStatistics" );
373 getRepositoryStatisticsManager().deleteStatistics( metadataRepository, repository.getId() );
374 repositorySession.save();
376 catch ( MetadataRepositoryException e )
378 //throw new RepositoryAdminException( e.getMessage(), e );
379 log.warn( "skip error during removing repository from MetadatRepository:" + e.getMessage(), e );
383 repositorySession.close();
386 config.removeManagedRepository( repository );
390 // TODO could be async ? as directory can be huge
391 File dir = new File( repository.getLocation() );
392 if ( !FileUtils.deleteQuietly( dir ) )
394 throw new RepositoryAdminException( "Cannot delete repository " + dir );
398 // olamy: copy list for reading as a unit test in webapp fail with ConcurrentModificationException
399 List<ProxyConnectorConfiguration> proxyConnectors =
400 new ArrayList<ProxyConnectorConfiguration>( config.getProxyConnectors() );
401 for ( ProxyConnectorConfiguration proxyConnector : proxyConnectors )
403 if ( StringUtils.equals( proxyConnector.getSourceRepoId(), repository.getId() ) )
405 config.removeProxyConnector( proxyConnector );
409 Map<String, List<String>> repoToGroupMap = config.getRepositoryToGroupMap();
410 if ( repoToGroupMap != null )
412 if ( repoToGroupMap.containsKey( repository.getId() ) )
414 List<String> repoGroups = repoToGroupMap.get( repository.getId() );
415 for ( String repoGroup : repoGroups )
417 // copy to prevent UnsupportedOperationException
418 RepositoryGroupConfiguration repositoryGroupConfiguration =
419 config.findRepositoryGroupById( repoGroup );
420 List<String> repos = new ArrayList<String>( repositoryGroupConfiguration.getRepositories() );
421 config.removeRepositoryGroup( repositoryGroupConfiguration );
422 repos.remove( repository.getId() );
423 repositoryGroupConfiguration.setRepositories( repos );
424 config.addRepositoryGroup( repositoryGroupConfiguration );
431 removeRepositoryRoles( repository );
433 catch ( RoleManagerException e )
435 throw new RepositoryAdminException(
436 "fail to remove repository roles for repository " + repository.getId() + " : " + e.getMessage(), e );
439 saveConfiguration( config );
445 public Boolean updateManagedRepository( ManagedRepository managedRepository, boolean needStageRepo,
446 AuditInformation auditInformation, boolean resetStats )
447 throws RepositoryAdminException
450 log.debug( "updateManagedConfiguration repo {} needStage {} resetStats {} ",
451 Arrays.asList( managedRepository, needStageRepo, resetStats ).toArray() );
453 // Ensure that the fields are valid.
455 getRepositoryCommonValidator().basicValidation( managedRepository, true );
457 getRepositoryCommonValidator().validateManagedRepository( managedRepository );
459 Configuration configuration = getArchivaConfiguration().getConfiguration();
461 ManagedRepositoryConfiguration toremove = configuration.findManagedRepositoryById( managedRepository.getId() );
463 if ( toremove != null )
465 configuration.removeManagedRepository( toremove );
468 ManagedRepositoryConfiguration stagingRepository = getStageRepoConfig( toremove );
470 // TODO remove content from old if path has changed !!!!!
472 if ( stagingRepository != null )
474 configuration.removeManagedRepository( stagingRepository );
477 ManagedRepositoryConfiguration managedRepositoryConfiguration =
478 addManagedRepository( managedRepository.getId(), managedRepository.getLayout(), managedRepository.getName(),
479 managedRepository.getLocation(), managedRepository.isBlockRedeployments(),
480 managedRepository.isReleases(), managedRepository.isSnapshots(), needStageRepo,
481 managedRepository.getCronExpression(), managedRepository.getIndexDirectory(),
482 managedRepository.getDaysOlder(), managedRepository.getRetentionCount(),
483 managedRepository.isDeleteReleasedSnapshots(), auditInformation,
484 getArchivaConfiguration().getConfiguration() );
486 // Save the repository configuration.
487 RepositorySession repositorySession = getRepositorySessionFactory().createSession();
491 triggerAuditEvent( managedRepositoryConfiguration.getId(), null, AuditEvent.MODIFY_MANAGED_REPO,
494 saveConfiguration( this.getArchivaConfiguration().getConfiguration() );
497 log.debug( "call repositoryStatisticsManager.deleteStatistics" );
498 getRepositoryStatisticsManager().deleteStatistics( repositorySession.getRepository(),
499 managedRepositoryConfiguration.getId() );
500 repositorySession.save();
504 catch ( MetadataRepositoryException e )
506 throw new RepositoryAdminException( e.getMessage(), e );
510 repositorySession.close();
512 createIndexContext( managedRepository );
516 //--------------------------
518 //--------------------------
521 protected void addRepository( ManagedRepositoryConfiguration repository, Configuration configuration )
522 throws RepositoryAdminException, IOException
524 // Normalize the path
525 File file = new File( repository.getLocation() );
526 repository.setLocation( file.getCanonicalPath() );
527 if ( !file.exists() )
531 if ( !file.exists() || !file.isDirectory() )
533 throw new RepositoryAdminException(
534 "Unable to add repository - no write access, can not create the root directory: " + file );
537 configuration.addManagedRepository( repository );
541 public IndexingContext createIndexContext( ManagedRepository repository )
542 throws RepositoryAdminException
547 IndexingContext context = indexer.getIndexingContexts().get( repository.getId() );
549 if ( context != null )
551 log.debug( "skip adding repository indexingContent with id {} as already exists", repository.getId() );
555 String indexDir = repository.getIndexDirectory();
556 File managedRepository = new File( repository.getLocation() );
558 File indexDirectory = null;
559 if ( indexDir != null && !"".equals( indexDir ) )
561 indexDirectory = new File( repository.getIndexDirectory() );
562 if ( !indexDirectory.isAbsolute() )
564 indexDirectory = new File( managedRepository, repository.getIndexDirectory() );
569 indexDirectory = new File( managedRepository, ".indexer" );
572 if ( !indexDirectory.exists() )
574 indexDirectory.mkdirs();
577 context = indexer.getIndexingContexts().get( repository.getId() );
579 if ( context == null )
581 context = indexer.addIndexingContext( repository.getId(), repository.getId(), managedRepository,
583 managedRepository.toURI().toURL().toExternalForm(),
584 indexDirectory.toURI().toURL().toString(), indexCreators );
586 context.setSearchable( repository.isScanned() );
590 catch ( MalformedURLException e )
592 throw new RepositoryAdminException( e.getMessage(), e );
594 catch ( IOException e )
596 throw new RepositoryAdminException( e.getMessage(), e );
598 catch ( UnsupportedExistingLuceneIndexException e )
600 throw new RepositoryAdminException( e.getMessage(), e );
604 private ManagedRepositoryConfiguration getStageRepoConfig( ManagedRepositoryConfiguration repository )
606 ManagedRepositoryConfiguration stagingRepository = new ManagedRepositoryConfiguration();
607 stagingRepository.setId( repository.getId() + STAGE_REPO_ID_END );
608 stagingRepository.setLayout( repository.getLayout() );
609 stagingRepository.setName( repository.getName() + STAGE_REPO_ID_END );
610 stagingRepository.setBlockRedeployments( repository.isBlockRedeployments() );
611 stagingRepository.setDaysOlder( repository.getDaysOlder() );
612 stagingRepository.setDeleteReleasedSnapshots( repository.isDeleteReleasedSnapshots() );
613 stagingRepository.setIndexDir( repository.getIndexDir() );
614 String path = repository.getLocation();
615 int lastIndex = path.replace( '\\', '/' ).lastIndexOf( '/' );
616 stagingRepository.setLocation( path.substring( 0, lastIndex ) + "/" + stagingRepository.getId() );
617 stagingRepository.setRefreshCronExpression( repository.getRefreshCronExpression() );
618 stagingRepository.setReleases( repository.isReleases() );
619 stagingRepository.setRetentionCount( repository.getRetentionCount() );
620 stagingRepository.setScanned( repository.isScanned() );
621 stagingRepository.setSnapshots( repository.isSnapshots() );
622 return stagingRepository;
625 public Boolean scanRepository( String repositoryId, boolean fullScan )
627 if ( getRepositoryTaskScheduler().isProcessingRepositoryTask( repositoryId ) )
629 log.info( "scanning of repository with id {} already scheduled", repositoryId );
631 RepositoryTask task = new RepositoryTask();
632 task.setRepositoryId( repositoryId );
633 task.setScanAll( fullScan );
636 getRepositoryTaskScheduler().queueTask( task );
638 catch ( TaskQueueException e )
640 log.error( "failed to schedule scanning of repo with id {}", repositoryId, e );
646 protected void addRepositoryRoles( ManagedRepositoryConfiguration newRepository )
647 throws RoleManagerException
649 String repoId = newRepository.getId();
651 // TODO: double check these are configured on start up
652 // TODO: belongs in the business logic
654 if ( !getRoleManager().templatedRoleExists( ArchivaRoleConstants.TEMPLATE_REPOSITORY_OBSERVER, repoId ) )
656 getRoleManager().createTemplatedRole( ArchivaRoleConstants.TEMPLATE_REPOSITORY_OBSERVER, repoId );
659 if ( !getRoleManager().templatedRoleExists( ArchivaRoleConstants.TEMPLATE_REPOSITORY_MANAGER, repoId ) )
661 getRoleManager().createTemplatedRole( ArchivaRoleConstants.TEMPLATE_REPOSITORY_MANAGER, repoId );
665 protected void removeRepositoryRoles( ManagedRepositoryConfiguration existingRepository )
666 throws RoleManagerException
668 String repoId = existingRepository.getId();
670 if ( getRoleManager().templatedRoleExists( ArchivaRoleConstants.TEMPLATE_REPOSITORY_MANAGER, repoId ) )
672 getRoleManager().removeTemplatedRole( ArchivaRoleConstants.TEMPLATE_REPOSITORY_MANAGER, repoId );
675 if ( getRoleManager().templatedRoleExists( ArchivaRoleConstants.TEMPLATE_REPOSITORY_OBSERVER, repoId ) )
677 getRoleManager().removeTemplatedRole( ArchivaRoleConstants.TEMPLATE_REPOSITORY_OBSERVER, repoId );
680 log.debug( "removed user roles associated with repository {}", repoId );
683 //--------------------------
685 //--------------------------
688 public RoleManager getRoleManager()
693 public void setRoleManager( RoleManager roleManager )
695 this.roleManager = roleManager;
698 public RepositoryStatisticsManager getRepositoryStatisticsManager()
700 return repositoryStatisticsManager;
703 public void setRepositoryStatisticsManager( RepositoryStatisticsManager repositoryStatisticsManager )
705 this.repositoryStatisticsManager = repositoryStatisticsManager;
708 public RepositorySessionFactory getRepositorySessionFactory()
710 return repositorySessionFactory;
713 public void setRepositorySessionFactory( RepositorySessionFactory repositorySessionFactory )
715 this.repositorySessionFactory = repositorySessionFactory;
719 public RepositoryArchivaTaskScheduler getRepositoryTaskScheduler()
721 return repositoryTaskScheduler;
724 public void setRepositoryTaskScheduler( RepositoryArchivaTaskScheduler repositoryTaskScheduler )
726 this.repositoryTaskScheduler = repositoryTaskScheduler;
729 public PlexusSisuBridge getPlexusSisuBridge()
731 return plexusSisuBridge;
734 public void setPlexusSisuBridge( PlexusSisuBridge plexusSisuBridge )
736 this.plexusSisuBridge = plexusSisuBridge;
739 public MavenIndexerUtils getMavenIndexerUtils()
741 return mavenIndexerUtils;
744 public void setMavenIndexerUtils( MavenIndexerUtils mavenIndexerUtils )
746 this.mavenIndexerUtils = mavenIndexerUtils;