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.AuditInformation;
22 import org.apache.archiva.admin.repository.AbstractRepositoryAdmin;
23 import org.apache.archiva.admin.repository.RepositoryAdminException;
24 import org.apache.archiva.audit.AuditEvent;
25 import org.apache.archiva.metadata.repository.MetadataRepository;
26 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
27 import org.apache.archiva.metadata.repository.RepositorySession;
28 import org.apache.archiva.metadata.repository.RepositorySessionFactory;
29 import org.apache.archiva.metadata.repository.stats.RepositoryStatisticsManager;
30 import org.apache.archiva.scheduler.repository.RepositoryArchivaTaskScheduler;
31 import org.apache.archiva.scheduler.repository.RepositoryTask;
32 import org.apache.archiva.security.common.ArchivaRoleConstants;
33 import org.apache.commons.io.FileUtils;
34 import org.apache.commons.lang.StringUtils;
35 import org.apache.commons.validator.GenericValidator;
36 import org.apache.maven.archiva.configuration.Configuration;
37 import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
38 import org.apache.maven.archiva.configuration.ProxyConnectorConfiguration;
39 import org.codehaus.plexus.redback.role.RoleManager;
40 import org.codehaus.plexus.redback.role.RoleManagerException;
41 import org.codehaus.plexus.taskqueue.TaskQueueException;
42 import org.codehaus.redback.components.scheduler.CronExpressionValidator;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45 import org.springframework.stereotype.Service;
47 import javax.inject.Inject;
48 import javax.inject.Named;
50 import java.io.IOException;
51 import java.util.ArrayList;
52 import java.util.Arrays;
53 import java.util.List;
57 * FIXME remove all generic Exception to have usefull ones
58 * FIXME review the staging mechanism to have a per user session one
60 * @author Olivier Lamy
62 @Service( "managedRepositoryAdmin#default" )
63 public class DefaultManagedRepositoryAdmin
64 extends AbstractRepositoryAdmin
65 implements ManagedRepositoryAdmin
68 public static final String REPOSITORY_LOCATION_VALID_EXPRESSION = "^[-a-zA-Z0-9._/~:?!&=\\\\]+$";
70 private Logger log = LoggerFactory.getLogger( getClass() );
72 public static final String STAGE_REPO_ID_END = "-stage";
76 @Named( value = "archivaTaskScheduler#repository" )
77 private RepositoryArchivaTaskScheduler repositoryTaskScheduler;
80 private RepositorySessionFactory repositorySessionFactory;
83 private RepositoryStatisticsManager repositoryStatisticsManager;
87 protected RoleManager roleManager;
89 public List<ManagedRepository> getManagedRepositories()
90 throws RepositoryAdminException
92 List<ManagedRepositoryConfiguration> managedRepoConfigs =
93 getArchivaConfiguration().getConfiguration().getManagedRepositories();
95 List<ManagedRepository> managedRepos = new ArrayList<ManagedRepository>( managedRepoConfigs.size() );
97 for ( ManagedRepositoryConfiguration repoConfig : managedRepoConfigs )
99 // TODO add staging repo information back too
100 ManagedRepository repo =
101 new ManagedRepository( repoConfig.getId(), repoConfig.getName(), repoConfig.getLocation(),
102 repoConfig.getLayout(), repoConfig.isSnapshots(), repoConfig.isReleases(),
103 repoConfig.isBlockRedeployments(), repoConfig.getRefreshCronExpression(),
104 repoConfig.getIndexDir(), repoConfig.isScanned(), repoConfig.getDaysOlder(),
105 repoConfig.getRetentionCount(), repoConfig.isDeleteReleasedSnapshots() );
107 managedRepos.add( repo );
113 public ManagedRepository getManagedRepository( String repositoryId )
114 throws RepositoryAdminException
116 List<ManagedRepository> repos = getManagedRepositories();
117 for ( ManagedRepository repo : repos )
119 if ( StringUtils.equals( repo.getId(), repositoryId ) )
127 public Boolean addManagedRepository( ManagedRepository managedRepository, boolean needStageRepo,
128 AuditInformation auditInformation )
129 throws RepositoryAdminException
132 getRepositoryCommonValidator().basicValidation( managedRepository, false );
133 triggerAuditEvent( managedRepository.getId(), null, AuditEvent.ADD_MANAGED_REPO, auditInformation );
135 addManagedRepository( managedRepository.getId(), managedRepository.getLayout(), managedRepository.getName(),
136 managedRepository.getLocation(), managedRepository.isBlockRedeployments(),
137 managedRepository.isReleases(), managedRepository.isSnapshots(), needStageRepo,
138 managedRepository.getCronExpression(), managedRepository.getIndexDirectory(),
139 managedRepository.getDaysOlder(), managedRepository.getRetentionCount(),
140 managedRepository.isDeleteReleasedSnapshots(), auditInformation ) != null;
144 private ManagedRepositoryConfiguration addManagedRepository( String repoId, String layout, String name,
145 String location, boolean blockRedeployments,
146 boolean releasesIncluded, boolean snapshotsIncluded,
147 boolean stageRepoNeeded, String cronExpression,
148 String indexDir, int daysOlder, int retentionCount,
149 boolean deteleReleasedSnapshots,
150 AuditInformation auditInformation )
151 throws RepositoryAdminException
154 Configuration config = getArchivaConfiguration().getConfiguration();
156 // FIXME : olamy can be empty to avoid scheduled scan ?
157 if ( StringUtils.isNotBlank( cronExpression ) )
159 CronExpressionValidator validator = new CronExpressionValidator();
161 if ( !validator.validate( cronExpression ) )
163 throw new RepositoryAdminException( "Invalid cron expression." );
168 throw new RepositoryAdminException( "Cron expression cannot be empty." );
171 String repoLocation = getRepositoryCommonValidator().removeExpressions( location );
173 if ( !GenericValidator.matchRegexp( repoLocation, REPOSITORY_LOCATION_VALID_EXPRESSION ) )
175 throw new RepositoryAdminException(
176 "Invalid repository location. Directory must only contain alphanumeric characters, equals(=), question-marks(?), "
177 + "exclamation-points(!), ampersands(&), forward-slashes(/), back-slashes(\\), underscores(_), dots(.), colons(:), tildes(~), and dashes(-)." );
180 ManagedRepositoryConfiguration repository = new ManagedRepositoryConfiguration();
182 repository.setId( repoId );
183 repository.setBlockRedeployments( blockRedeployments );
184 repository.setReleases( releasesIncluded );
185 repository.setSnapshots( snapshotsIncluded );
186 repository.setName( name );
187 repository.setLocation( repoLocation );
188 repository.setLayout( layout );
189 repository.setRefreshCronExpression( cronExpression );
190 repository.setIndexDir( indexDir );
191 repository.setDaysOlder( daysOlder );
192 repository.setRetentionCount( retentionCount );
193 repository.setDeleteReleasedSnapshots( deteleReleasedSnapshots );
196 addRepository( repository, config );
197 addRepositoryRoles( repository );
199 if ( stageRepoNeeded )
201 ManagedRepositoryConfiguration stagingRepository = getStageRepoConfig( repository );
202 addRepository( stagingRepository, config );
203 addRepositoryRoles( stagingRepository );
204 triggerAuditEvent( stagingRepository.getId(), null, AuditEvent.ADD_MANAGED_REPO, auditInformation );
207 catch ( RoleManagerException e )
209 throw new RepositoryAdminException( "failed to add repository roles " + e.getMessage(), e );
211 catch ( IOException e )
213 throw new RepositoryAdminException( "failed to add repository " + e.getMessage(), e );
216 saveConfiguration( config );
218 //MRM-1342 Repository statistics report doesn't appear to be working correctly
219 //scan repository when adding of repository is successful
222 scanRepository( repoId, true );
223 // olamy no need of scanning staged repo
225 if ( stageRepoNeeded )
227 ManagedRepositoryConfiguration stagingRepository = getStageRepoConfig( repository );
228 scanRepository( stagingRepository.getId(), true );
231 catch ( Exception e )
233 log.warn( new StringBuilder( "Unable to scan repository [" ).append( repoId ).append( "]: " ).append(
234 e.getMessage() ).toString(), e );
241 public Boolean deleteManagedRepository( String repositoryId, AuditInformation auditInformation,
242 boolean deleteContent )
243 throws RepositoryAdminException
245 Configuration config = getArchivaConfiguration().getConfiguration();
247 ManagedRepositoryConfiguration repository = config.findManagedRepositoryById( repositoryId );
249 if ( repository == null )
251 throw new RepositoryAdminException( "A repository with that id does not exist" );
254 triggerAuditEvent( repositoryId, null, AuditEvent.DELETE_MANAGED_REPO, auditInformation );
256 deleteManagedRepository( repository, deleteContent, config, false );
258 // stage repo exists ?
259 ManagedRepositoryConfiguration stagingRepository =
260 getArchivaConfiguration().getConfiguration().findManagedRepositoryById( repositoryId + STAGE_REPO_ID_END );
261 if ( stagingRepository != null )
263 // do not trigger event when deleting the staged one
264 //triggerAuditEvent( stagingRepository.getId(), null, AuditEvent.DELETE_MANAGED_REPO, auditInformation );
265 deleteManagedRepository( stagingRepository, deleteContent, config, true );
270 saveConfiguration( config );
272 catch ( Exception e )
274 throw new RepositoryAdminException( "Error saving configuration for delete action" + e.getMessage() );
280 private Boolean deleteManagedRepository( ManagedRepositoryConfiguration repository, boolean deleteContent,
281 Configuration config, boolean stagedOne )
282 throws RepositoryAdminException
286 RepositorySession repositorySession = getRepositorySessionFactory().createSession();
289 MetadataRepository metadataRepository = repositorySession.getRepository();
290 metadataRepository.removeRepository( repository.getId() );
291 log.debug( "call repositoryStatisticsManager.deleteStatistics" );
292 getRepositoryStatisticsManager().deleteStatistics( metadataRepository, repository.getId() );
293 repositorySession.save();
295 catch ( MetadataRepositoryException e )
297 throw new RepositoryAdminException( e.getMessage(), e );
301 repositorySession.close();
304 config.removeManagedRepository( repository );
308 // TODO could be async ? as directory can be huge
309 File dir = new File( repository.getLocation() );
310 if ( !FileUtils.deleteQuietly( dir ) )
312 throw new RepositoryAdminException( "Cannot delete repository " + dir );
316 // olamy: copy list for reading as a unit test in webapp fail with ConcurrentModificationException
317 List<ProxyConnectorConfiguration> proxyConnectors =
318 new ArrayList<ProxyConnectorConfiguration>( config.getProxyConnectors() );
319 for ( ProxyConnectorConfiguration proxyConnector : proxyConnectors )
321 if ( StringUtils.equals( proxyConnector.getSourceRepoId(), repository.getId() ) )
323 config.removeProxyConnector( proxyConnector );
327 Map<String, List<String>> repoToGroupMap = config.getRepositoryToGroupMap();
328 if ( repoToGroupMap != null )
330 if ( repoToGroupMap.containsKey( repository.getId() ) )
332 List<String> repoGroups = repoToGroupMap.get( repository.getId() );
333 for ( String repoGroup : repoGroups )
335 config.findRepositoryGroupById( repoGroup ).removeRepository( repository.getId() );
342 removeRepositoryRoles( repository );
344 catch ( RoleManagerException e )
346 throw new RepositoryAdminException(
347 "fail to remove repository roles for repository " + repository.getId() + " : " + e.getMessage(), e );
350 saveConfiguration( config );
356 public Boolean updateManagedRepository( ManagedRepository managedRepository, boolean needStageRepo,
357 AuditInformation auditInformation, boolean resetStats )
358 throws RepositoryAdminException
361 log.debug( "updateManagedConfiguration repo {} needStage {} resetStats {} ",
362 Arrays.asList( managedRepository, needStageRepo, resetStats ).toArray() );
364 // Ensure that the fields are valid.
366 getRepositoryCommonValidator().basicValidation( managedRepository, true );
368 Configuration configuration = getArchivaConfiguration().getConfiguration();
370 ManagedRepositoryConfiguration toremove = configuration.findManagedRepositoryById( managedRepository.getId() );
372 if ( toremove != null )
374 configuration.removeManagedRepository( toremove );
377 ManagedRepositoryConfiguration stagingRepository = getStageRepoConfig( toremove );
379 // TODO remove content from old if path has changed !!!!!
381 if ( stagingRepository != null )
383 configuration.removeManagedRepository( stagingRepository );
386 if ( toremove != null && stagingRepository != null )
388 saveConfiguration( configuration );
391 ManagedRepositoryConfiguration managedRepositoryConfiguration =
392 addManagedRepository( managedRepository.getId(), managedRepository.getLayout(), managedRepository.getName(),
393 managedRepository.getLocation(), managedRepository.isBlockRedeployments(),
394 managedRepository.isReleases(), managedRepository.isSnapshots(), needStageRepo,
395 managedRepository.getCronExpression(), managedRepository.getIndexDirectory(),
396 managedRepository.getDaysOlder(), managedRepository.getRetentionCount(),
397 managedRepository.isDeleteReleasedSnapshots(), auditInformation );
399 // Save the repository configuration.
400 RepositorySession repositorySession = getRepositorySessionFactory().createSession();
404 triggerAuditEvent( managedRepositoryConfiguration.getId(), null, AuditEvent.MODIFY_MANAGED_REPO,
407 saveConfiguration( this.getArchivaConfiguration().getConfiguration() );
410 log.debug( "call repositoryStatisticsManager.deleteStatistics" );
411 getRepositoryStatisticsManager().deleteStatistics( repositorySession.getRepository(),
412 managedRepositoryConfiguration.getId() );
413 repositorySession.save();
417 catch ( MetadataRepositoryException e )
419 throw new RepositoryAdminException( e.getMessage(), e );
423 repositorySession.close();
429 //--------------------------
431 //--------------------------
434 protected void addRepository( ManagedRepositoryConfiguration repository, Configuration configuration )
435 throws RepositoryAdminException, IOException
437 // Normalize the path
438 File file = new File( repository.getLocation() );
439 repository.setLocation( file.getCanonicalPath() );
440 if ( !file.exists() )
444 if ( !file.exists() || !file.isDirectory() )
446 throw new RepositoryAdminException(
447 "Unable to add repository - no write access, can not create the root directory: " + file );
450 configuration.addManagedRepository( repository );
453 private ManagedRepositoryConfiguration getStageRepoConfig( ManagedRepositoryConfiguration repository )
455 ManagedRepositoryConfiguration stagingRepository = new ManagedRepositoryConfiguration();
456 stagingRepository.setId( repository.getId() + STAGE_REPO_ID_END );
457 stagingRepository.setLayout( repository.getLayout() );
458 stagingRepository.setName( repository.getName() + STAGE_REPO_ID_END );
459 stagingRepository.setBlockRedeployments( repository.isBlockRedeployments() );
460 stagingRepository.setDaysOlder( repository.getDaysOlder() );
461 stagingRepository.setDeleteReleasedSnapshots( repository.isDeleteReleasedSnapshots() );
462 stagingRepository.setIndexDir( repository.getIndexDir() );
463 String path = repository.getLocation();
464 int lastIndex = path.lastIndexOf( '/' );
465 stagingRepository.setLocation( path.substring( 0, lastIndex ) + "/" + stagingRepository.getId() );
466 stagingRepository.setRefreshCronExpression( repository.getRefreshCronExpression() );
467 stagingRepository.setReleases( repository.isReleases() );
468 stagingRepository.setRetentionCount( repository.getRetentionCount() );
469 stagingRepository.setScanned( repository.isScanned() );
470 stagingRepository.setSnapshots( repository.isSnapshots() );
471 return stagingRepository;
474 public Boolean scanRepository( String repositoryId, boolean fullScan )
476 if ( getRepositoryTaskScheduler().isProcessingRepositoryTask( repositoryId ) )
478 log.info( "scanning of repository with id {} already scheduled", repositoryId );
480 RepositoryTask task = new RepositoryTask();
481 task.setRepositoryId( repositoryId );
482 task.setScanAll( fullScan );
485 getRepositoryTaskScheduler().queueTask( task );
487 catch ( TaskQueueException e )
489 log.error( "failed to schedule scanning of repo with id {}", repositoryId, e );
495 protected void addRepositoryRoles( ManagedRepositoryConfiguration newRepository )
496 throws RoleManagerException
498 String repoId = newRepository.getId();
500 // TODO: double check these are configured on start up
501 // TODO: belongs in the business logic
503 if ( !getRoleManager().templatedRoleExists( ArchivaRoleConstants.TEMPLATE_REPOSITORY_OBSERVER, repoId ) )
505 getRoleManager().createTemplatedRole( ArchivaRoleConstants.TEMPLATE_REPOSITORY_OBSERVER, repoId );
508 if ( !getRoleManager().templatedRoleExists( ArchivaRoleConstants.TEMPLATE_REPOSITORY_MANAGER, repoId ) )
510 getRoleManager().createTemplatedRole( ArchivaRoleConstants.TEMPLATE_REPOSITORY_MANAGER, repoId );
514 protected void removeRepositoryRoles( ManagedRepositoryConfiguration existingRepository )
515 throws RoleManagerException
517 String repoId = existingRepository.getId();
519 if ( getRoleManager().templatedRoleExists( ArchivaRoleConstants.TEMPLATE_REPOSITORY_MANAGER, repoId ) )
521 getRoleManager().removeTemplatedRole( ArchivaRoleConstants.TEMPLATE_REPOSITORY_MANAGER, repoId );
524 if ( getRoleManager().templatedRoleExists( ArchivaRoleConstants.TEMPLATE_REPOSITORY_OBSERVER, repoId ) )
526 getRoleManager().removeTemplatedRole( ArchivaRoleConstants.TEMPLATE_REPOSITORY_OBSERVER, repoId );
529 log.debug( "removed user roles associated with repository {}", repoId );
532 //--------------------------
534 //--------------------------
537 public RoleManager getRoleManager()
542 public void setRoleManager( RoleManager roleManager )
544 this.roleManager = roleManager;
547 public RepositoryStatisticsManager getRepositoryStatisticsManager()
549 return repositoryStatisticsManager;
552 public void setRepositoryStatisticsManager( RepositoryStatisticsManager repositoryStatisticsManager )
554 this.repositoryStatisticsManager = repositoryStatisticsManager;
557 public RepositorySessionFactory getRepositorySessionFactory()
559 return repositorySessionFactory;
562 public void setRepositorySessionFactory( RepositorySessionFactory repositorySessionFactory )
564 this.repositorySessionFactory = repositorySessionFactory;
568 public RepositoryArchivaTaskScheduler getRepositoryTaskScheduler()
570 return repositoryTaskScheduler;
573 public void setRepositoryTaskScheduler( RepositoryArchivaTaskScheduler repositoryTaskScheduler )
575 this.repositoryTaskScheduler = repositoryTaskScheduler;