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.RepositorySession;
27 import org.apache.archiva.metadata.repository.RepositorySessionFactory;
28 import org.apache.archiva.metadata.repository.filter.Filter;
29 import org.apache.archiva.metadata.repository.filter.IncludesFilter;
30 import org.apache.archiva.metadata.repository.stats.RepositoryStatisticsManager;
31 import org.apache.archiva.repository.events.RepositoryListener;
32 import org.apache.archiva.repository.scanner.RepositoryContentConsumers;
33 import org.apache.archiva.scheduler.repository.RepositoryArchivaTaskScheduler;
34 import org.apache.archiva.scheduler.repository.RepositoryTask;
35 import org.apache.archiva.stagerepository.merge.RepositoryMerger;
36 import org.apache.archiva.web.xmlrpc.api.AdministrationService;
37 import org.apache.archiva.web.xmlrpc.api.beans.ManagedRepository;
38 import org.apache.archiva.web.xmlrpc.api.beans.RemoteRepository;
39 import org.apache.commons.io.FileUtils;
40 import org.apache.commons.lang.StringUtils;
41 import org.apache.maven.archiva.configuration.ArchivaConfiguration;
42 import org.apache.maven.archiva.configuration.Configuration;
43 import org.apache.maven.archiva.configuration.IndeterminateConfigurationException;
44 import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
45 import org.apache.maven.archiva.configuration.ProxyConnectorConfiguration;
46 import org.apache.maven.archiva.configuration.RemoteRepositoryConfiguration;
47 import org.apache.maven.archiva.configuration.RepositoryScanningConfiguration;
48 import org.apache.maven.archiva.consumers.InvalidRepositoryContentConsumer;
49 import org.apache.maven.archiva.consumers.KnownRepositoryContentConsumer;
50 import org.apache.maven.archiva.model.VersionedReference;
51 import org.apache.maven.archiva.repository.ContentNotFoundException;
52 import org.apache.maven.archiva.repository.ManagedRepositoryContent;
53 import org.apache.maven.archiva.repository.RepositoryContentFactory;
54 import org.apache.maven.archiva.repository.RepositoryException;
55 import org.apache.maven.archiva.repository.RepositoryNotFoundException;
56 import org.codehaus.plexus.registry.Registry;
57 import org.codehaus.plexus.registry.RegistryException;
58 import org.codehaus.plexus.scheduler.CronExpressionValidator;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
63 import java.io.IOException;
64 import java.util.ArrayList;
65 import java.util.Collection;
66 import java.util.Date;
67 import java.util.List;
71 * AdministrationServiceImpl
73 * @version $Id: AdministrationServiceImpl.java
75 public class AdministrationServiceImpl
76 implements AdministrationService
78 protected Logger log = LoggerFactory.getLogger( getClass() );
80 private ArchivaConfiguration archivaConfiguration;
82 private RepositoryContentConsumers repoConsumersUtil;
84 private RepositoryContentFactory repoFactory;
86 private RepositoryArchivaTaskScheduler repositoryTaskScheduler;
88 private Collection<RepositoryListener> listeners;
90 private RepositoryStatisticsManager repositoryStatisticsManager;
92 private RepositoryMerger repositoryMerger;
94 private static final String STAGE = "-stage";
96 private AuditListener auditListener;
98 private RepositorySessionFactory repositorySessionFactory;
100 private Registry registry;
102 public AdministrationServiceImpl( ArchivaConfiguration archivaConfig, RepositoryContentConsumers repoConsumersUtil,
103 RepositoryContentFactory repoFactory,
104 RepositorySessionFactory repositorySessionFactory,
105 RepositoryArchivaTaskScheduler repositoryTaskScheduler,
106 Collection<RepositoryListener> listeners,
107 RepositoryStatisticsManager repositoryStatisticsManager,
108 RepositoryMerger repositoryMerger, AuditListener auditListener,
111 this.archivaConfiguration = archivaConfig;
112 this.repoConsumersUtil = repoConsumersUtil;
113 this.repoFactory = repoFactory;
114 this.repositoryTaskScheduler = repositoryTaskScheduler;
115 this.listeners = listeners;
116 this.repositorySessionFactory = repositorySessionFactory;
117 this.repositoryStatisticsManager = repositoryStatisticsManager;
118 this.repositoryMerger = repositoryMerger;
119 this.auditListener = auditListener;
120 this.registry = registry;
124 * @see AdministrationService#configureRepositoryConsumer(String, String, boolean)
126 public Boolean configureRepositoryConsumer( String repoId, String consumerId, boolean enable )
129 // TODO use repoId once consumers are configured per repository! (MRM-930)
131 List<KnownRepositoryContentConsumer> knownConsumers = repoConsumersUtil.getAvailableKnownConsumers();
132 List<InvalidRepositoryContentConsumer> invalidConsumers = repoConsumersUtil.getAvailableInvalidConsumers();
134 boolean found = false;
135 boolean isKnownContentConsumer = false;
136 for ( KnownRepositoryContentConsumer consumer : knownConsumers )
138 if ( consumer.getId().equals( consumerId ) )
141 isKnownContentConsumer = true;
148 for ( InvalidRepositoryContentConsumer consumer : invalidConsumers )
150 if ( consumer.getId().equals( consumerId ) )
160 throw new Exception( "Invalid repository consumer." );
163 Configuration config = archivaConfiguration.getConfiguration();
164 RepositoryScanningConfiguration repoScanningConfig = config.getRepositoryScanning();
166 if ( isKnownContentConsumer )
168 repoScanningConfig.addKnownContentConsumer( consumerId );
172 repoScanningConfig.addInvalidContentConsumer( consumerId );
175 config.setRepositoryScanning( repoScanningConfig );
176 saveConfiguration( config );
182 * @see AdministrationService#deleteArtifact(String, String, String, String)
184 public Boolean deleteArtifact( String repoId, String groupId, String artifactId, String version )
187 // TODO: remove duplication with web
189 Configuration config = archivaConfiguration.getConfiguration();
190 ManagedRepositoryConfiguration repoConfig = config.findManagedRepositoryById( repoId );
192 if ( repoConfig == null )
194 throw new Exception( "Repository does not exist." );
197 RepositorySession repositorySession = repositorySessionFactory.createSession();
200 ManagedRepositoryContent repoContent = repoFactory.getManagedRepositoryContent( repoId );
201 VersionedReference ref = new VersionedReference();
202 ref.setGroupId( groupId );
203 ref.setArtifactId( artifactId );
204 ref.setVersion( version );
206 // delete from file system
207 repoContent.deleteVersion( ref );
209 MetadataRepository metadataRepository = repositorySession.getRepository();
210 Collection<ArtifactMetadata> artifacts = metadataRepository.getArtifacts( repoId, groupId, artifactId,
213 for ( ArtifactMetadata artifact : artifacts )
215 // TODO: mismatch between artifact (snapshot) version and project (base) version here
216 if ( artifact.getVersion().equals( version ) )
218 metadataRepository.removeArtifact( artifact.getRepositoryId(), artifact.getNamespace(),
219 artifact.getProject(), artifact.getVersion(), artifact.getId() );
221 // TODO: move into the metadata repository proper - need to differentiate attachment of
222 // repository metadata to an artifact
223 for ( RepositoryListener listener : listeners )
225 listener.deleteArtifact( metadataRepository, repoId, artifact.getNamespace(),
226 artifact.getProject(), artifact.getVersion(), artifact.getId() );
230 repositorySession.save();
232 catch ( ContentNotFoundException e )
234 throw new Exception( "Artifact does not exist." );
236 catch ( RepositoryNotFoundException e )
238 throw new Exception( "Repository does not exist." );
240 catch ( RepositoryException e )
242 throw new Exception( "Repository exception occurred." );
246 repositorySession.close();
253 * @see AdministrationService#executeRepositoryScanner(String)
255 public Boolean executeRepositoryScanner( String repoId )
258 Configuration config = archivaConfiguration.getConfiguration();
259 if ( config.findManagedRepositoryById( repoId ) == null )
261 throw new Exception( "Repository does not exist." );
264 if ( repositoryTaskScheduler.isProcessingRepositoryTask( repoId ) )
269 RepositoryTask task = new RepositoryTask();
270 task.setRepositoryId( repoId );
272 repositoryTaskScheduler.queueTask( task );
278 * @see AdministrationService#getAllRepositoryConsumers()
280 public List<String> getAllRepositoryConsumers()
282 List<String> consumers = new ArrayList<String>();
284 List<KnownRepositoryContentConsumer> knownConsumers = repoConsumersUtil.getAvailableKnownConsumers();
285 List<InvalidRepositoryContentConsumer> invalidConsumers = repoConsumersUtil.getAvailableInvalidConsumers();
287 for ( KnownRepositoryContentConsumer consumer : knownConsumers )
289 consumers.add( consumer.getId() );
292 for ( InvalidRepositoryContentConsumer consumer : invalidConsumers )
294 consumers.add( consumer.getId() );
301 * @see AdministrationService#getAllManagedRepositories()
303 public List<ManagedRepository> getAllManagedRepositories()
305 List<ManagedRepository> managedRepos = new ArrayList<ManagedRepository>();
307 Configuration config = archivaConfiguration.getConfiguration();
308 List<ManagedRepositoryConfiguration> managedRepoConfigs = config.getManagedRepositories();
310 for ( ManagedRepositoryConfiguration repoConfig : managedRepoConfigs )
312 // TODO fix resolution of repo url!
313 ManagedRepository repo = new ManagedRepository( repoConfig.getId(), repoConfig.getName(), "URL",
314 repoConfig.getLayout(), repoConfig.isSnapshots(),
315 repoConfig.isReleases() );
316 managedRepos.add( repo );
323 * @see AdministrationService#getAllRemoteRepositories()
325 public List<RemoteRepository> getAllRemoteRepositories()
327 List<RemoteRepository> remoteRepos = new ArrayList<RemoteRepository>();
329 Configuration config = archivaConfiguration.getConfiguration();
330 List<RemoteRepositoryConfiguration> remoteRepoConfigs = config.getRemoteRepositories();
332 for ( RemoteRepositoryConfiguration repoConfig : remoteRepoConfigs )
334 RemoteRepository repo = new RemoteRepository( repoConfig.getId(), repoConfig.getName(), repoConfig.getUrl(),
335 repoConfig.getLayout() );
336 remoteRepos.add( repo );
342 private void saveConfiguration( Configuration config )
347 archivaConfiguration.save( config );
349 catch ( RegistryException e )
351 throw new Exception( "Error occurred in the registry." );
353 catch ( IndeterminateConfigurationException e )
355 throw new Exception( "Error occurred while saving the configuration." );
359 public Boolean addManagedRepository( String repoId, String layout, String name, String location,
360 boolean blockRedeployments, boolean releasesIncluded,
361 boolean snapshotsIncluded, boolean stageRepoNeeded, String cronExpression )
365 Configuration config = archivaConfiguration.getConfiguration();
367 CronExpressionValidator validator = new CronExpressionValidator();
369 if ( config.getManagedRepositoriesAsMap().containsKey( repoId ) )
371 throw new Exception( "Unable to add new repository with id [" + repoId +
372 "], that id already exists as a managed repository." );
374 else if ( config.getRemoteRepositoriesAsMap().containsKey( repoId ) )
376 throw new Exception( "Unable to add new repository with id [" + repoId +
377 "], that id already exists as a remote repository." );
379 else if ( config.getRepositoryGroupsAsMap().containsKey( repoId ) )
381 throw new Exception( "Unable to add new repository with id [" + repoId +
382 "], that id already exists as a repository group." );
385 if ( !validator.validate( cronExpression ) )
387 throw new Exception( "Invalid cron expression." );
390 ManagedRepositoryConfiguration repository = new ManagedRepositoryConfiguration();
392 repository.setId( repoId );
393 repository.setBlockRedeployments( blockRedeployments );
394 repository.setReleases( releasesIncluded );
395 repository.setSnapshots( snapshotsIncluded );
396 repository.setName( name );
397 repository.setLocation( removeExpressions( location ) );
398 repository.setLayout( layout );
399 repository.setRefreshCronExpression( cronExpression );
401 addRepository( repository, config );
403 if ( stageRepoNeeded )
405 ManagedRepositoryConfiguration stagingRepository = getStageRepoConfig( repository );
406 addRepository( stagingRepository, config );
409 saveConfiguration( config );
413 public Boolean deleteManagedRepository( String repoId )
416 Configuration config = archivaConfiguration.getConfiguration();
418 ManagedRepositoryConfiguration repository = config.findManagedRepositoryById( repoId );
420 if ( repository == null )
422 throw new Exception( "A repository with that id does not exist" );
425 RepositorySession repositorySession = repositorySessionFactory.createSession();
428 MetadataRepository metadataRepository = repositorySession.getRepository();
429 metadataRepository.removeRepository( repository.getId() );
430 repositoryStatisticsManager.deleteStatistics( metadataRepository, repository.getId() );
431 repositorySession.save();
435 repositorySession.close();
437 config.removeManagedRepository( repository );
441 saveConfiguration( config );
443 catch ( Exception e )
445 throw new Exception( "Error saving configuration for delete action" + e.getMessage() );
448 File dir = new File( repository.getLocation() );
449 if ( !FileUtils.deleteQuietly( dir ) )
451 throw new IOException( "Cannot delete repository " + dir );
454 List<ProxyConnectorConfiguration> proxyConnectors = config.getProxyConnectors();
455 for ( ProxyConnectorConfiguration proxyConnector : proxyConnectors )
457 if ( StringUtils.equals( proxyConnector.getSourceRepoId(), repository.getId() ) )
459 archivaConfiguration.getConfiguration().removeProxyConnector( proxyConnector );
463 Map<String, List<String>> repoToGroupMap = archivaConfiguration.getConfiguration().getRepositoryToGroupMap();
464 if ( repoToGroupMap != null )
466 if ( repoToGroupMap.containsKey( repository.getId() ) )
468 List<String> repoGroups = repoToGroupMap.get( repository.getId() );
469 for ( String repoGroup : repoGroups )
471 archivaConfiguration.getConfiguration().findRepositoryGroupById( repoGroup ).removeRepository(
472 repository.getId() );
480 public Boolean deleteManagedRepositoryContent( String repoId )
483 Configuration config = archivaConfiguration.getConfiguration();
485 ManagedRepositoryConfiguration repository = config.findManagedRepositoryById( repoId );
487 if ( repository == null )
489 throw new Exception( "Repository Id : " + repoId + " not found." );
492 RepositorySession repositorySession = repositorySessionFactory.createSession();
495 MetadataRepository metadataRepository = repositorySession.getRepository();
496 metadataRepository.removeRepository( repository.getId() );
497 repositorySession.save();
501 repositorySession.close();
504 File repoDir = new File( repository.getLocation() );
505 File[] children = repoDir.listFiles();
507 if ( children != null )
509 for ( File child : children )
511 FileUtils.deleteQuietly( child );
514 if ( repoDir.listFiles().length > 0 )
516 throw new IOException( "Cannot delete repository contents of " + repoDir );
523 public ManagedRepository getManagedRepository( String repoId )
526 Configuration config = archivaConfiguration.getConfiguration();
527 ManagedRepositoryConfiguration managedRepository = config.findManagedRepositoryById( repoId );
528 if ( managedRepository == null )
530 throw new Exception( "A repository with that id does not exist" );
532 ManagedRepository repo = new ManagedRepository( managedRepository.getId(), managedRepository.getName(), "URL",
533 managedRepository.getLayout(), managedRepository.isSnapshots(),
534 managedRepository.isReleases() );
539 public boolean merge( String repoId, boolean skipConflicts )
542 String stagingId = repoId + STAGE;
543 ManagedRepositoryConfiguration repoConfig;
544 ManagedRepositoryConfiguration stagingConfig;
546 Configuration config = archivaConfiguration.getConfiguration();
547 repoConfig = config.findManagedRepositoryById( repoId );
549 log.debug( "Retrieved repository configuration for repo '" + repoId + "'" );
551 RepositorySession repositorySession = repositorySessionFactory.createSession();
554 MetadataRepository metadataRepository = repositorySession.getRepository();
555 if ( repoConfig != null )
557 stagingConfig = config.findManagedRepositoryById( stagingId );
559 if ( stagingConfig != null )
561 List<ArtifactMetadata> sourceArtifacts = metadataRepository.getArtifacts( stagingId );
563 if ( repoConfig.isReleases() && !repoConfig.isSnapshots() )
565 log.info( "Repository to be merged contains releases only.." );
568 List<ArtifactMetadata> conflicts = repositoryMerger.getConflictingArtifacts(
569 metadataRepository, repoId, stagingId );
571 if ( log.isDebugEnabled() )
573 log.debug( "Artifacts in conflict.." );
574 for ( ArtifactMetadata metadata : conflicts )
576 log.debug( metadata.getNamespace() + ":" + metadata.getProject() + ":" +
577 metadata.getProjectVersion() );
581 sourceArtifacts.removeAll( conflicts );
583 log.debug( "Source artifacts size :: " + sourceArtifacts.size() );
584 mergeWithOutSnapshots( sourceArtifacts, stagingId, repoId, metadataRepository );
588 log.debug( "Source artifacts size :: " + sourceArtifacts.size() );
589 mergeWithOutSnapshots( sourceArtifacts, stagingId, repoId, metadataRepository );
594 log.info( "Repository to be merged has snapshot artifacts.." );
597 List<ArtifactMetadata> conflicts = repositoryMerger.getConflictingArtifacts(
598 metadataRepository, repoId, stagingId );
600 if ( log.isDebugEnabled() )
602 log.debug( "Artifacts in conflict.." );
603 for ( ArtifactMetadata metadata : conflicts )
605 log.debug( metadata.getNamespace() + ":" + metadata.getProject() + ":" +
606 metadata.getProjectVersion() );
610 sourceArtifacts.removeAll( conflicts );
612 log.debug( "Source artifacts size :: " + sourceArtifacts.size() );
614 Filter<ArtifactMetadata> artifactsWithOutConflicts = new IncludesFilter<ArtifactMetadata>(
616 repositoryMerger.merge( metadataRepository, stagingId, repoId, artifactsWithOutConflicts );
618 log.info( "Staging repository '" + stagingId + "' merged successfully with managed repo '" +
623 repositoryMerger.merge( metadataRepository, stagingId, repoId );
625 log.info( "Staging repository '" + stagingId + "' merged successfully with managed repo '" +
632 throw new Exception( "Staging Id : " + stagingId + " not found." );
637 throw new Exception( "Repository Id : " + repoId + " not found." );
640 if ( !repositoryTaskScheduler.isProcessingRepositoryTask( repoId ) )
642 RepositoryTask task = new RepositoryTask();
643 task.setRepositoryId( repoId );
645 repositoryTaskScheduler.queueTask( task );
648 AuditEvent event = createAuditEvent( repoConfig );
650 // add event for audit log reports
651 metadataRepository.addMetadataFacet( event.getRepositoryId(), event );
653 // log event in archiva audit log
654 auditListener.auditEvent( createAuditEvent( repoConfig ) );
655 repositorySession.save();
659 repositorySession.close();
665 protected void addRepository( ManagedRepositoryConfiguration repository, Configuration configuration )
668 // Normalize the path
669 File file = new File( repository.getLocation() );
670 repository.setLocation( file.getCanonicalPath() );
671 if ( !file.exists() )
675 if ( !file.exists() || !file.isDirectory() )
677 throw new IOException(
678 "Unable to add repository - no write access, can not create the root directory: " + file );
681 configuration.addManagedRepository( repository );
684 // todo: setting userid of audit event
685 private AuditEvent createAuditEvent( ManagedRepositoryConfiguration repoConfig )
688 AuditEvent event = new AuditEvent();
689 event.setAction( AuditEvent.MERGE_REPO_REMOTE );
690 event.setRepositoryId( repoConfig.getId() );
691 event.setResource( repoConfig.getLocation() );
692 event.setTimestamp( new Date() );
697 private void mergeWithOutSnapshots( List<ArtifactMetadata> sourceArtifacts, String sourceRepoId, String repoid,
698 MetadataRepository metadataRepository )
701 List<ArtifactMetadata> artifactsWithOutSnapshots = new ArrayList<ArtifactMetadata>();
702 for ( ArtifactMetadata metadata : sourceArtifacts )
705 if ( metadata.getProjectVersion().contains( "SNAPSHOT" ) )
707 artifactsWithOutSnapshots.add( metadata );
711 sourceArtifacts.removeAll( artifactsWithOutSnapshots );
713 Filter<ArtifactMetadata> artifactListWithOutSnapShots = new IncludesFilter<ArtifactMetadata>( sourceArtifacts );
715 repositoryMerger.merge( metadataRepository, sourceRepoId, repoid, artifactListWithOutSnapShots );
718 private ManagedRepositoryConfiguration getStageRepoConfig( ManagedRepositoryConfiguration repository )
720 ManagedRepositoryConfiguration stagingRepository = new ManagedRepositoryConfiguration();
721 stagingRepository.setId( repository.getId() + "-stage" );
722 stagingRepository.setLayout( repository.getLayout() );
723 stagingRepository.setName( repository.getName() + "-stage" );
724 stagingRepository.setBlockRedeployments( repository.isBlockRedeployments() );
725 stagingRepository.setDaysOlder( repository.getDaysOlder() );
726 stagingRepository.setDeleteReleasedSnapshots( repository.isDeleteReleasedSnapshots() );
727 stagingRepository.setIndexDir( repository.getIndexDir() );
728 String path = repository.getLocation();
729 int lastIndex = path.lastIndexOf( '/' );
730 stagingRepository.setLocation( path.substring( 0, lastIndex ) + "/" + stagingRepository.getId() );
731 stagingRepository.setRefreshCronExpression( repository.getRefreshCronExpression() );
732 stagingRepository.setReleases( repository.isReleases() );
733 stagingRepository.setRetentionCount( repository.getRetentionCount() );
734 stagingRepository.setScanned( repository.isScanned() );
735 stagingRepository.setSnapshots( repository.isSnapshots() );
736 return stagingRepository;
739 private String removeExpressions( String directory )
741 String value = StringUtils.replace( directory, "${appserver.base}", registry.getString( "appserver.base",
742 "${appserver.base}" ) );
743 value = StringUtils.replace( value, "${appserver.home}", registry.getString( "appserver.home",
744 "${appserver.home}" ) );