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.admin.AuditInformation;
23 import org.apache.archiva.admin.repository.RepositoryAdminException;
24 import org.apache.archiva.admin.repository.managed.ManagedRepositoryAdmin;
25 import org.apache.archiva.admin.repository.remote.RemoteRepositoryAdmin;
26 import org.apache.archiva.audit.AuditEvent;
27 import org.apache.archiva.audit.AuditListener;
28 import org.apache.archiva.metadata.model.ArtifactMetadata;
29 import org.apache.archiva.metadata.repository.MetadataRepository;
30 import org.apache.archiva.metadata.repository.RepositorySession;
31 import org.apache.archiva.metadata.repository.RepositorySessionFactory;
32 import org.apache.archiva.metadata.repository.filter.Filter;
33 import org.apache.archiva.metadata.repository.filter.IncludesFilter;
34 import org.apache.archiva.metadata.repository.stats.RepositoryStatisticsManager;
35 import org.apache.archiva.repository.events.RepositoryListener;
36 import org.apache.archiva.repository.scanner.RepositoryContentConsumers;
37 import org.apache.archiva.scheduler.repository.RepositoryArchivaTaskScheduler;
38 import org.apache.archiva.scheduler.repository.RepositoryTask;
39 import org.apache.archiva.stagerepository.merge.RepositoryMerger;
40 import org.apache.archiva.web.xmlrpc.api.AdministrationService;
41 import org.apache.archiva.web.xmlrpc.api.beans.ManagedRepository;
42 import org.apache.archiva.web.xmlrpc.api.beans.RemoteRepository;
43 import org.apache.commons.io.FileUtils;
44 import org.apache.commons.lang.StringUtils;
45 import org.apache.maven.archiva.configuration.ArchivaConfiguration;
46 import org.apache.maven.archiva.configuration.Configuration;
47 import org.apache.maven.archiva.configuration.IndeterminateConfigurationException;
48 import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
49 import org.apache.maven.archiva.configuration.ProxyConnectorConfiguration;
50 import org.apache.maven.archiva.configuration.RepositoryScanningConfiguration;
51 import org.apache.maven.archiva.consumers.InvalidRepositoryContentConsumer;
52 import org.apache.maven.archiva.consumers.KnownRepositoryContentConsumer;
53 import org.apache.maven.archiva.model.VersionedReference;
54 import org.apache.maven.archiva.repository.ContentNotFoundException;
55 import org.apache.maven.archiva.repository.ManagedRepositoryContent;
56 import org.apache.maven.archiva.repository.RepositoryContentFactory;
57 import org.apache.maven.archiva.repository.RepositoryException;
58 import org.apache.maven.archiva.repository.RepositoryNotFoundException;
59 import org.codehaus.plexus.registry.RegistryException;
60 import org.slf4j.Logger;
61 import org.slf4j.LoggerFactory;
64 import java.io.IOException;
65 import java.util.ArrayList;
66 import java.util.Collection;
67 import java.util.Date;
68 import java.util.List;
72 * AdministrationServiceImpl
74 * @version $Id: AdministrationServiceImpl.java
76 public class AdministrationServiceImpl
77 implements AdministrationService
79 protected Logger log = LoggerFactory.getLogger( getClass() );
81 private ArchivaConfiguration archivaConfiguration;
83 private RepositoryContentConsumers repoConsumersUtil;
85 private RepositoryContentFactory repoFactory;
87 private RepositoryArchivaTaskScheduler repositoryTaskScheduler;
89 private Collection<RepositoryListener> listeners;
91 private RepositoryStatisticsManager repositoryStatisticsManager;
93 private RepositoryMerger repositoryMerger;
95 private static final String STAGE = "-stage";
97 private AuditListener auditListener;
99 private RepositorySessionFactory repositorySessionFactory;
101 private ManagedRepositoryAdmin managedRepositoryAdmin;
103 private RemoteRepositoryAdmin remoteRepositoryAdmin;
105 private static final String REPOSITORY_ID_VALID_EXPRESSION = "^[a-zA-Z0-9._-]+$";
107 private static final String REPOSITORY_NAME_VALID_EXPRESSION = "^([a-zA-Z0-9.)/_(-]|\\s)+$";
109 private static final String REPOSITORY_LOCATION_VALID_EXPRESSION = "^[-a-zA-Z0-9._/~:?!&=\\\\]+$";
111 public AdministrationServiceImpl( ArchivaConfiguration archivaConfig, RepositoryContentConsumers repoConsumersUtil,
112 RepositoryContentFactory repoFactory,
113 RepositorySessionFactory repositorySessionFactory,
114 RepositoryArchivaTaskScheduler repositoryTaskScheduler,
115 Collection<RepositoryListener> listeners,
116 RepositoryStatisticsManager repositoryStatisticsManager,
117 RepositoryMerger repositoryMerger, AuditListener auditListener,
118 ManagedRepositoryAdmin managedRepositoryAdmin,
119 RemoteRepositoryAdmin remoteRepositoryAdmin )
121 this.archivaConfiguration = archivaConfig;
122 this.repoConsumersUtil = repoConsumersUtil;
123 this.repoFactory = repoFactory;
124 this.repositoryTaskScheduler = repositoryTaskScheduler;
125 this.listeners = listeners;
126 this.repositorySessionFactory = repositorySessionFactory;
127 this.repositoryStatisticsManager = repositoryStatisticsManager;
128 this.repositoryMerger = repositoryMerger;
129 this.auditListener = auditListener;
130 this.managedRepositoryAdmin = managedRepositoryAdmin;
131 this.remoteRepositoryAdmin = remoteRepositoryAdmin;
135 * @see AdministrationService#configureRepositoryConsumer(String, String, boolean)
137 public Boolean configureRepositoryConsumer( String repoId, String consumerId, boolean enable )
140 // TODO use repoId once consumers are configured per repository! (MRM-930)
142 List<KnownRepositoryContentConsumer> knownConsumers = repoConsumersUtil.getAvailableKnownConsumers();
143 List<InvalidRepositoryContentConsumer> invalidConsumers = repoConsumersUtil.getAvailableInvalidConsumers();
145 boolean found = false;
146 boolean isKnownContentConsumer = false;
147 for ( KnownRepositoryContentConsumer consumer : knownConsumers )
149 if ( consumer.getId().equals( consumerId ) )
152 isKnownContentConsumer = true;
159 for ( InvalidRepositoryContentConsumer consumer : invalidConsumers )
161 if ( consumer.getId().equals( consumerId ) )
171 throw new Exception( "Invalid repository consumer." );
174 Configuration config = archivaConfiguration.getConfiguration();
175 RepositoryScanningConfiguration repoScanningConfig = config.getRepositoryScanning();
177 if ( isKnownContentConsumer )
179 repoScanningConfig.addKnownContentConsumer( consumerId );
183 repoScanningConfig.addInvalidContentConsumer( consumerId );
186 config.setRepositoryScanning( repoScanningConfig );
187 saveConfiguration( config );
193 * @see AdministrationService#deleteArtifact(String, String, String, String)
195 public Boolean deleteArtifact( String repoId, String groupId, String artifactId, String version )
198 // TODO: remove duplication with web
200 Configuration config = archivaConfiguration.getConfiguration();
201 ManagedRepositoryConfiguration repoConfig = config.findManagedRepositoryById( repoId );
203 if ( repoConfig == null )
205 throw new Exception( "Repository does not exist." );
208 RepositorySession repositorySession = repositorySessionFactory.createSession();
211 ManagedRepositoryContent repoContent = repoFactory.getManagedRepositoryContent( repoId );
212 VersionedReference ref = new VersionedReference();
213 ref.setGroupId( groupId );
214 ref.setArtifactId( artifactId );
215 ref.setVersion( version );
217 // delete from file system
218 repoContent.deleteVersion( ref );
220 MetadataRepository metadataRepository = repositorySession.getRepository();
221 Collection<ArtifactMetadata> artifacts =
222 metadataRepository.getArtifacts( repoId, groupId, artifactId, version );
224 for ( ArtifactMetadata artifact : artifacts )
226 // TODO: mismatch between artifact (snapshot) version and project (base) version here
227 if ( artifact.getVersion().equals( version ) )
229 metadataRepository.removeArtifact( artifact.getRepositoryId(), artifact.getNamespace(),
230 artifact.getProject(), artifact.getVersion(), artifact.getId() );
232 // TODO: move into the metadata repository proper - need to differentiate attachment of
233 // repository metadata to an artifact
234 for ( RepositoryListener listener : listeners )
236 listener.deleteArtifact( metadataRepository, repoId, artifact.getNamespace(),
237 artifact.getProject(), artifact.getVersion(), artifact.getId() );
241 repositorySession.save();
243 catch ( ContentNotFoundException e )
245 throw new Exception( "Artifact does not exist." );
247 catch ( RepositoryNotFoundException e )
249 throw new Exception( "Repository does not exist." );
251 catch ( RepositoryException e )
253 throw new Exception( "Repository exception occurred." );
257 repositorySession.close();
264 * @see AdministrationService#executeRepositoryScanner(String)
266 public Boolean executeRepositoryScanner( String repoId )
269 Configuration config = archivaConfiguration.getConfiguration();
270 if ( config.findManagedRepositoryById( repoId ) == null )
272 throw new Exception( "Repository does not exist." );
275 if ( repositoryTaskScheduler.isProcessingRepositoryTask( repoId ) )
280 RepositoryTask task = new RepositoryTask();
281 task.setRepositoryId( repoId );
282 repositoryTaskScheduler.queueTask( task );
288 * @see AdministrationService#getAllRepositoryConsumers()
290 public List<String> getAllRepositoryConsumers()
292 List<String> consumers = new ArrayList<String>();
294 List<KnownRepositoryContentConsumer> knownConsumers = repoConsumersUtil.getAvailableKnownConsumers();
295 List<InvalidRepositoryContentConsumer> invalidConsumers = repoConsumersUtil.getAvailableInvalidConsumers();
297 for ( KnownRepositoryContentConsumer consumer : knownConsumers )
299 consumers.add( consumer.getId() );
302 for ( InvalidRepositoryContentConsumer consumer : invalidConsumers )
304 consumers.add( consumer.getId() );
311 * @see AdministrationService#getAllManagedRepositories()
313 public List<ManagedRepository> getAllManagedRepositories()
314 throws RepositoryAdminException
316 List<ManagedRepository> managedRepos = new ArrayList<ManagedRepository>();
318 for ( org.apache.archiva.admin.repository.managed.ManagedRepository repoConfig : managedRepositoryAdmin.getManagedRepositories() )
320 ManagedRepository repo =
321 new ManagedRepository( repoConfig.getId(), repoConfig.getName(), repoConfig.getLocation(),
322 repoConfig.getLayout(), repoConfig.isSnapshots(), repoConfig.isReleases() );
323 managedRepos.add( repo );
330 * @see AdministrationService#getAllRemoteRepositories()
332 public List<RemoteRepository> getAllRemoteRepositories()
333 throws RepositoryAdminException
335 List<RemoteRepository> remoteRepos = new ArrayList<RemoteRepository>();
337 for ( org.apache.archiva.admin.repository.remote.RemoteRepository repoConfig : remoteRepositoryAdmin.getRemoteRepositories() )
339 RemoteRepository repo = new RemoteRepository( repoConfig.getId(), repoConfig.getName(), repoConfig.getUrl(),
340 repoConfig.getLayout() );
341 remoteRepos.add( repo );
347 private void saveConfiguration( Configuration config )
352 archivaConfiguration.save( config );
354 catch ( RegistryException e )
356 throw new Exception( "Error occurred in the registry." );
358 catch ( IndeterminateConfigurationException e )
360 throw new Exception( "Error occurred while saving the configuration." );
364 public Boolean addManagedRepository( String repoId, String layout, String name, String location,
365 boolean blockRedeployments, boolean releasesIncluded,
366 boolean snapshotsIncluded, boolean stageRepoNeeded, String cronExpression,
367 int daysOlder, int retentionCount, boolean deleteReleasedSnapshots )
371 org.apache.archiva.admin.repository.managed.ManagedRepository repository =
372 new org.apache.archiva.admin.repository.managed.ManagedRepository( repoId, name, location, layout,
373 snapshotsIncluded, releasesIncluded,
374 blockRedeployments, cronExpression, null,
375 false, daysOlder, retentionCount,
376 deleteReleasedSnapshots );
377 return managedRepositoryAdmin.addManagedRepository( repository, stageRepoNeeded, getAuditInformation() );
381 public Boolean deleteManagedRepository( String repoId )
384 Configuration config = archivaConfiguration.getConfiguration();
386 ManagedRepositoryConfiguration repository = config.findManagedRepositoryById( repoId );
388 if ( repository == null )
390 throw new Exception( "A repository with that id does not exist" );
393 RepositorySession repositorySession = repositorySessionFactory.createSession();
396 MetadataRepository metadataRepository = repositorySession.getRepository();
397 metadataRepository.removeRepository( repository.getId() );
398 repositoryStatisticsManager.deleteStatistics( metadataRepository, repository.getId() );
399 repositorySession.save();
403 repositorySession.close();
405 config.removeManagedRepository( repository );
409 saveConfiguration( config );
411 catch ( Exception e )
413 throw new Exception( "Error saving configuration for delete action" + e.getMessage() );
416 File dir = new File( repository.getLocation() );
417 if ( !FileUtils.deleteQuietly( dir ) )
419 throw new IOException( "Cannot delete repository " + dir );
422 List<ProxyConnectorConfiguration> proxyConnectors = config.getProxyConnectors();
423 for ( ProxyConnectorConfiguration proxyConnector : proxyConnectors )
425 if ( StringUtils.equals( proxyConnector.getSourceRepoId(), repository.getId() ) )
427 archivaConfiguration.getConfiguration().removeProxyConnector( proxyConnector );
431 Map<String, List<String>> repoToGroupMap = archivaConfiguration.getConfiguration().getRepositoryToGroupMap();
432 if ( repoToGroupMap != null )
434 if ( repoToGroupMap.containsKey( repository.getId() ) )
436 List<String> repoGroups = repoToGroupMap.get( repository.getId() );
437 for ( String repoGroup : repoGroups )
439 archivaConfiguration.getConfiguration().findRepositoryGroupById( repoGroup ).removeRepository(
440 repository.getId() );
448 public Boolean deleteManagedRepositoryContent( String repoId )
451 Configuration config = archivaConfiguration.getConfiguration();
453 ManagedRepositoryConfiguration repository = config.findManagedRepositoryById( repoId );
455 if ( repository == null )
457 throw new Exception( "Repository Id : " + repoId + " not found." );
460 RepositorySession repositorySession = repositorySessionFactory.createSession();
463 MetadataRepository metadataRepository = repositorySession.getRepository();
464 metadataRepository.removeRepository( repository.getId() );
465 repositorySession.save();
469 repositorySession.close();
472 File repoDir = new File( repository.getLocation() );
473 File[] children = repoDir.listFiles();
475 if ( children != null )
477 for ( File child : children )
479 FileUtils.deleteQuietly( child );
482 if ( repoDir.listFiles().length > 0 )
484 throw new IOException( "Cannot delete repository contents of " + repoDir );
491 public ManagedRepository getManagedRepository( String repoId )
494 Configuration config = archivaConfiguration.getConfiguration();
495 ManagedRepositoryConfiguration managedRepository = config.findManagedRepositoryById( repoId );
496 if ( managedRepository == null )
498 throw new Exception( "A repository with that id does not exist" );
500 ManagedRepository repo = new ManagedRepository( managedRepository.getId(), managedRepository.getName(), "URL",
501 managedRepository.getLayout(), managedRepository.isSnapshots(),
502 managedRepository.isReleases() );
507 public boolean merge( String repoId, boolean skipConflicts )
510 String stagingId = repoId + STAGE;
511 ManagedRepositoryConfiguration repoConfig;
512 ManagedRepositoryConfiguration stagingConfig;
514 Configuration config = archivaConfiguration.getConfiguration();
515 repoConfig = config.findManagedRepositoryById( repoId );
517 log.debug( "Retrieved repository configuration for repo '" + repoId + "'" );
519 RepositorySession repositorySession = repositorySessionFactory.createSession();
522 MetadataRepository metadataRepository = repositorySession.getRepository();
523 if ( repoConfig != null )
525 stagingConfig = config.findManagedRepositoryById( stagingId );
527 if ( stagingConfig != null )
529 List<ArtifactMetadata> sourceArtifacts = metadataRepository.getArtifacts( stagingId );
531 if ( repoConfig.isReleases() && !repoConfig.isSnapshots() )
533 log.info( "Repository to be merged contains releases only.." );
536 List<ArtifactMetadata> conflicts =
537 repositoryMerger.getConflictingArtifacts( metadataRepository, repoId, stagingId );
539 if ( log.isDebugEnabled() )
541 log.debug( "Artifacts in conflict.." );
542 for ( ArtifactMetadata metadata : conflicts )
544 log.debug( metadata.getNamespace() + ":" + metadata.getProject() + ":"
545 + metadata.getProjectVersion() );
549 sourceArtifacts.removeAll( conflicts );
551 log.debug( "Source artifacts size :: " + sourceArtifacts.size() );
552 mergeWithOutSnapshots( sourceArtifacts, stagingId, repoId, metadataRepository );
556 log.debug( "Source artifacts size :: " + sourceArtifacts.size() );
557 mergeWithOutSnapshots( sourceArtifacts, stagingId, repoId, metadataRepository );
562 log.info( "Repository to be merged has snapshot artifacts.." );
565 List<ArtifactMetadata> conflicts =
566 repositoryMerger.getConflictingArtifacts( metadataRepository, repoId, stagingId );
568 if ( log.isDebugEnabled() )
570 log.debug( "Artifacts in conflict.." );
571 for ( ArtifactMetadata metadata : conflicts )
573 log.debug( metadata.getNamespace() + ":" + metadata.getProject() + ":"
574 + metadata.getProjectVersion() );
578 sourceArtifacts.removeAll( conflicts );
580 log.debug( "Source artifacts size :: " + sourceArtifacts.size() );
582 Filter<ArtifactMetadata> artifactsWithOutConflicts =
583 new IncludesFilter<ArtifactMetadata>( sourceArtifacts );
584 repositoryMerger.merge( metadataRepository, stagingId, repoId, artifactsWithOutConflicts );
586 log.info( "Staging repository '" + stagingId + "' merged successfully with managed repo '"
591 repositoryMerger.merge( metadataRepository, stagingId, repoId );
593 log.info( "Staging repository '" + stagingId + "' merged successfully with managed repo '"
600 throw new Exception( "Staging Id : " + stagingId + " not found." );
605 throw new Exception( "Repository Id : " + repoId + " not found." );
608 if ( !repositoryTaskScheduler.isProcessingRepositoryTask( repoId ) )
610 RepositoryTask task = new RepositoryTask();
611 task.setRepositoryId( repoId );
613 repositoryTaskScheduler.queueTask( task );
616 AuditEvent event = createAuditEvent( repoConfig );
618 // add event for audit log reports
619 metadataRepository.addMetadataFacet( event.getRepositoryId(), event );
621 // log event in archiva audit log
622 auditListener.auditEvent( createAuditEvent( repoConfig ) );
623 repositorySession.save();
627 repositorySession.close();
633 // todo: setting userid of audit event
634 private AuditEvent createAuditEvent( ManagedRepositoryConfiguration repoConfig )
637 AuditEvent event = new AuditEvent();
638 event.setAction( AuditEvent.MERGE_REPO_REMOTE );
639 event.setRepositoryId( repoConfig.getId() );
640 event.setResource( repoConfig.getLocation() );
641 event.setTimestamp( new Date() );
646 private void mergeWithOutSnapshots( List<ArtifactMetadata> sourceArtifacts, String sourceRepoId, String repoid,
647 MetadataRepository metadataRepository )
650 List<ArtifactMetadata> artifactsWithOutSnapshots = new ArrayList<ArtifactMetadata>();
651 for ( ArtifactMetadata metadata : sourceArtifacts )
654 if ( metadata.getProjectVersion().contains( "SNAPSHOT" ) )
656 artifactsWithOutSnapshots.add( metadata );
660 sourceArtifacts.removeAll( artifactsWithOutSnapshots );
662 Filter<ArtifactMetadata> artifactListWithOutSnapShots = new IncludesFilter<ArtifactMetadata>( sourceArtifacts );
664 repositoryMerger.merge( metadataRepository, sourceRepoId, repoid, artifactListWithOutSnapShots );
667 private ManagedRepositoryConfiguration getStageRepoConfig( ManagedRepositoryConfiguration repository )
669 ManagedRepositoryConfiguration stagingRepository = new ManagedRepositoryConfiguration();
670 stagingRepository.setId( repository.getId() + "-stage" );
671 stagingRepository.setLayout( repository.getLayout() );
672 stagingRepository.setName( repository.getName() + "-stage" );
673 stagingRepository.setBlockRedeployments( repository.isBlockRedeployments() );
674 stagingRepository.setDaysOlder( repository.getDaysOlder() );
675 stagingRepository.setDeleteReleasedSnapshots( repository.isDeleteReleasedSnapshots() );
676 stagingRepository.setIndexDir( repository.getIndexDir() );
677 String path = repository.getLocation();
678 int lastIndex = path.lastIndexOf( '/' );
679 stagingRepository.setLocation( path.substring( 0, lastIndex ) + "/" + stagingRepository.getId() );
680 stagingRepository.setRefreshCronExpression( repository.getRefreshCronExpression() );
681 stagingRepository.setReleases( repository.isReleases() );
682 stagingRepository.setRetentionCount( repository.getRetentionCount() );
683 stagingRepository.setScanned( repository.isScanned() );
684 stagingRepository.setSnapshots( repository.isSnapshots() );
685 return stagingRepository;
688 // FIXME find a way to get user id and adress
689 private AuditInformation getAuditInformation()
691 return new AuditInformation( null, null );