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
22 import org.apache.archiva.audit.AuditEvent;
23 import org.apache.archiva.audit.AuditListener;
24 import org.apache.archiva.metadata.model.ArtifactMetadata;
25 import org.apache.archiva.metadata.repository.MetadataRepository;
26 import org.apache.archiva.metadata.repository.filter.Filter;
27 import org.apache.archiva.metadata.repository.filter.IncludesFilter;
28 import org.apache.archiva.metadata.repository.stats.RepositoryStatisticsManager;
29 import org.apache.archiva.repository.events.RepositoryListener;
30 import org.apache.archiva.repository.scanner.RepositoryContentConsumers;
31 import org.apache.archiva.scheduler.repository.RepositoryArchivaTaskScheduler;
32 import org.apache.archiva.scheduler.repository.RepositoryTask;
33 import org.apache.archiva.stagerepository.merge.RepositoryMerger;
34 import org.apache.archiva.web.xmlrpc.api.AdministrationService;
35 import org.apache.archiva.web.xmlrpc.api.beans.ManagedRepository;
36 import org.apache.archiva.web.xmlrpc.api.beans.RemoteRepository;
37 import org.apache.commons.io.FileUtils;
38 import org.apache.commons.lang.StringUtils;
39 import org.apache.maven.archiva.configuration.ArchivaConfiguration;
40 import org.apache.maven.archiva.configuration.Configuration;
41 import org.apache.maven.archiva.configuration.IndeterminateConfigurationException;
42 import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
43 import org.apache.maven.archiva.configuration.ProxyConnectorConfiguration;
44 import org.apache.maven.archiva.configuration.RemoteRepositoryConfiguration;
45 import org.apache.maven.archiva.configuration.RepositoryScanningConfiguration;
46 import org.apache.maven.archiva.consumers.InvalidRepositoryContentConsumer;
47 import org.apache.maven.archiva.consumers.KnownRepositoryContentConsumer;
48 import org.apache.maven.archiva.model.VersionedReference;
49 import org.apache.maven.archiva.repository.ContentNotFoundException;
50 import org.apache.maven.archiva.repository.ManagedRepositoryContent;
51 import org.apache.maven.archiva.repository.RepositoryContentFactory;
52 import org.apache.maven.archiva.repository.RepositoryException;
53 import org.apache.maven.archiva.repository.RepositoryNotFoundException;
54 import org.codehaus.plexus.registry.RegistryException;
55 import org.codehaus.plexus.scheduler.CronExpressionValidator;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
60 import java.io.IOException;
61 import java.util.ArrayList;
62 import java.util.Collection;
63 import java.util.Date;
64 import java.util.List;
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 = metadataRepository.getArtifacts( repoId, groupId, artifactId,
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.removeArtifact( 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 = new ManagedRepository( repoConfig.getId(), repoConfig.getName(), "URL",
299 repoConfig.getLayout(), repoConfig.isSnapshots(),
300 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 = new RemoteRepository( repoConfig.getId(), repoConfig.getName(), repoConfig.getUrl(),
320 repoConfig.getLayout() );
321 remoteRepos.add( repo );
327 private void saveConfiguration( Configuration config )
332 archivaConfiguration.save( config );
334 catch ( RegistryException e )
336 throw new Exception( "Error occurred in the registry." );
338 catch ( IndeterminateConfigurationException e )
340 throw new Exception( "Error occurred while saving the configuration." );
344 public Boolean addManagedRepository( String repoId, String layout, String name, String location,
345 boolean blockRedeployments, boolean releasesIncluded,
346 boolean snapshotsIncluded, boolean stageRepoNeeded, String cronExpression )
350 Configuration config = archivaConfiguration.getConfiguration();
352 CronExpressionValidator validator = new CronExpressionValidator();
354 if ( config.getManagedRepositoriesAsMap().containsKey( repoId ) )
356 throw new Exception( "Unable to add new repository with id [" + repoId +
357 "], that id already exists as a managed repository." );
359 else if ( config.getRemoteRepositoriesAsMap().containsKey( repoId ) )
361 throw new Exception( "Unable to add new repository with id [" + repoId +
362 "], that id already exists as a remote repository." );
364 else if ( config.getRepositoryGroupsAsMap().containsKey( repoId ) )
366 throw new Exception( "Unable to add new repository with id [" + repoId +
367 "], that id already exists as a repository group." );
370 if ( !validator.validate( cronExpression ) )
372 throw new Exception( "Invalid cron expression." );
375 ManagedRepositoryConfiguration repository = new ManagedRepositoryConfiguration();
377 repository.setId( repoId );
378 repository.setBlockRedeployments( blockRedeployments );
379 repository.setReleases( releasesIncluded );
380 repository.setSnapshots( snapshotsIncluded );
381 repository.setName( name );
382 repository.setLocation( location );
383 repository.setLayout( layout );
384 repository.setRefreshCronExpression( cronExpression );
386 addRepository( repository, config );
388 if ( stageRepoNeeded )
390 ManagedRepositoryConfiguration stagingRepository = getStageRepoConfig( repository );
391 addRepository( stagingRepository, config );
394 saveConfiguration( config );
398 public Boolean deleteManagedRepository( String repoId )
401 Configuration config = archivaConfiguration.getConfiguration();
403 ManagedRepositoryConfiguration repository = config.findManagedRepositoryById( repoId );
405 if ( repository == null )
407 throw new Exception( "A repository with that id does not exist" );
410 metadataRepository.removeRepository( repository.getId() );
411 repositoryStatisticsManager.deleteStatistics( repository.getId() );
412 config.removeManagedRepository( repository );
416 saveConfiguration( config );
418 catch ( Exception e )
420 throw new Exception( "Error saving configuration for delete action" + e.getMessage() );
423 FileUtils.deleteDirectory( new File( repository.getLocation() ) );
425 List<ProxyConnectorConfiguration> proxyConnectors = config.getProxyConnectors();
426 for ( ProxyConnectorConfiguration proxyConnector : proxyConnectors )
428 if ( StringUtils.equals( proxyConnector.getSourceRepoId(), repository.getId() ) )
430 archivaConfiguration.getConfiguration().removeProxyConnector( proxyConnector );
434 Map<String, List<String>> repoToGroupMap = archivaConfiguration.getConfiguration().getRepositoryToGroupMap();
435 if ( repoToGroupMap != null )
437 if ( repoToGroupMap.containsKey( repository.getId() ) )
439 List<String> repoGroups = repoToGroupMap.get( repository.getId() );
440 for ( String repoGroup : repoGroups )
442 archivaConfiguration.getConfiguration().findRepositoryGroupById( repoGroup ).removeRepository(
443 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 = new ManagedRepository( managedRepository.getId(), managedRepository.getName(), "URL",
461 managedRepository.getLayout(), managedRepository.isSnapshots(),
462 managedRepository.isReleases() );
467 public boolean merge( String repoId, boolean skipConflicts )
470 String stagingId = repoId + STAGE;
471 ManagedRepositoryConfiguration repoConfig;
472 ManagedRepositoryConfiguration stagingConfig;
474 Configuration config = archivaConfiguration.getConfiguration();
475 repoConfig = config.findManagedRepositoryById( repoId );
477 log.debug( "Retrieved repository configuration for repo '" + repoId + "'" );
479 if ( repoConfig != null )
481 stagingConfig = config.findManagedRepositoryById( stagingId );
483 if ( stagingConfig != null )
485 List<ArtifactMetadata> sourceArtifacts = metadataRepository.getArtifacts( stagingId );
487 if ( repoConfig.isReleases() && !repoConfig.isSnapshots() )
489 log.info( "Repository to be merged contains releases only.." );
492 List<ArtifactMetadata> conflicts = repositoryMerger.getConflictingArtifacts( repoId,
495 if ( log.isDebugEnabled() )
497 log.debug( "Artifacts in conflict.." );
498 for ( ArtifactMetadata metadata : conflicts )
500 log.debug( metadata.getNamespace() + ":" + metadata.getProject() + ":" +
501 metadata.getProjectVersion() );
505 sourceArtifacts.removeAll( conflicts );
507 log.debug( "Source artifacts size :: " + sourceArtifacts.size() );
508 mergeWithOutSnapshots( sourceArtifacts, stagingId, repoId );
512 log.debug( "Source artifacts size :: " + sourceArtifacts.size() );
513 mergeWithOutSnapshots( sourceArtifacts, stagingId, repoId );
518 log.info( "Repository to be merged has snapshot artifacts.." );
521 List<ArtifactMetadata> conflicts = repositoryMerger.getConflictingArtifacts( repoId,
524 if ( log.isDebugEnabled() )
526 log.debug( "Artifacts in conflict.." );
527 for ( ArtifactMetadata metadata : conflicts )
529 log.debug( metadata.getNamespace() + ":" + metadata.getProject() + ":" +
530 metadata.getProjectVersion() );
534 sourceArtifacts.removeAll( conflicts );
536 log.debug( "Source artifacts size :: " + sourceArtifacts.size() );
538 Filter<ArtifactMetadata> artifactsWithOutConflicts = new IncludesFilter<ArtifactMetadata>(
540 repositoryMerger.merge( stagingId, repoId, artifactsWithOutConflicts );
543 "Staging repository '" + stagingId + "' merged successfully with managed repo '" + repoId +
548 repositoryMerger.merge( stagingId, repoId );
551 "Staging repository '" + stagingId + "' merged successfully with managed repo '" + repoId +
558 throw new Exception( "Staging Id : " + stagingId + " not found." );
563 throw new Exception( "Repository Id : " + repoId + " not found." );
566 if ( !repositoryTaskScheduler.isProcessingRepositoryTask( repoId ) )
568 RepositoryTask task = new RepositoryTask();
569 task.setRepositoryId( repoId );
571 repositoryTaskScheduler.queueTask( task );
574 AuditEvent event = createAuditEvent( repoConfig );
576 // add event for audit log reports
577 metadataRepository.addMetadataFacet( event.getRepositoryId(), event );
579 // log event in archiva audit log
580 auditListener.auditEvent( createAuditEvent( repoConfig ) );
585 protected void addRepository( ManagedRepositoryConfiguration repository, Configuration configuration )
588 // Normalize the path
589 File file = new File( repository.getLocation() );
590 repository.setLocation( file.getCanonicalPath() );
591 if ( !file.exists() )
595 if ( !file.exists() || !file.isDirectory() )
597 throw new IOException(
598 "Unable to add repository - no write access, can not create the root directory: " + file );
601 configuration.addManagedRepository( repository );
604 // todo: setting userid of audit event
605 private AuditEvent createAuditEvent( ManagedRepositoryConfiguration repoConfig )
608 AuditEvent event = new AuditEvent();
609 event.setAction( AuditEvent.MERGE_REPO_REMOTE );
610 event.setRepositoryId( repoConfig.getId() );
611 event.setResource( repoConfig.getLocation() );
612 event.setTimestamp( new Date() );
617 private void mergeWithOutSnapshots( List<ArtifactMetadata> sourceArtifacts, String sourceRepoId, String repoid )
620 List<ArtifactMetadata> artifactsWithOutSnapshots = new ArrayList<ArtifactMetadata>();
621 for ( ArtifactMetadata metadata : sourceArtifacts )
624 if ( metadata.getProjectVersion().contains( "SNAPSHOT" ) )
626 artifactsWithOutSnapshots.add( metadata );
630 sourceArtifacts.removeAll( artifactsWithOutSnapshots );
632 Filter<ArtifactMetadata> artifactListWithOutSnapShots = new IncludesFilter<ArtifactMetadata>( sourceArtifacts );
634 repositoryMerger.merge( sourceRepoId, repoid, artifactListWithOutSnapShots );
637 private ManagedRepositoryConfiguration getStageRepoConfig( ManagedRepositoryConfiguration repository )
639 ManagedRepositoryConfiguration stagingRepository = new ManagedRepositoryConfiguration();
640 stagingRepository.setId( repository.getId() + "-stage" );
641 stagingRepository.setLayout( repository.getLayout() );
642 stagingRepository.setName( repository.getName() + "-stage" );
643 stagingRepository.setBlockRedeployments( repository.isBlockRedeployments() );
644 stagingRepository.setDaysOlder( repository.getDaysOlder() );
645 stagingRepository.setDeleteReleasedSnapshots( repository.isDeleteReleasedSnapshots() );
646 stagingRepository.setIndexDir( repository.getIndexDir() );
647 String path = repository.getLocation();
648 int lastIndex = path.lastIndexOf( '/' );
649 stagingRepository.setLocation( path.substring( 0, lastIndex ) + "/" + stagingRepository.getId() );
650 stagingRepository.setRefreshCronExpression( repository.getRefreshCronExpression() );
651 stagingRepository.setReleases( repository.isReleases() );
652 stagingRepository.setRetentionCount( repository.getRetentionCount() );
653 stagingRepository.setScanned( repository.isScanned() );
654 stagingRepository.setSnapshots( repository.isSnapshots() );
655 return stagingRepository;