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.model.AuditInformation;
23 import org.apache.archiva.admin.model.RepositoryAdminException;
24 import org.apache.archiva.admin.model.admin.ArchivaAdministration;
25 import org.apache.archiva.admin.model.beans.ProxyConnector;
26 import org.apache.archiva.admin.model.group.RepositoryGroupAdmin;
27 import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin;
28 import org.apache.archiva.admin.model.proxyconnector.ProxyConnectorAdmin;
29 import org.apache.archiva.admin.model.remote.RemoteRepositoryAdmin;
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.RepositorySession;
35 import org.apache.archiva.metadata.repository.RepositorySessionFactory;
36 import org.apache.archiva.metadata.repository.filter.Filter;
37 import org.apache.archiva.metadata.repository.filter.IncludesFilter;
38 import org.apache.archiva.metadata.repository.stats.RepositoryStatisticsManager;
39 import org.apache.archiva.repository.events.RepositoryListener;
40 import org.apache.archiva.repository.scanner.RepositoryContentConsumers;
41 import org.apache.archiva.scheduler.repository.RepositoryArchivaTaskScheduler;
42 import org.apache.archiva.scheduler.repository.RepositoryTask;
43 import org.apache.archiva.stagerepository.merge.RepositoryMerger;
44 import org.apache.archiva.web.xmlrpc.api.AdministrationService;
45 import org.apache.archiva.web.xmlrpc.api.beans.ManagedRepository;
46 import org.apache.archiva.web.xmlrpc.api.beans.RemoteRepository;
47 import org.apache.commons.io.FileUtils;
48 import org.apache.commons.lang.StringUtils;
49 import org.apache.archiva.consumers.InvalidRepositoryContentConsumer;
50 import org.apache.archiva.consumers.KnownRepositoryContentConsumer;
51 import org.apache.archiva.model.VersionedReference;
52 import org.apache.archiva.repository.ContentNotFoundException;
53 import org.apache.archiva.repository.ManagedRepositoryContent;
54 import org.apache.archiva.repository.RepositoryContentFactory;
55 import org.apache.archiva.repository.RepositoryException;
56 import org.apache.archiva.repository.RepositoryNotFoundException;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
61 import java.io.IOException;
62 import java.util.ArrayList;
63 import java.util.Collection;
64 import java.util.Date;
65 import java.util.List;
69 * AdministrationServiceImpl
71 * @version $Id: AdministrationServiceImpl.java
73 public class AdministrationServiceImpl
74 implements AdministrationService
76 protected Logger log = LoggerFactory.getLogger( getClass() );
78 private RepositoryContentConsumers repoConsumersUtil;
80 private RepositoryContentFactory repoFactory;
82 private RepositoryArchivaTaskScheduler repositoryTaskScheduler;
84 private Collection<RepositoryListener> listeners;
86 private RepositoryStatisticsManager repositoryStatisticsManager;
88 private RepositoryMerger repositoryMerger;
90 private static final String STAGE = "-stage";
92 private AuditListener auditListener;
94 private RepositorySessionFactory repositorySessionFactory;
96 private ManagedRepositoryAdmin managedRepositoryAdmin;
98 private RemoteRepositoryAdmin remoteRepositoryAdmin;
100 private ArchivaAdministration archivaAdministration;
102 private ProxyConnectorAdmin proxyConnectorAdmin;
104 private RepositoryGroupAdmin repositoryGroupAdmin;
106 private static final String REPOSITORY_ID_VALID_EXPRESSION = "^[a-zA-Z0-9._-]+$";
108 private static final String REPOSITORY_NAME_VALID_EXPRESSION = "^([a-zA-Z0-9.)/_(-]|\\s)+$";
110 private static final String REPOSITORY_LOCATION_VALID_EXPRESSION = "^[-a-zA-Z0-9._/~:?!&=\\\\]+$";
112 public AdministrationServiceImpl( ArchivaAdministration archivaAdministration,
113 RepositoryContentConsumers repoConsumersUtil,
114 RepositoryContentFactory repoFactory,
115 RepositorySessionFactory repositorySessionFactory,
116 RepositoryArchivaTaskScheduler repositoryTaskScheduler,
117 Collection<RepositoryListener> listeners,
118 RepositoryStatisticsManager repositoryStatisticsManager,
119 RepositoryMerger repositoryMerger, AuditListener auditListener,
120 ManagedRepositoryAdmin managedRepositoryAdmin,
121 RemoteRepositoryAdmin remoteRepositoryAdmin,
122 ProxyConnectorAdmin proxyConnectorAdmin,
123 RepositoryGroupAdmin repositoryGroupAdmin )
125 this.repoConsumersUtil = repoConsumersUtil;
126 this.repoFactory = repoFactory;
127 this.repositoryTaskScheduler = repositoryTaskScheduler;
128 this.listeners = listeners;
129 this.repositorySessionFactory = repositorySessionFactory;
130 this.repositoryStatisticsManager = repositoryStatisticsManager;
131 this.repositoryMerger = repositoryMerger;
132 this.auditListener = auditListener;
133 this.managedRepositoryAdmin = managedRepositoryAdmin;
134 this.remoteRepositoryAdmin = remoteRepositoryAdmin;
135 this.archivaAdministration = archivaAdministration;
136 this.proxyConnectorAdmin = proxyConnectorAdmin;
137 this.repositoryGroupAdmin = repositoryGroupAdmin;
141 * @see AdministrationService#configureRepositoryConsumer(String, String, boolean)
143 public Boolean configureRepositoryConsumer( String repoId, String consumerId, boolean enable )
146 // TODO use repoId once consumers are configured per repository! (MRM-930)
148 List<KnownRepositoryContentConsumer> knownConsumers = repoConsumersUtil.getAvailableKnownConsumers();
149 List<InvalidRepositoryContentConsumer> invalidConsumers = repoConsumersUtil.getAvailableInvalidConsumers();
151 boolean found = false;
152 boolean isKnownContentConsumer = false;
153 for ( KnownRepositoryContentConsumer consumer : knownConsumers )
155 if ( consumer.getId().equals( consumerId ) )
158 isKnownContentConsumer = true;
165 for ( InvalidRepositoryContentConsumer consumer : invalidConsumers )
167 if ( consumer.getId().equals( consumerId ) )
177 throw new Exception( "Invalid repository consumer." );
180 if ( isKnownContentConsumer )
184 archivaAdministration.addKnownContentConsumer( consumerId, getAuditInformation() );
188 archivaAdministration.removeKnownContentConsumer( consumerId, getAuditInformation() );
196 archivaAdministration.addInvalidContentConsumer( consumerId, getAuditInformation() );
200 archivaAdministration.removeInvalidContentConsumer( consumerId, getAuditInformation() );
208 * @see AdministrationService#deleteArtifact(String, String, String, String)
210 public Boolean deleteArtifact( String repoId, String groupId, String artifactId, String version )
213 // TODO: remove duplication with web
215 org.apache.archiva.admin.model.beans.ManagedRepository repoConfig =
216 managedRepositoryAdmin.getManagedRepository( repoId );
218 if ( repoConfig == null )
220 throw new Exception( "Repository does not exist." );
223 RepositorySession repositorySession = repositorySessionFactory.createSession();
226 ManagedRepositoryContent repoContent = repoFactory.getManagedRepositoryContent( repoId );
227 VersionedReference ref = new VersionedReference();
228 ref.setGroupId( groupId );
229 ref.setArtifactId( artifactId );
230 ref.setVersion( version );
232 // delete from file system
233 repoContent.deleteVersion( ref );
235 MetadataRepository metadataRepository = repositorySession.getRepository();
236 Collection<ArtifactMetadata> artifacts =
237 metadataRepository.getArtifacts( repoId, groupId, artifactId, version );
239 for ( ArtifactMetadata artifact : artifacts )
241 // TODO: mismatch between artifact (snapshot) version and project (base) version here
242 if ( artifact.getVersion().equals( version ) )
244 metadataRepository.removeArtifact( artifact.getRepositoryId(), artifact.getNamespace(),
245 artifact.getProject(), artifact.getVersion(), artifact.getId() );
247 // TODO: move into the metadata repository proper - need to differentiate attachment of
248 // repository metadata to an artifact
249 for ( RepositoryListener listener : listeners )
251 listener.deleteArtifact( metadataRepository, repoId, artifact.getNamespace(),
252 artifact.getProject(), artifact.getVersion(), artifact.getId() );
256 repositorySession.save();
258 catch ( ContentNotFoundException e )
260 throw new Exception( "Artifact does not exist." );
262 catch ( RepositoryNotFoundException e )
264 throw new Exception( "Repository does not exist." );
266 catch ( RepositoryException e )
268 throw new Exception( "Repository exception occurred." );
272 repositorySession.close();
279 * @see AdministrationService#executeRepositoryScanner(String)
281 public Boolean executeRepositoryScanner( String repoId )
284 if ( managedRepositoryAdmin.getManagedRepository( repoId ) == null )
286 throw new Exception( "Repository does not exist." );
289 if ( repositoryTaskScheduler.isProcessingRepositoryTask( repoId ) )
294 RepositoryTask task = new RepositoryTask();
295 task.setRepositoryId( repoId );
296 repositoryTaskScheduler.queueTask( task );
302 * @see AdministrationService#getAllRepositoryConsumers()
304 public List<String> getAllRepositoryConsumers()
306 List<String> consumers = new ArrayList<String>();
308 List<KnownRepositoryContentConsumer> knownConsumers = repoConsumersUtil.getAvailableKnownConsumers();
309 List<InvalidRepositoryContentConsumer> invalidConsumers = repoConsumersUtil.getAvailableInvalidConsumers();
311 for ( KnownRepositoryContentConsumer consumer : knownConsumers )
313 consumers.add( consumer.getId() );
316 for ( InvalidRepositoryContentConsumer consumer : invalidConsumers )
318 consumers.add( consumer.getId() );
325 * @see AdministrationService#getAllManagedRepositories()
327 public List<ManagedRepository> getAllManagedRepositories()
328 throws RepositoryAdminException
330 List<ManagedRepository> managedRepos = new ArrayList<ManagedRepository>();
332 for ( org.apache.archiva.admin.model.beans.ManagedRepository repoConfig : managedRepositoryAdmin.getManagedRepositories() )
334 ManagedRepository repo =
335 new ManagedRepository( repoConfig.getId(), repoConfig.getName(), repoConfig.getLocation(),
336 repoConfig.getLayout(), repoConfig.isSnapshots(), repoConfig.isReleases() );
337 managedRepos.add( repo );
344 * @see AdministrationService#getAllRemoteRepositories()
346 public List<RemoteRepository> getAllRemoteRepositories()
347 throws RepositoryAdminException
349 List<RemoteRepository> remoteRepos = new ArrayList<RemoteRepository>();
351 for ( org.apache.archiva.admin.model.beans.RemoteRepository repoConfig : remoteRepositoryAdmin.getRemoteRepositories() )
353 RemoteRepository repo = new RemoteRepository( repoConfig.getId(), repoConfig.getName(), repoConfig.getUrl(),
354 repoConfig.getLayout() );
355 remoteRepos.add( repo );
361 public Boolean addManagedRepository( String repoId, String layout, String name, String location,
362 boolean blockRedeployments, boolean releasesIncluded,
363 boolean snapshotsIncluded, boolean stageRepoNeeded, String cronExpression,
364 int daysOlder, int retentionCount, boolean deleteReleasedSnapshots )
368 org.apache.archiva.admin.model.beans.ManagedRepository repository =
369 new org.apache.archiva.admin.model.beans.ManagedRepository( repoId, name, location, layout,
370 snapshotsIncluded, releasesIncluded,
371 blockRedeployments, cronExpression, null, false,
372 daysOlder, retentionCount,
373 deleteReleasedSnapshots, false );
374 return managedRepositoryAdmin.addManagedRepository( repository, stageRepoNeeded, getAuditInformation() );
378 public Boolean deleteManagedRepository( String repoId )
382 org.apache.archiva.admin.model.beans.ManagedRepository repository =
383 managedRepositoryAdmin.getManagedRepository( repoId );
385 if ( repository == null )
387 throw new Exception( "A repository with that id does not exist" );
390 RepositorySession repositorySession = repositorySessionFactory.createSession();
393 MetadataRepository metadataRepository = repositorySession.getRepository();
394 metadataRepository.removeRepository( repository.getId() );
395 repositoryStatisticsManager.deleteStatistics( metadataRepository, repository.getId() );
396 repositorySession.save();
400 repositorySession.close();
402 managedRepositoryAdmin.deleteManagedRepository( repoId, getAuditInformation(), false );
404 File dir = new File( repository.getLocation() );
405 if ( !FileUtils.deleteQuietly( dir ) )
407 throw new IOException( "Cannot delete repository " + dir );
410 List<ProxyConnector> proxyConnectors = proxyConnectorAdmin.getProxyConnectors();
411 for ( ProxyConnector proxyConnector : proxyConnectors )
413 if ( StringUtils.equals( proxyConnector.getSourceRepoId(), repository.getId() ) )
415 proxyConnectorAdmin.deleteProxyConnector( proxyConnector, getAuditInformation() );
419 Map<String, List<String>> repoToGroupMap = repositoryGroupAdmin.getRepositoryToGroupMap();
420 if ( repoToGroupMap != null )
422 if ( repoToGroupMap.containsKey( repository.getId() ) )
424 List<String> repoGroups = repoToGroupMap.get( repository.getId() );
425 for ( String repoGroup : repoGroups )
427 repositoryGroupAdmin.deleteRepositoryFromGroup( repoGroup, repository.getId(),
428 getAuditInformation() );
436 public Boolean deleteManagedRepositoryContent( String repoId )
440 org.apache.archiva.admin.model.beans.ManagedRepository repository =
441 managedRepositoryAdmin.getManagedRepository( repoId );
443 if ( repository == null )
445 throw new Exception( "Repository Id : " + repoId + " not found." );
448 RepositorySession repositorySession = repositorySessionFactory.createSession();
451 MetadataRepository metadataRepository = repositorySession.getRepository();
452 metadataRepository.removeRepository( repository.getId() );
453 repositorySession.save();
457 repositorySession.close();
460 File repoDir = new File( repository.getLocation() );
461 File[] children = repoDir.listFiles();
463 if ( children != null )
465 for ( File child : children )
467 FileUtils.deleteQuietly( child );
470 if ( repoDir.listFiles().length > 0 )
472 throw new IOException( "Cannot delete repository contents of " + repoDir );
479 public ManagedRepository getManagedRepository( String repoId )
482 org.apache.archiva.admin.model.beans.ManagedRepository managedRepository =
483 managedRepositoryAdmin.getManagedRepository( repoId );
484 if ( managedRepository == null )
486 throw new Exception( "A repository with that id does not exist" );
488 ManagedRepository repo = new ManagedRepository( managedRepository.getId(), managedRepository.getName(), "URL",
489 managedRepository.getLayout(), managedRepository.isSnapshots(),
490 managedRepository.isReleases() );
495 public boolean merge( String repoId, boolean skipConflicts )
498 String stagingId = repoId + STAGE;
499 org.apache.archiva.admin.model.beans.ManagedRepository repoConfig;
500 org.apache.archiva.admin.model.beans.ManagedRepository stagingConfig;
502 repoConfig = managedRepositoryAdmin.getManagedRepository( repoId );
504 log.debug( "Retrieved repository configuration for repo '" + repoId + "'" );
506 RepositorySession repositorySession = repositorySessionFactory.createSession();
509 MetadataRepository metadataRepository = repositorySession.getRepository();
510 if ( repoConfig != null )
512 stagingConfig = managedRepositoryAdmin.getManagedRepository( stagingId );
514 if ( stagingConfig != null )
516 List<ArtifactMetadata> sourceArtifacts = metadataRepository.getArtifacts( stagingId );
518 if ( repoConfig.isReleases() && !repoConfig.isSnapshots() )
520 log.info( "Repository to be merged contains releases only.." );
523 List<ArtifactMetadata> conflicts =
524 repositoryMerger.getConflictingArtifacts( metadataRepository, repoId, stagingId );
526 if ( log.isDebugEnabled() )
528 log.debug( "Artifacts in conflict.." );
529 for ( ArtifactMetadata metadata : conflicts )
531 log.debug( metadata.getNamespace() + ":" + metadata.getProject() + ":"
532 + metadata.getProjectVersion() );
536 sourceArtifacts.removeAll( conflicts );
538 log.debug( "Source artifacts size :: " + sourceArtifacts.size() );
539 mergeWithOutSnapshots( sourceArtifacts, stagingId, repoId, metadataRepository );
543 log.debug( "Source artifacts size :: " + sourceArtifacts.size() );
544 mergeWithOutSnapshots( sourceArtifacts, stagingId, repoId, metadataRepository );
549 log.info( "Repository to be merged has snapshot artifacts.." );
552 List<ArtifactMetadata> conflicts =
553 repositoryMerger.getConflictingArtifacts( metadataRepository, repoId, stagingId );
555 if ( log.isDebugEnabled() )
557 log.debug( "Artifacts in conflict.." );
558 for ( ArtifactMetadata metadata : conflicts )
560 log.debug( metadata.getNamespace() + ":" + metadata.getProject() + ":"
561 + metadata.getProjectVersion() );
565 sourceArtifacts.removeAll( conflicts );
567 log.debug( "Source artifacts size :: " + sourceArtifacts.size() );
569 Filter<ArtifactMetadata> artifactsWithOutConflicts =
570 new IncludesFilter<ArtifactMetadata>( sourceArtifacts );
571 repositoryMerger.merge( metadataRepository, stagingId, repoId, artifactsWithOutConflicts );
573 log.info( "Staging repository '" + stagingId + "' merged successfully with managed repo '"
578 repositoryMerger.merge( metadataRepository, stagingId, repoId );
580 log.info( "Staging repository '" + stagingId + "' merged successfully with managed repo '"
587 throw new Exception( "Staging Id : " + stagingId + " not found." );
592 throw new Exception( "Repository Id : " + repoId + " not found." );
595 if ( !repositoryTaskScheduler.isProcessingRepositoryTask( repoId ) )
597 RepositoryTask task = new RepositoryTask();
598 task.setRepositoryId( repoId );
600 repositoryTaskScheduler.queueTask( task );
603 AuditEvent event = createAuditEvent( repoConfig );
605 // add event for audit log reports
606 metadataRepository.addMetadataFacet( event.getRepositoryId(), event );
608 // log event in archiva audit log
609 auditListener.auditEvent( createAuditEvent( repoConfig ) );
610 repositorySession.save();
614 repositorySession.close();
620 // todo: setting userid of audit event
621 private AuditEvent createAuditEvent( org.apache.archiva.admin.model.beans.ManagedRepository repoConfig )
624 AuditEvent event = new AuditEvent();
625 event.setAction( AuditEvent.MERGE_REPO_REMOTE );
626 event.setRepositoryId( repoConfig.getId() );
627 event.setResource( repoConfig.getLocation() );
628 event.setTimestamp( new Date() );
633 private void mergeWithOutSnapshots( List<ArtifactMetadata> sourceArtifacts, String sourceRepoId, String repoid,
634 MetadataRepository metadataRepository )
637 List<ArtifactMetadata> artifactsWithOutSnapshots = new ArrayList<ArtifactMetadata>();
638 for ( ArtifactMetadata metadata : sourceArtifacts )
641 if ( metadata.getProjectVersion().contains( "SNAPSHOT" ) )
643 artifactsWithOutSnapshots.add( metadata );
647 sourceArtifacts.removeAll( artifactsWithOutSnapshots );
649 Filter<ArtifactMetadata> artifactListWithOutSnapShots = new IncludesFilter<ArtifactMetadata>( sourceArtifacts );
651 repositoryMerger.merge( metadataRepository, sourceRepoId, repoid, artifactListWithOutSnapShots );
655 // FIXME find a way to get user id and adress
656 private AuditInformation getAuditInformation()
658 return new AuditInformation( null, null );