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 if ( !file.isAbsolute() )
528 // add appserver.base/repositories
529 file = new File( getRegistry().getString( "appserver.base" ) + File.separatorChar + "repositories",
530 repository.getLocation() );
532 repository.setLocation( file.getCanonicalPath() );
533 if ( !file.exists() )
537 if ( !file.exists() || !file.isDirectory() )
539 throw new RepositoryAdminException(
540 "Unable to add repository - no write access, can not create the root directory: " + file );
543 configuration.addManagedRepository( repository );
547 public IndexingContext createIndexContext( ManagedRepository repository )
548 throws RepositoryAdminException
553 IndexingContext context = indexer.getIndexingContexts().get( repository.getId() );
555 if ( context != null )
557 log.debug( "skip adding repository indexingContent with id {} as already exists", repository.getId() );
561 String indexDir = repository.getIndexDirectory();
562 File managedRepository = new File( repository.getLocation() );
564 File indexDirectory = null;
565 if ( indexDir != null && !"".equals( indexDir ) )
567 indexDirectory = new File( repository.getIndexDirectory() );
568 if ( !indexDirectory.isAbsolute() )
570 indexDirectory = new File( managedRepository, repository.getIndexDirectory() );
575 indexDirectory = new File( managedRepository, ".indexer" );
578 if ( !indexDirectory.exists() )
580 indexDirectory.mkdirs();
583 context = indexer.getIndexingContexts().get( repository.getId() );
585 if ( context == null )
587 context = indexer.addIndexingContext( repository.getId(), repository.getId(), managedRepository,
589 managedRepository.toURI().toURL().toExternalForm(),
590 indexDirectory.toURI().toURL().toString(), indexCreators );
592 context.setSearchable( repository.isScanned() );
596 catch ( MalformedURLException e )
598 throw new RepositoryAdminException( e.getMessage(), e );
600 catch ( IOException e )
602 throw new RepositoryAdminException( e.getMessage(), e );
604 catch ( UnsupportedExistingLuceneIndexException e )
606 throw new RepositoryAdminException( e.getMessage(), e );
610 private ManagedRepositoryConfiguration getStageRepoConfig( ManagedRepositoryConfiguration repository )
612 ManagedRepositoryConfiguration stagingRepository = new ManagedRepositoryConfiguration();
613 stagingRepository.setId( repository.getId() + STAGE_REPO_ID_END );
614 stagingRepository.setLayout( repository.getLayout() );
615 stagingRepository.setName( repository.getName() + STAGE_REPO_ID_END );
616 stagingRepository.setBlockRedeployments( repository.isBlockRedeployments() );
617 stagingRepository.setDaysOlder( repository.getDaysOlder() );
618 stagingRepository.setDeleteReleasedSnapshots( repository.isDeleteReleasedSnapshots() );
619 stagingRepository.setIndexDir( repository.getIndexDir() );
620 String path = repository.getLocation();
621 int lastIndex = path.replace( '\\', '/' ).lastIndexOf( '/' );
622 stagingRepository.setLocation( path.substring( 0, lastIndex ) + "/" + stagingRepository.getId() );
623 stagingRepository.setRefreshCronExpression( repository.getRefreshCronExpression() );
624 stagingRepository.setReleases( repository.isReleases() );
625 stagingRepository.setRetentionCount( repository.getRetentionCount() );
626 stagingRepository.setScanned( repository.isScanned() );
627 stagingRepository.setSnapshots( repository.isSnapshots() );
628 return stagingRepository;
631 public Boolean scanRepository( String repositoryId, boolean fullScan )
633 if ( getRepositoryTaskScheduler().isProcessingRepositoryTask( repositoryId ) )
635 log.info( "scanning of repository with id {} already scheduled", repositoryId );
637 RepositoryTask task = new RepositoryTask();
638 task.setRepositoryId( repositoryId );
639 task.setScanAll( fullScan );
642 getRepositoryTaskScheduler().queueTask( task );
644 catch ( TaskQueueException e )
646 log.error( "failed to schedule scanning of repo with id {}", repositoryId, e );
652 protected void addRepositoryRoles( ManagedRepositoryConfiguration newRepository )
653 throws RoleManagerException
655 String repoId = newRepository.getId();
657 // TODO: double check these are configured on start up
658 // TODO: belongs in the business logic
660 if ( !getRoleManager().templatedRoleExists( ArchivaRoleConstants.TEMPLATE_REPOSITORY_OBSERVER, repoId ) )
662 getRoleManager().createTemplatedRole( ArchivaRoleConstants.TEMPLATE_REPOSITORY_OBSERVER, repoId );
665 if ( !getRoleManager().templatedRoleExists( ArchivaRoleConstants.TEMPLATE_REPOSITORY_MANAGER, repoId ) )
667 getRoleManager().createTemplatedRole( ArchivaRoleConstants.TEMPLATE_REPOSITORY_MANAGER, repoId );
671 protected void removeRepositoryRoles( ManagedRepositoryConfiguration existingRepository )
672 throws RoleManagerException
674 String repoId = existingRepository.getId();
676 if ( getRoleManager().templatedRoleExists( ArchivaRoleConstants.TEMPLATE_REPOSITORY_MANAGER, repoId ) )
678 getRoleManager().removeTemplatedRole( ArchivaRoleConstants.TEMPLATE_REPOSITORY_MANAGER, repoId );
681 if ( getRoleManager().templatedRoleExists( ArchivaRoleConstants.TEMPLATE_REPOSITORY_OBSERVER, repoId ) )
683 getRoleManager().removeTemplatedRole( ArchivaRoleConstants.TEMPLATE_REPOSITORY_OBSERVER, repoId );
686 log.debug( "removed user roles associated with repository {}", repoId );
689 //--------------------------
691 //--------------------------
694 public RoleManager getRoleManager()
699 public void setRoleManager( RoleManager roleManager )
701 this.roleManager = roleManager;
704 public RepositoryStatisticsManager getRepositoryStatisticsManager()
706 return repositoryStatisticsManager;
709 public void setRepositoryStatisticsManager( RepositoryStatisticsManager repositoryStatisticsManager )
711 this.repositoryStatisticsManager = repositoryStatisticsManager;
714 public RepositorySessionFactory getRepositorySessionFactory()
716 return repositorySessionFactory;
719 public void setRepositorySessionFactory( RepositorySessionFactory repositorySessionFactory )
721 this.repositorySessionFactory = repositorySessionFactory;
725 public RepositoryArchivaTaskScheduler getRepositoryTaskScheduler()
727 return repositoryTaskScheduler;
730 public void setRepositoryTaskScheduler( RepositoryArchivaTaskScheduler repositoryTaskScheduler )
732 this.repositoryTaskScheduler = repositoryTaskScheduler;
735 public PlexusSisuBridge getPlexusSisuBridge()
737 return plexusSisuBridge;
740 public void setPlexusSisuBridge( PlexusSisuBridge plexusSisuBridge )
742 this.plexusSisuBridge = plexusSisuBridge;
745 public MavenIndexerUtils getMavenIndexerUtils()
747 return mavenIndexerUtils;
750 public void setMavenIndexerUtils( MavenIndexerUtils mavenIndexerUtils )
752 this.mavenIndexerUtils = mavenIndexerUtils;