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
82 private Logger log = LoggerFactory.getLogger( getClass() );
84 public static final String STAGE_REPO_ID_END = "-stage";
88 @Named( value = "archivaTaskScheduler#repository" )
89 private RepositoryArchivaTaskScheduler repositoryTaskScheduler;
92 private RepositorySessionFactory repositorySessionFactory;
95 private RepositoryStatisticsManager repositoryStatisticsManager;
98 private PlexusSisuBridge plexusSisuBridge;
101 private MavenIndexerUtils mavenIndexerUtils;
104 protected RoleManager roleManager;
107 List<? extends IndexCreator> indexCreators;
109 NexusIndexer indexer;
112 public void initialize()
113 throws RepositoryAdminException
117 indexCreators = mavenIndexerUtils.getAllIndexCreators();
118 indexer = plexusSisuBridge.lookup( NexusIndexer.class );
120 catch ( PlexusSisuBridgeException e )
122 throw new RepositoryAdminException( e.getMessage(), e );
124 // initialize index context on start
125 for ( ManagedRepository managedRepository : getManagedRepositories() )
127 createIndexContext( managedRepository );
132 public void shutdown()
133 throws RepositoryAdminException
137 // close index on shutdown
138 for ( ManagedRepository managedRepository : getManagedRepositories() )
140 IndexingContext context = indexer.getIndexingContexts().get( managedRepository.getId() );
141 if ( context != null )
143 indexer.removeIndexingContext( context, false );
147 catch ( IOException e )
149 throw new RepositoryAdminException( e.getMessage(), e );
153 public List<ManagedRepository> getManagedRepositories()
154 throws RepositoryAdminException
156 List<ManagedRepositoryConfiguration> managedRepoConfigs =
157 getArchivaConfiguration().getConfiguration().getManagedRepositories();
159 if ( managedRepoConfigs == null )
161 return Collections.emptyList();
164 List<ManagedRepository> managedRepos = new ArrayList<ManagedRepository>( managedRepoConfigs.size() );
166 for ( ManagedRepositoryConfiguration repoConfig : managedRepoConfigs )
168 // TODO add staging repo information back too
169 ManagedRepository repo =
170 new ManagedRepository( repoConfig.getId(), repoConfig.getName(), repoConfig.getLocation(),
171 repoConfig.getLayout(), repoConfig.isSnapshots(), repoConfig.isReleases(),
172 repoConfig.isBlockRedeployments(), repoConfig.getRefreshCronExpression(),
173 repoConfig.getIndexDir(), repoConfig.isScanned(), repoConfig.getDaysOlder(),
174 repoConfig.getRetentionCount(), repoConfig.isDeleteReleasedSnapshots(), false );
176 managedRepos.add( repo );
182 public Map<String, ManagedRepository> getManagedRepositoriesAsMap()
183 throws RepositoryAdminException
185 List<ManagedRepository> managedRepositories = getManagedRepositories();
186 Map<String, ManagedRepository> repositoriesMap =
187 new HashMap<String, ManagedRepository>( managedRepositories.size() );
188 for ( ManagedRepository managedRepository : managedRepositories )
190 repositoriesMap.put( managedRepository.getId(), managedRepository );
192 return repositoriesMap;
195 public ManagedRepository getManagedRepository( String repositoryId )
196 throws RepositoryAdminException
198 List<ManagedRepository> repos = getManagedRepositories();
199 for ( ManagedRepository repo : repos )
201 if ( StringUtils.equals( repo.getId(), repositoryId ) )
209 public Boolean addManagedRepository( ManagedRepository managedRepository, boolean needStageRepo,
210 AuditInformation auditInformation )
211 throws RepositoryAdminException
214 getRepositoryCommonValidator().basicValidation( managedRepository, false );
215 getRepositoryCommonValidator().validateManagedRepository( managedRepository );
216 triggerAuditEvent( managedRepository.getId(), null, AuditEvent.ADD_MANAGED_REPO, auditInformation );
218 addManagedRepository( managedRepository.getId(), managedRepository.getLayout(), managedRepository.getName(),
219 managedRepository.getLocation(), managedRepository.isBlockRedeployments(),
220 managedRepository.isReleases(), managedRepository.isSnapshots(), needStageRepo,
221 managedRepository.getCronExpression(), managedRepository.getIndexDirectory(),
222 managedRepository.getDaysOlder(), managedRepository.getRetentionCount(),
223 managedRepository.isDeleteReleasedSnapshots(), auditInformation,
224 getArchivaConfiguration().getConfiguration() ) != null;
226 createIndexContext( managedRepository );
231 private ManagedRepositoryConfiguration addManagedRepository( String repoId, String layout, String name,
232 String location, boolean blockRedeployments,
233 boolean releasesIncluded, boolean snapshotsIncluded,
234 boolean stageRepoNeeded, String cronExpression,
235 String indexDir, int daysOlder, int retentionCount,
236 boolean deteleReleasedSnapshots,
237 AuditInformation auditInformation,
238 Configuration config )
239 throws RepositoryAdminException
242 ManagedRepositoryConfiguration repository = new ManagedRepositoryConfiguration();
244 repository.setId( repoId );
245 repository.setBlockRedeployments( blockRedeployments );
246 repository.setReleases( releasesIncluded );
247 repository.setSnapshots( snapshotsIncluded );
248 repository.setName( name );
249 repository.setLocation( getRepositoryCommonValidator().removeExpressions( location ) );
250 repository.setLayout( layout );
251 repository.setRefreshCronExpression( cronExpression );
252 repository.setIndexDir( indexDir );
253 repository.setDaysOlder( daysOlder );
254 repository.setRetentionCount( retentionCount );
255 repository.setDeleteReleasedSnapshots( deteleReleasedSnapshots );
256 repository.setIndexDir( indexDir );
260 addRepository( repository, config );
261 addRepositoryRoles( repository );
263 if ( stageRepoNeeded )
265 ManagedRepositoryConfiguration stagingRepository = getStageRepoConfig( repository );
266 addRepository( stagingRepository, config );
267 addRepositoryRoles( stagingRepository );
268 triggerAuditEvent( stagingRepository.getId(), null, AuditEvent.ADD_MANAGED_REPO, auditInformation );
271 catch ( RoleManagerException e )
273 throw new RepositoryAdminException( "failed to add repository roles " + e.getMessage(), e );
275 catch ( IOException e )
277 throw new RepositoryAdminException( "failed to add repository " + e.getMessage(), e );
280 saveConfiguration( config );
282 //MRM-1342 Repository statistics report doesn't appear to be working correctly
283 //scan repository when adding of repository is successful
286 scanRepository( repoId, true );
287 // olamy no need of scanning staged repo
289 if ( stageRepoNeeded )
291 ManagedRepositoryConfiguration stagingRepository = getStageRepoConfig( repository );
292 scanRepository( stagingRepository.getId(), true );
295 catch ( Exception e )
297 log.warn( new StringBuilder( "Unable to scan repository [" ).append( repoId ).append( "]: " ).append(
298 e.getMessage() ).toString(), e );
304 public Boolean deleteManagedRepository( String repositoryId, AuditInformation auditInformation,
305 boolean deleteContent )
306 throws RepositoryAdminException
308 Configuration config = getArchivaConfiguration().getConfiguration();
310 ManagedRepositoryConfiguration repository = config.findManagedRepositoryById( repositoryId );
312 if ( repository == null )
314 throw new RepositoryAdminException( "A repository with that id does not exist" );
317 triggerAuditEvent( repositoryId, null, AuditEvent.DELETE_MANAGED_REPO, auditInformation );
319 deleteManagedRepository( repository, deleteContent, config, false );
321 // stage repo exists ?
322 ManagedRepositoryConfiguration stagingRepository =
323 getArchivaConfiguration().getConfiguration().findManagedRepositoryById( repositoryId + STAGE_REPO_ID_END );
324 if ( stagingRepository != null )
326 // do not trigger event when deleting the staged one
327 deleteManagedRepository( stagingRepository, deleteContent, config, true );
332 saveConfiguration( config );
334 catch ( Exception e )
336 throw new RepositoryAdminException( "Error saving configuration for delete action" + e.getMessage() );
342 private Boolean deleteManagedRepository( ManagedRepositoryConfiguration repository, boolean deleteContent,
343 Configuration config, boolean stagedOne )
344 throws RepositoryAdminException
349 NexusIndexer nexusIndexer = plexusSisuBridge.lookup( NexusIndexer.class );
351 IndexingContext context = nexusIndexer.getIndexingContexts().get( repository.getId() );
352 if ( context != null )
354 // delete content only if directory exists
355 nexusIndexer.removeIndexingContext( context,
356 deleteContent && context.getIndexDirectoryFile().exists() );
359 catch ( PlexusSisuBridgeException e )
361 throw new RepositoryAdminException( e.getMessage(), e );
363 catch ( IOException e )
365 throw new RepositoryAdminException( e.getMessage(), e );
369 RepositorySession repositorySession = getRepositorySessionFactory().createSession();
372 MetadataRepository metadataRepository = repositorySession.getRepository();
373 metadataRepository.removeRepository( repository.getId() );
374 log.debug( "call repositoryStatisticsManager.deleteStatistics" );
375 getRepositoryStatisticsManager().deleteStatistics( metadataRepository, repository.getId() );
376 repositorySession.save();
378 catch ( MetadataRepositoryException e )
380 //throw new RepositoryAdminException( e.getMessage(), e );
381 log.warn( "skip error during removing repository from MetadatRepository:" + e.getMessage(), e );
385 repositorySession.close();
388 config.removeManagedRepository( repository );
392 // TODO could be async ? as directory can be huge
393 File dir = new File( repository.getLocation() );
394 if ( !FileUtils.deleteQuietly( dir ) )
396 throw new RepositoryAdminException( "Cannot delete repository " + dir );
400 // olamy: copy list for reading as a unit test in webapp fail with ConcurrentModificationException
401 List<ProxyConnectorConfiguration> proxyConnectors =
402 new ArrayList<ProxyConnectorConfiguration>( config.getProxyConnectors() );
403 for ( ProxyConnectorConfiguration proxyConnector : proxyConnectors )
405 if ( StringUtils.equals( proxyConnector.getSourceRepoId(), repository.getId() ) )
407 config.removeProxyConnector( proxyConnector );
411 Map<String, List<String>> repoToGroupMap = config.getRepositoryToGroupMap();
412 if ( repoToGroupMap != null )
414 if ( repoToGroupMap.containsKey( repository.getId() ) )
416 List<String> repoGroups = repoToGroupMap.get( repository.getId() );
417 for ( String repoGroup : repoGroups )
419 // copy to prevent UnsupportedOperationException
420 RepositoryGroupConfiguration repositoryGroupConfiguration =
421 config.findRepositoryGroupById( repoGroup );
422 List<String> repos = new ArrayList<String>( repositoryGroupConfiguration.getRepositories() );
423 config.removeRepositoryGroup( repositoryGroupConfiguration );
424 repos.remove( repository.getId() );
425 repositoryGroupConfiguration.setRepositories( repos );
426 config.addRepositoryGroup( repositoryGroupConfiguration );
433 removeRepositoryRoles( repository );
435 catch ( RoleManagerException e )
437 throw new RepositoryAdminException(
438 "fail to remove repository roles for repository " + repository.getId() + " : " + e.getMessage(), e );
441 saveConfiguration( config );
447 public Boolean updateManagedRepository( ManagedRepository managedRepository, boolean needStageRepo,
448 AuditInformation auditInformation, boolean resetStats )
449 throws RepositoryAdminException
452 log.debug( "updateManagedConfiguration repo {} needStage {} resetStats {} ",
453 Arrays.asList( managedRepository, needStageRepo, resetStats ).toArray() );
455 // Ensure that the fields are valid.
457 getRepositoryCommonValidator().basicValidation( managedRepository, true );
459 getRepositoryCommonValidator().validateManagedRepository( managedRepository );
461 Configuration configuration = getArchivaConfiguration().getConfiguration();
463 ManagedRepositoryConfiguration toremove = configuration.findManagedRepositoryById( managedRepository.getId() );
465 if ( toremove != null )
467 configuration.removeManagedRepository( toremove );
470 ManagedRepositoryConfiguration stagingRepository = getStageRepoConfig( toremove );
472 // TODO remove content from old if path has changed !!!!!
474 if ( stagingRepository != null )
476 configuration.removeManagedRepository( stagingRepository );
479 ManagedRepositoryConfiguration managedRepositoryConfiguration =
480 addManagedRepository( managedRepository.getId(), managedRepository.getLayout(), managedRepository.getName(),
481 managedRepository.getLocation(), managedRepository.isBlockRedeployments(),
482 managedRepository.isReleases(), managedRepository.isSnapshots(), needStageRepo,
483 managedRepository.getCronExpression(), managedRepository.getIndexDirectory(),
484 managedRepository.getDaysOlder(), managedRepository.getRetentionCount(),
485 managedRepository.isDeleteReleasedSnapshots(), auditInformation,
486 getArchivaConfiguration().getConfiguration() );
488 // Save the repository configuration.
489 RepositorySession repositorySession = getRepositorySessionFactory().createSession();
493 triggerAuditEvent( managedRepositoryConfiguration.getId(), null, AuditEvent.MODIFY_MANAGED_REPO,
496 saveConfiguration( this.getArchivaConfiguration().getConfiguration() );
499 log.debug( "call repositoryStatisticsManager.deleteStatistics" );
500 getRepositoryStatisticsManager().deleteStatistics( repositorySession.getRepository(),
501 managedRepositoryConfiguration.getId() );
502 repositorySession.save();
506 catch ( MetadataRepositoryException e )
508 throw new RepositoryAdminException( e.getMessage(), e );
512 repositorySession.close();
514 createIndexContext( managedRepository );
518 //--------------------------
520 //--------------------------
523 protected void addRepository( ManagedRepositoryConfiguration repository, Configuration configuration )
524 throws RepositoryAdminException, IOException
526 // Normalize the path
527 File file = new File( repository.getLocation() );
528 repository.setLocation( file.getCanonicalPath() );
529 if ( !file.exists() )
533 if ( !file.exists() || !file.isDirectory() )
535 throw new RepositoryAdminException(
536 "Unable to add repository - no write access, can not create the root directory: " + file );
539 configuration.addManagedRepository( repository );
543 public IndexingContext createIndexContext( ManagedRepository repository )
544 throws RepositoryAdminException
549 IndexingContext context = indexer.getIndexingContexts().get( repository.getId() );
551 if ( context != null )
553 log.debug( "skip adding repository indexingContent with id {} as already exists", repository.getId() );
557 String indexDir = repository.getIndexDirectory();
558 File managedRepository = new File( repository.getLocation() );
560 File indexDirectory = null;
561 if ( indexDir != null && !"".equals( indexDir ) )
563 indexDirectory = new File( repository.getIndexDirectory() );
564 if ( !indexDirectory.isAbsolute() )
566 indexDirectory = new File( managedRepository, repository.getIndexDirectory() );
571 indexDirectory = new File( managedRepository, ".indexer" );
574 if ( !indexDirectory.exists() )
576 indexDirectory.mkdirs();
579 context = indexer.getIndexingContexts().get( repository.getId() );
581 if ( context == null )
583 context = indexer.addIndexingContext( repository.getId(), repository.getId(), managedRepository,
585 managedRepository.toURI().toURL().toExternalForm(),
586 indexDirectory.toURI().toURL().toString(), indexCreators );
588 context.setSearchable( repository.isScanned() );
592 catch ( MalformedURLException e )
594 throw new RepositoryAdminException( e.getMessage(), e );
596 catch ( IOException e )
598 throw new RepositoryAdminException( e.getMessage(), e );
600 catch ( UnsupportedExistingLuceneIndexException e )
602 throw new RepositoryAdminException( e.getMessage(), e );
606 private ManagedRepositoryConfiguration getStageRepoConfig( ManagedRepositoryConfiguration repository )
608 ManagedRepositoryConfiguration stagingRepository = new ManagedRepositoryConfiguration();
609 stagingRepository.setId( repository.getId() + STAGE_REPO_ID_END );
610 stagingRepository.setLayout( repository.getLayout() );
611 stagingRepository.setName( repository.getName() + STAGE_REPO_ID_END );
612 stagingRepository.setBlockRedeployments( repository.isBlockRedeployments() );
613 stagingRepository.setDaysOlder( repository.getDaysOlder() );
614 stagingRepository.setDeleteReleasedSnapshots( repository.isDeleteReleasedSnapshots() );
615 stagingRepository.setIndexDir( repository.getIndexDir() );
616 String path = repository.getLocation();
617 int lastIndex = path.replace( '\\', '/' ).lastIndexOf( '/' );
618 stagingRepository.setLocation( path.substring( 0, lastIndex ) + "/" + stagingRepository.getId() );
619 stagingRepository.setRefreshCronExpression( repository.getRefreshCronExpression() );
620 stagingRepository.setReleases( repository.isReleases() );
621 stagingRepository.setRetentionCount( repository.getRetentionCount() );
622 stagingRepository.setScanned( repository.isScanned() );
623 stagingRepository.setSnapshots( repository.isSnapshots() );
624 return stagingRepository;
627 public Boolean scanRepository( String repositoryId, boolean fullScan )
629 if ( getRepositoryTaskScheduler().isProcessingRepositoryTask( repositoryId ) )
631 log.info( "scanning of repository with id {} already scheduled", repositoryId );
633 RepositoryTask task = new RepositoryTask();
634 task.setRepositoryId( repositoryId );
635 task.setScanAll( fullScan );
638 getRepositoryTaskScheduler().queueTask( task );
640 catch ( TaskQueueException e )
642 log.error( "failed to schedule scanning of repo with id {}", repositoryId, e );
648 protected void addRepositoryRoles( ManagedRepositoryConfiguration newRepository )
649 throws RoleManagerException
651 String repoId = newRepository.getId();
653 // TODO: double check these are configured on start up
654 // TODO: belongs in the business logic
656 if ( !getRoleManager().templatedRoleExists( ArchivaRoleConstants.TEMPLATE_REPOSITORY_OBSERVER, repoId ) )
658 getRoleManager().createTemplatedRole( ArchivaRoleConstants.TEMPLATE_REPOSITORY_OBSERVER, repoId );
661 if ( !getRoleManager().templatedRoleExists( ArchivaRoleConstants.TEMPLATE_REPOSITORY_MANAGER, repoId ) )
663 getRoleManager().createTemplatedRole( ArchivaRoleConstants.TEMPLATE_REPOSITORY_MANAGER, repoId );
667 protected void removeRepositoryRoles( ManagedRepositoryConfiguration existingRepository )
668 throws RoleManagerException
670 String repoId = existingRepository.getId();
672 if ( getRoleManager().templatedRoleExists( ArchivaRoleConstants.TEMPLATE_REPOSITORY_MANAGER, repoId ) )
674 getRoleManager().removeTemplatedRole( ArchivaRoleConstants.TEMPLATE_REPOSITORY_MANAGER, repoId );
677 if ( getRoleManager().templatedRoleExists( ArchivaRoleConstants.TEMPLATE_REPOSITORY_OBSERVER, repoId ) )
679 getRoleManager().removeTemplatedRole( ArchivaRoleConstants.TEMPLATE_REPOSITORY_OBSERVER, repoId );
682 log.debug( "removed user roles associated with repository {}", repoId );
685 //--------------------------
687 //--------------------------
690 public RoleManager getRoleManager()
695 public void setRoleManager( RoleManager roleManager )
697 this.roleManager = roleManager;
700 public RepositoryStatisticsManager getRepositoryStatisticsManager()
702 return repositoryStatisticsManager;
705 public void setRepositoryStatisticsManager( RepositoryStatisticsManager repositoryStatisticsManager )
707 this.repositoryStatisticsManager = repositoryStatisticsManager;
710 public RepositorySessionFactory getRepositorySessionFactory()
712 return repositorySessionFactory;
715 public void setRepositorySessionFactory( RepositorySessionFactory repositorySessionFactory )
717 this.repositorySessionFactory = repositorySessionFactory;
721 public RepositoryArchivaTaskScheduler getRepositoryTaskScheduler()
723 return repositoryTaskScheduler;
726 public void setRepositoryTaskScheduler( RepositoryArchivaTaskScheduler repositoryTaskScheduler )
728 this.repositoryTaskScheduler = repositoryTaskScheduler;
731 public PlexusSisuBridge getPlexusSisuBridge()
733 return plexusSisuBridge;
736 public void setPlexusSisuBridge( PlexusSisuBridge plexusSisuBridge )
738 this.plexusSisuBridge = plexusSisuBridge;
741 public MavenIndexerUtils getMavenIndexerUtils()
743 return mavenIndexerUtils;
746 public void setMavenIndexerUtils( MavenIndexerUtils mavenIndexerUtils )
748 this.mavenIndexerUtils = mavenIndexerUtils;