1 package org.apache.archiva.web.xmlrpc.services;
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
23 import java.io.IOException;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Date;
27 import java.util.List;
30 import org.apache.archiva.audit.AuditEvent;
31 import org.apache.archiva.audit.AuditListener;
32 import org.apache.archiva.metadata.model.ArtifactMetadata;
33 import org.apache.archiva.metadata.repository.MetadataRepository;
34 import org.apache.archiva.metadata.repository.filter.Filter;
35 import org.apache.archiva.metadata.repository.filter.IncludesFilter;
36 import org.apache.archiva.metadata.repository.stats.RepositoryStatisticsManager;
37 import org.apache.archiva.repository.events.RepositoryListener;
38 import org.apache.archiva.repository.scanner.RepositoryContentConsumers;
39 import org.apache.archiva.scheduler.repository.RepositoryArchivaTaskScheduler;
40 import org.apache.archiva.scheduler.repository.RepositoryTask;
41 import org.apache.archiva.stagerepository.merge.RepositoryMerger;
42 import org.apache.archiva.web.xmlrpc.api.AdministrationService;
43 import org.apache.archiva.web.xmlrpc.api.beans.ManagedRepository;
44 import org.apache.archiva.web.xmlrpc.api.beans.RemoteRepository;
45 import org.apache.commons.io.FileUtils;
46 import org.apache.commons.lang.StringUtils;
47 import org.apache.maven.archiva.configuration.ArchivaConfiguration;
48 import org.apache.maven.archiva.configuration.Configuration;
49 import org.apache.maven.archiva.configuration.IndeterminateConfigurationException;
50 import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
51 import org.apache.maven.archiva.configuration.ProxyConnectorConfiguration;
52 import org.apache.maven.archiva.configuration.RemoteRepositoryConfiguration;
53 import org.apache.maven.archiva.configuration.RepositoryScanningConfiguration;
54 import org.apache.maven.archiva.consumers.InvalidRepositoryContentConsumer;
55 import org.apache.maven.archiva.consumers.KnownRepositoryContentConsumer;
56 import org.apache.maven.archiva.model.VersionedReference;
57 import org.apache.maven.archiva.repository.ContentNotFoundException;
58 import org.apache.maven.archiva.repository.ManagedRepositoryContent;
59 import org.apache.maven.archiva.repository.RepositoryContentFactory;
60 import org.apache.maven.archiva.repository.RepositoryException;
61 import org.apache.maven.archiva.repository.RepositoryNotFoundException;
62 import org.codehaus.plexus.registry.RegistryException;
63 import org.codehaus.plexus.scheduler.CronExpressionValidator;
64 import org.slf4j.Logger;
65 import org.slf4j.LoggerFactory;
68 * AdministrationServiceImpl
70 * @version $Id: AdministrationServiceImpl.java
72 public class AdministrationServiceImpl
73 implements AdministrationService
75 protected Logger log = LoggerFactory.getLogger( getClass() );
77 private ArchivaConfiguration archivaConfiguration;
79 private RepositoryContentConsumers repoConsumersUtil;
81 private RepositoryContentFactory repoFactory;
83 private RepositoryArchivaTaskScheduler repositoryTaskScheduler;
85 private Collection<RepositoryListener> listeners;
87 private MetadataRepository metadataRepository;
89 private RepositoryStatisticsManager repositoryStatisticsManager;
91 private RepositoryMerger repositoryMerger;
93 private static final String STAGE = "-stage";
95 private AuditListener auditListener;
97 public AdministrationServiceImpl( ArchivaConfiguration archivaConfig, RepositoryContentConsumers repoConsumersUtil,
98 RepositoryContentFactory repoFactory, MetadataRepository metadataRepository,
99 RepositoryArchivaTaskScheduler repositoryTaskScheduler,
100 Collection<RepositoryListener> listeners,
101 RepositoryStatisticsManager repositoryStatisticsManager,
102 RepositoryMerger repositoryMerger, AuditListener auditListener )
104 this.archivaConfiguration = archivaConfig;
105 this.repoConsumersUtil = repoConsumersUtil;
106 this.repoFactory = repoFactory;
107 this.repositoryTaskScheduler = repositoryTaskScheduler;
108 this.listeners = listeners;
109 this.metadataRepository = metadataRepository;
110 this.repositoryStatisticsManager = repositoryStatisticsManager;
111 this.repositoryMerger = repositoryMerger;
112 this.auditListener = auditListener;
116 * @see AdministrationService#configureRepositoryConsumer(String, String, boolean)
118 public Boolean configureRepositoryConsumer( String repoId, String consumerId, boolean enable )
121 // TODO use repoId once consumers are configured per repository! (MRM-930)
123 List<KnownRepositoryContentConsumer> knownConsumers = repoConsumersUtil.getAvailableKnownConsumers();
124 List<InvalidRepositoryContentConsumer> invalidConsumers = repoConsumersUtil.getAvailableInvalidConsumers();
126 boolean found = false;
127 boolean isKnownContentConsumer = false;
128 for ( KnownRepositoryContentConsumer consumer : knownConsumers )
130 if ( consumer.getId().equals( consumerId ) )
133 isKnownContentConsumer = true;
140 for ( InvalidRepositoryContentConsumer consumer : invalidConsumers )
142 if ( consumer.getId().equals( consumerId ) )
152 throw new Exception( "Invalid repository consumer." );
155 Configuration config = archivaConfiguration.getConfiguration();
156 RepositoryScanningConfiguration repoScanningConfig = config.getRepositoryScanning();
158 if ( isKnownContentConsumer )
160 repoScanningConfig.addKnownContentConsumer( consumerId );
164 repoScanningConfig.addInvalidContentConsumer( consumerId );
167 config.setRepositoryScanning( repoScanningConfig );
168 saveConfiguration( config );
174 * @see AdministrationService#deleteArtifact(String, String, String, String)
176 public Boolean deleteArtifact( String repoId, String groupId, String artifactId, String version )
179 // TODO: remove duplication with web
181 Configuration config = archivaConfiguration.getConfiguration();
182 ManagedRepositoryConfiguration repoConfig = config.findManagedRepositoryById( repoId );
184 if ( repoConfig == null )
186 throw new Exception( "Repository does not exist." );
191 ManagedRepositoryContent repoContent = repoFactory.getManagedRepositoryContent( repoId );
192 VersionedReference ref = new VersionedReference();
193 ref.setGroupId( groupId );
194 ref.setArtifactId( artifactId );
195 ref.setVersion( version );
197 // delete from file system
198 repoContent.deleteVersion( ref );
200 Collection<ArtifactMetadata> artifacts =
201 metadataRepository.getArtifacts( repoId, groupId, artifactId, version );
203 for ( ArtifactMetadata artifact : artifacts )
205 // TODO: mismatch between artifact (snapshot) version and project (base) version here
206 if ( artifact.getVersion().equals( version ) )
208 metadataRepository.deleteArtifact( artifact.getRepositoryId(), artifact.getNamespace(),
209 artifact.getProject(), artifact.getVersion(), artifact.getId() );
211 // TODO: move into the metadata repository proper - need to differentiate attachment of
212 // repository metadata to an artifact
213 for ( RepositoryListener listener : listeners )
215 listener.deleteArtifact( repoId, artifact.getNamespace(), artifact.getProject(),
216 artifact.getVersion(), artifact.getId() );
221 catch ( ContentNotFoundException e )
223 throw new Exception( "Artifact does not exist." );
225 catch ( RepositoryNotFoundException e )
227 throw new Exception( "Repository does not exist." );
229 catch ( RepositoryException e )
231 throw new Exception( "Repository exception occurred." );
238 * @see AdministrationService#executeRepositoryScanner(String)
240 public Boolean executeRepositoryScanner( String repoId )
243 Configuration config = archivaConfiguration.getConfiguration();
244 if ( config.findManagedRepositoryById( repoId ) == null )
246 throw new Exception( "Repository does not exist." );
249 if ( repositoryTaskScheduler.isProcessingRepositoryTask( repoId ) )
254 RepositoryTask task = new RepositoryTask();
255 task.setRepositoryId( repoId );
257 repositoryTaskScheduler.queueTask( task );
263 * @see AdministrationService#getAllRepositoryConsumers()
265 public List<String> getAllRepositoryConsumers()
267 List<String> consumers = new ArrayList<String>();
269 List<KnownRepositoryContentConsumer> knownConsumers = repoConsumersUtil.getAvailableKnownConsumers();
270 List<InvalidRepositoryContentConsumer> invalidConsumers = repoConsumersUtil.getAvailableInvalidConsumers();
272 for ( KnownRepositoryContentConsumer consumer : knownConsumers )
274 consumers.add( consumer.getId() );
277 for ( InvalidRepositoryContentConsumer consumer : invalidConsumers )
279 consumers.add( consumer.getId() );
286 * @see AdministrationService#getAllManagedRepositories()
288 public List<ManagedRepository> getAllManagedRepositories()
290 List<ManagedRepository> managedRepos = new ArrayList<ManagedRepository>();
292 Configuration config = archivaConfiguration.getConfiguration();
293 List<ManagedRepositoryConfiguration> managedRepoConfigs = config.getManagedRepositories();
295 for ( ManagedRepositoryConfiguration repoConfig : managedRepoConfigs )
297 // TODO fix resolution of repo url!
298 ManagedRepository repo =
299 new ManagedRepository( repoConfig.getId(), repoConfig.getName(), "URL", repoConfig.getLayout(),
300 repoConfig.isSnapshots(), repoConfig.isReleases() );
301 managedRepos.add( repo );
308 * @see AdministrationService#getAllRemoteRepositories()
310 public List<RemoteRepository> getAllRemoteRepositories()
312 List<RemoteRepository> remoteRepos = new ArrayList<RemoteRepository>();
314 Configuration config = archivaConfiguration.getConfiguration();
315 List<RemoteRepositoryConfiguration> remoteRepoConfigs = config.getRemoteRepositories();
317 for ( RemoteRepositoryConfiguration repoConfig : remoteRepoConfigs )
319 RemoteRepository repo =
320 new RemoteRepository( repoConfig.getId(), repoConfig.getName(), repoConfig.getUrl(),
321 repoConfig.getLayout() );
322 remoteRepos.add( repo );
328 private void saveConfiguration( Configuration config )
333 archivaConfiguration.save( config );
335 catch ( RegistryException e )
337 throw new Exception( "Error occurred in the registry." );
339 catch ( IndeterminateConfigurationException e )
341 throw new Exception( "Error occurred while saving the configuration." );
345 public Boolean addManagedRepository( String repoId, String layout, String name, String location,
346 boolean blockRedeployments, boolean releasesIncluded,
347 boolean snapshotsIncluded, boolean stageRepoNeeded, String cronExpression )
351 Configuration config = archivaConfiguration.getConfiguration();
353 CronExpressionValidator validator = new CronExpressionValidator();
355 if ( config.getManagedRepositoriesAsMap().containsKey( repoId ) )
357 throw new Exception( "Unable to add new repository with id [" + repoId
358 + "], that id already exists as a managed repository." );
360 else if ( config.getRemoteRepositoriesAsMap().containsKey( repoId ) )
362 throw new Exception( "Unable to add new repository with id [" + repoId
363 + "], that id already exists as a remote repository." );
365 else if ( config.getRepositoryGroupsAsMap().containsKey( repoId ) )
367 throw new Exception( "Unable to add new repository with id [" + repoId
368 + "], that id already exists as a repository group." );
371 if ( !validator.validate( cronExpression ) )
373 throw new Exception( "Invalid cron expression." );
376 ManagedRepositoryConfiguration repository = new ManagedRepositoryConfiguration();
378 repository.setId( repoId );
379 repository.setBlockRedeployments( blockRedeployments );
380 repository.setReleases( releasesIncluded );
381 repository.setSnapshots( snapshotsIncluded );
382 repository.setName( name );
383 repository.setLocation( location );
384 repository.setLayout( layout );
385 repository.setRefreshCronExpression( cronExpression );
387 addRepository( repository, config );
389 if ( stageRepoNeeded )
391 ManagedRepositoryConfiguration stagingRepository = getStageRepoConfig( repository );
392 addRepository( stagingRepository, config );
395 saveConfiguration( config );
399 public Boolean deleteManagedRepository( String repoId )
402 Configuration config = archivaConfiguration.getConfiguration();
404 ManagedRepositoryConfiguration repository = config.findManagedRepositoryById( repoId );
406 if ( repository == null )
408 throw new Exception( "A repository with that id does not exist" );
411 metadataRepository.deleteRepository( repository.getId() );
412 repositoryStatisticsManager.deleteStatistics( repository.getId() );
413 config.removeManagedRepository( repository );
417 saveConfiguration( config );
419 catch ( Exception e )
421 throw new Exception( "Error saving configuration for delete action" + e.getMessage() );
424 FileUtils.deleteDirectory( new File( repository.getLocation() ) );
426 List<ProxyConnectorConfiguration> proxyConnectors = config.getProxyConnectors();
427 for ( ProxyConnectorConfiguration proxyConnector : proxyConnectors )
429 if ( StringUtils.equals( proxyConnector.getSourceRepoId(), repository.getId() ) )
431 archivaConfiguration.getConfiguration().removeProxyConnector( proxyConnector );
435 Map<String, List<String>> repoToGroupMap = archivaConfiguration.getConfiguration().getRepositoryToGroupMap();
436 if ( repoToGroupMap != null )
438 if ( repoToGroupMap.containsKey( repository.getId() ) )
440 List<String> repoGroups = repoToGroupMap.get( repository.getId() );
441 for ( String repoGroup : repoGroups )
443 archivaConfiguration.getConfiguration().findRepositoryGroupById( repoGroup ).removeRepository( repository.getId() );
451 public ManagedRepository getManagedRepository( String repoId )
454 Configuration config = archivaConfiguration.getConfiguration();
455 ManagedRepositoryConfiguration managedRepository = config.findManagedRepositoryById( repoId );
456 if ( managedRepository == null )
458 throw new Exception( "A repository with that id does not exist" );
460 ManagedRepository repo =
461 new ManagedRepository( managedRepository.getId(), managedRepository.getName(), "URL",
462 managedRepository.getLayout(), managedRepository.isSnapshots(),
463 managedRepository.isReleases() );
468 public boolean merge( String repoId, boolean skipConflicts )
471 String stagingId = repoId + STAGE;
472 ManagedRepositoryConfiguration repoConfig;
473 ManagedRepositoryConfiguration stagingConfig;
475 Configuration config = archivaConfiguration.getConfiguration();
476 repoConfig = config.findManagedRepositoryById( repoId );
478 log.debug( "Retrieved repository configuration for repo '" + repoId + "'" );
480 if ( repoConfig != null )
482 stagingConfig = config.findManagedRepositoryById( stagingId );
484 if ( stagingConfig != null )
486 List<ArtifactMetadata> sourceArtifacts = metadataRepository.getArtifacts( stagingId );
488 if ( repoConfig.isReleases() && !repoConfig.isSnapshots() )
490 log.info( "Repository to be merged contains releases only.." );
493 List<ArtifactMetadata> conflicts =
494 repositoryMerger.getConflictingArtifacts( repoId, stagingId );
496 log.debug( "Artifacts in conflict.." );
497 for( ArtifactMetadata metadata : conflicts )
499 log.debug( metadata.getNamespace() + ":" + metadata.getProject() + ":" +
500 metadata.getProjectVersion() );
503 sourceArtifacts.removeAll( conflicts );
505 log.debug( "Source artifacts size :: " + sourceArtifacts.size() );
506 mergeWithOutSnapshots( sourceArtifacts, stagingId, repoId );
510 log.debug( "Source artifacts size :: " + sourceArtifacts.size() );
511 mergeWithOutSnapshots( sourceArtifacts, stagingId, repoId );
516 log.info( "Repository to be merged has snapshot artifacts.." );
519 List<ArtifactMetadata> conflicts =
520 repositoryMerger.getConflictingArtifacts( repoId, stagingId );
522 log.debug( "Artifacts in conflict.." );
523 for( ArtifactMetadata metadata : conflicts )
525 log.debug( metadata.getNamespace() + ":" + metadata.getProject() + ":" +
526 metadata.getProjectVersion() );
529 sourceArtifacts.removeAll( conflicts );
531 log.debug( "Source artifacts size :: " + sourceArtifacts.size() );
533 Filter<ArtifactMetadata> artifactsWithOutConflicts =
534 new IncludesFilter<ArtifactMetadata>( sourceArtifacts );
535 repositoryMerger.merge( stagingId, repoId, artifactsWithOutConflicts );
537 log.info( "Staging repository '" + stagingId + "' merged successfully with managed repo '" +
542 repositoryMerger.merge( stagingId, repoId );
544 log.info( "Staging repository '" + stagingId + "' merged successfully with managed repo '" +
551 throw new Exception( "Staging Id : " + stagingId + " not found." );
556 throw new Exception( "Repository Id : " + repoId + " not found." );
559 if ( !repositoryTaskScheduler.isProcessingRepositoryTask( repoId ) )
561 RepositoryTask task = new RepositoryTask();
562 task.setRepositoryId( repoId );
564 repositoryTaskScheduler.queueTask( task );
567 AuditEvent event = createAuditEvent( repoConfig );
569 // add event for audit log reports
570 metadataRepository.addMetadataFacet( event.getRepositoryId(), event );
572 // log event in archiva audit log
573 auditListener.auditEvent( createAuditEvent( repoConfig ) );
578 protected void addRepository( ManagedRepositoryConfiguration repository, Configuration configuration )
581 // Normalize the path
582 File file = new File( repository.getLocation() );
583 repository.setLocation( file.getCanonicalPath() );
584 if ( !file.exists() )
588 if ( !file.exists() || !file.isDirectory() )
590 throw new IOException( "Unable to add repository - no write access, can not create the root directory: "
594 configuration.addManagedRepository( repository );
597 // todo: setting userid of audit event
598 private AuditEvent createAuditEvent( ManagedRepositoryConfiguration repoConfig )
601 AuditEvent event = new AuditEvent();
602 event.setAction( AuditEvent.MERGE_REPO_REMOTE );
603 event.setRepositoryId( repoConfig.getId() );
604 event.setResource( repoConfig.getLocation() );
605 event.setTimestamp( new Date() );
610 private void mergeWithOutSnapshots( List<ArtifactMetadata> sourceArtifacts, String sourceRepoId, String repoid )
613 List<ArtifactMetadata> artifactsWithOutSnapshots = new ArrayList<ArtifactMetadata>();
614 for ( ArtifactMetadata metadata : sourceArtifacts )
617 if ( metadata.getProjectVersion().contains( "SNAPSHOT" ) )
619 artifactsWithOutSnapshots.add( metadata );
623 sourceArtifacts.removeAll( artifactsWithOutSnapshots );
625 Filter<ArtifactMetadata> artifactListWithOutSnapShots = new IncludesFilter<ArtifactMetadata>( sourceArtifacts );
627 repositoryMerger.merge( sourceRepoId, repoid, artifactListWithOutSnapShots );
630 private ManagedRepositoryConfiguration getStageRepoConfig( ManagedRepositoryConfiguration repository )
632 ManagedRepositoryConfiguration stagingRepository = new ManagedRepositoryConfiguration();
633 stagingRepository.setId( repository.getId() + "-stage" );
634 stagingRepository.setLayout( repository.getLayout() );
635 stagingRepository.setName( repository.getName() + "-stage" );
636 stagingRepository.setBlockRedeployments( repository.isBlockRedeployments() );
637 stagingRepository.setDaysOlder( repository.getDaysOlder() );
638 stagingRepository.setDeleteReleasedSnapshots( repository.isDeleteReleasedSnapshots() );
639 stagingRepository.setIndexDir( repository.getIndexDir() );
640 String path = repository.getLocation();
641 int lastIndex = path.lastIndexOf( '/' );
642 stagingRepository.setLocation( path.substring( 0, lastIndex ) + "/" + stagingRepository.getId() );
643 stagingRepository.setRefreshCronExpression( repository.getRefreshCronExpression() );
644 stagingRepository.setReleases( repository.isReleases() );
645 stagingRepository.setRetentionCount( repository.getRetentionCount() );
646 stagingRepository.setScanned( repository.isScanned() );
647 stagingRepository.setSnapshots( repository.isSnapshots() );
648 return stagingRepository;