]> source.dussan.org Git - archiva.git/blob
1250ec447c7783cc5be0733526800c8235591fbe
[archiva.git] /
1 package org.apache.archiva.web.xmlrpc.services;
2
3 /*
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
11  *
12  *  http://www.apache.org/licenses/LICENSE-2.0
13  *
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
19  * under the License.
20  */
21
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;
58
59 import java.io.File;
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;
65 import java.util.Map;
66
67 /**
68  * AdministrationServiceImpl
69  *
70  * @version $Id: AdministrationServiceImpl.java
71  */
72 public class AdministrationServiceImpl
73     implements AdministrationService
74 {
75     protected Logger log = LoggerFactory.getLogger( getClass() );
76
77     private ArchivaConfiguration archivaConfiguration;
78
79     private RepositoryContentConsumers repoConsumersUtil;
80
81     private RepositoryContentFactory repoFactory;
82
83     private RepositoryArchivaTaskScheduler repositoryTaskScheduler;
84
85     private Collection<RepositoryListener> listeners;
86
87     private MetadataRepository metadataRepository;
88
89     private RepositoryStatisticsManager repositoryStatisticsManager;
90
91     private RepositoryMerger repositoryMerger;
92
93     private static final String STAGE = "-stage";
94
95     private AuditListener auditListener;
96
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 )
103     {
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;
113     }
114
115     /**
116      * @see AdministrationService#configureRepositoryConsumer(String, String, boolean)
117      */
118     public Boolean configureRepositoryConsumer( String repoId, String consumerId, boolean enable )
119         throws Exception
120     {
121         // TODO use repoId once consumers are configured per repository! (MRM-930)
122
123         List<KnownRepositoryContentConsumer> knownConsumers = repoConsumersUtil.getAvailableKnownConsumers();
124         List<InvalidRepositoryContentConsumer> invalidConsumers = repoConsumersUtil.getAvailableInvalidConsumers();
125
126         boolean found = false;
127         boolean isKnownContentConsumer = false;
128         for ( KnownRepositoryContentConsumer consumer : knownConsumers )
129         {
130             if ( consumer.getId().equals( consumerId ) )
131             {
132                 found = true;
133                 isKnownContentConsumer = true;
134                 break;
135             }
136         }
137
138         if ( !found )
139         {
140             for ( InvalidRepositoryContentConsumer consumer : invalidConsumers )
141             {
142                 if ( consumer.getId().equals( consumerId ) )
143                 {
144                     found = true;
145                     break;
146                 }
147             }
148         }
149
150         if ( !found )
151         {
152             throw new Exception( "Invalid repository consumer." );
153         }
154
155         Configuration config = archivaConfiguration.getConfiguration();
156         RepositoryScanningConfiguration repoScanningConfig = config.getRepositoryScanning();
157
158         if ( isKnownContentConsumer )
159         {
160             repoScanningConfig.addKnownContentConsumer( consumerId );
161         }
162         else
163         {
164             repoScanningConfig.addInvalidContentConsumer( consumerId );
165         }
166
167         config.setRepositoryScanning( repoScanningConfig );
168         saveConfiguration( config );
169
170         return true;
171     }
172
173     /**
174      * @see AdministrationService#deleteArtifact(String, String, String, String)
175      */
176     public Boolean deleteArtifact( String repoId, String groupId, String artifactId, String version )
177         throws Exception
178     {
179         // TODO: remove duplication with web
180
181         Configuration config = archivaConfiguration.getConfiguration();
182         ManagedRepositoryConfiguration repoConfig = config.findManagedRepositoryById( repoId );
183
184         if ( repoConfig == null )
185         {
186             throw new Exception( "Repository does not exist." );
187         }
188
189         try
190         {
191             ManagedRepositoryContent repoContent = repoFactory.getManagedRepositoryContent( repoId );
192             VersionedReference ref = new VersionedReference();
193             ref.setGroupId( groupId );
194             ref.setArtifactId( artifactId );
195             ref.setVersion( version );
196
197             // delete from file system
198             repoContent.deleteVersion( ref );
199
200             Collection<ArtifactMetadata> artifacts = metadataRepository.getArtifacts( repoId, groupId, artifactId,
201                                                                                       version );
202
203             for ( ArtifactMetadata artifact : artifacts )
204             {
205                 // TODO: mismatch between artifact (snapshot) version and project (base) version here
206                 if ( artifact.getVersion().equals( version ) )
207                 {
208                     metadataRepository.removeArtifact( artifact.getRepositoryId(), artifact.getNamespace(),
209                                                        artifact.getProject(), artifact.getVersion(), artifact.getId() );
210
211                     // TODO: move into the metadata repository proper - need to differentiate attachment of
212                     // repository metadata to an artifact
213                     for ( RepositoryListener listener : listeners )
214                     {
215                         listener.deleteArtifact( repoId, artifact.getNamespace(), artifact.getProject(),
216                                                  artifact.getVersion(), artifact.getId() );
217                     }
218                 }
219             }
220         }
221         catch ( ContentNotFoundException e )
222         {
223             throw new Exception( "Artifact does not exist." );
224         }
225         catch ( RepositoryNotFoundException e )
226         {
227             throw new Exception( "Repository does not exist." );
228         }
229         catch ( RepositoryException e )
230         {
231             throw new Exception( "Repository exception occurred." );
232         }
233
234         return true;
235     }
236
237     /**
238      * @see AdministrationService#executeRepositoryScanner(String)
239      */
240     public Boolean executeRepositoryScanner( String repoId )
241         throws Exception
242     {
243         Configuration config = archivaConfiguration.getConfiguration();
244         if ( config.findManagedRepositoryById( repoId ) == null )
245         {
246             throw new Exception( "Repository does not exist." );
247         }
248
249         if ( repositoryTaskScheduler.isProcessingRepositoryTask( repoId ) )
250         {
251             return false;
252         }
253
254         RepositoryTask task = new RepositoryTask();
255         task.setRepositoryId( repoId );
256
257         repositoryTaskScheduler.queueTask( task );
258
259         return true;
260     }
261
262     /**
263      * @see AdministrationService#getAllRepositoryConsumers()
264      */
265     public List<String> getAllRepositoryConsumers()
266     {
267         List<String> consumers = new ArrayList<String>();
268
269         List<KnownRepositoryContentConsumer> knownConsumers = repoConsumersUtil.getAvailableKnownConsumers();
270         List<InvalidRepositoryContentConsumer> invalidConsumers = repoConsumersUtil.getAvailableInvalidConsumers();
271
272         for ( KnownRepositoryContentConsumer consumer : knownConsumers )
273         {
274             consumers.add( consumer.getId() );
275         }
276
277         for ( InvalidRepositoryContentConsumer consumer : invalidConsumers )
278         {
279             consumers.add( consumer.getId() );
280         }
281
282         return consumers;
283     }
284
285     /**
286      * @see AdministrationService#getAllManagedRepositories()
287      */
288     public List<ManagedRepository> getAllManagedRepositories()
289     {
290         List<ManagedRepository> managedRepos = new ArrayList<ManagedRepository>();
291
292         Configuration config = archivaConfiguration.getConfiguration();
293         List<ManagedRepositoryConfiguration> managedRepoConfigs = config.getManagedRepositories();
294
295         for ( ManagedRepositoryConfiguration repoConfig : managedRepoConfigs )
296         {
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 );
302         }
303
304         return managedRepos;
305     }
306
307     /**
308      * @see AdministrationService#getAllRemoteRepositories()
309      */
310     public List<RemoteRepository> getAllRemoteRepositories()
311     {
312         List<RemoteRepository> remoteRepos = new ArrayList<RemoteRepository>();
313
314         Configuration config = archivaConfiguration.getConfiguration();
315         List<RemoteRepositoryConfiguration> remoteRepoConfigs = config.getRemoteRepositories();
316
317         for ( RemoteRepositoryConfiguration repoConfig : remoteRepoConfigs )
318         {
319             RemoteRepository repo = new RemoteRepository( repoConfig.getId(), repoConfig.getName(), repoConfig.getUrl(),
320                                                           repoConfig.getLayout() );
321             remoteRepos.add( repo );
322         }
323
324         return remoteRepos;
325     }
326
327     private void saveConfiguration( Configuration config )
328         throws Exception
329     {
330         try
331         {
332             archivaConfiguration.save( config );
333         }
334         catch ( RegistryException e )
335         {
336             throw new Exception( "Error occurred in the registry." );
337         }
338         catch ( IndeterminateConfigurationException e )
339         {
340             throw new Exception( "Error occurred while saving the configuration." );
341         }
342     }
343
344     public Boolean addManagedRepository( String repoId, String layout, String name, String location,
345                                          boolean blockRedeployments, boolean releasesIncluded,
346                                          boolean snapshotsIncluded, boolean stageRepoNeeded, String cronExpression )
347         throws Exception
348     {
349
350         Configuration config = archivaConfiguration.getConfiguration();
351
352         CronExpressionValidator validator = new CronExpressionValidator();
353
354         if ( config.getManagedRepositoriesAsMap().containsKey( repoId ) )
355         {
356             throw new Exception( "Unable to add new repository with id [" + repoId +
357                                      "], that id already exists as a managed repository." );
358         }
359         else if ( config.getRemoteRepositoriesAsMap().containsKey( repoId ) )
360         {
361             throw new Exception( "Unable to add new repository with id [" + repoId +
362                                      "], that id already exists as a remote repository." );
363         }
364         else if ( config.getRepositoryGroupsAsMap().containsKey( repoId ) )
365         {
366             throw new Exception( "Unable to add new repository with id [" + repoId +
367                                      "], that id already exists as a repository group." );
368         }
369
370         if ( !validator.validate( cronExpression ) )
371         {
372             throw new Exception( "Invalid cron expression." );
373         }
374
375         ManagedRepositoryConfiguration repository = new ManagedRepositoryConfiguration();
376
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 );
385
386         addRepository( repository, config );
387
388         if ( stageRepoNeeded )
389         {
390             ManagedRepositoryConfiguration stagingRepository = getStageRepoConfig( repository );
391             addRepository( stagingRepository, config );
392         }
393
394         saveConfiguration( config );
395         return Boolean.TRUE;
396     }
397
398     public Boolean deleteManagedRepository( String repoId )
399         throws Exception
400     {
401         Configuration config = archivaConfiguration.getConfiguration();
402
403         ManagedRepositoryConfiguration repository = config.findManagedRepositoryById( repoId );
404
405         if ( repository == null )
406         {
407             throw new Exception( "A repository with that id does not exist" );
408         }
409
410         metadataRepository.removeRepository( repository.getId() );
411         repositoryStatisticsManager.deleteStatistics( repository.getId() );
412         config.removeManagedRepository( repository );
413
414         try
415         {
416             saveConfiguration( config );
417         }
418         catch ( Exception e )
419         {
420             throw new Exception( "Error saving configuration for delete action" + e.getMessage() );
421         }
422
423         FileUtils.deleteDirectory( new File( repository.getLocation() ) );
424
425         List<ProxyConnectorConfiguration> proxyConnectors = config.getProxyConnectors();
426         for ( ProxyConnectorConfiguration proxyConnector : proxyConnectors )
427         {
428             if ( StringUtils.equals( proxyConnector.getSourceRepoId(), repository.getId() ) )
429             {
430                 archivaConfiguration.getConfiguration().removeProxyConnector( proxyConnector );
431             }
432         }
433
434         Map<String, List<String>> repoToGroupMap = archivaConfiguration.getConfiguration().getRepositoryToGroupMap();
435         if ( repoToGroupMap != null )
436         {
437             if ( repoToGroupMap.containsKey( repository.getId() ) )
438             {
439                 List<String> repoGroups = repoToGroupMap.get( repository.getId() );
440                 for ( String repoGroup : repoGroups )
441                 {
442                     archivaConfiguration.getConfiguration().findRepositoryGroupById( repoGroup ).removeRepository(
443                         repository.getId() );
444                 }
445             }
446         }
447
448         return Boolean.TRUE;
449     }
450
451     public ManagedRepository getManagedRepository( String repoId )
452         throws Exception
453     {
454         Configuration config = archivaConfiguration.getConfiguration();
455         ManagedRepositoryConfiguration managedRepository = config.findManagedRepositoryById( repoId );
456         if ( managedRepository == null )
457         {
458             throw new Exception( "A repository with that id does not exist" );
459         }
460         ManagedRepository repo = new ManagedRepository( managedRepository.getId(), managedRepository.getName(), "URL",
461                                                         managedRepository.getLayout(), managedRepository.isSnapshots(),
462                                                         managedRepository.isReleases() );
463
464         return repo;
465     }
466
467     public boolean merge( String repoId, boolean skipConflicts )
468         throws Exception
469     {
470         String stagingId = repoId + STAGE;
471         ManagedRepositoryConfiguration repoConfig;
472         ManagedRepositoryConfiguration stagingConfig;
473
474         Configuration config = archivaConfiguration.getConfiguration();
475         repoConfig = config.findManagedRepositoryById( repoId );
476
477         log.debug( "Retrieved repository configuration for repo '" + repoId + "'" );
478
479         if ( repoConfig != null )
480         {
481             stagingConfig = config.findManagedRepositoryById( stagingId );
482
483             if ( stagingConfig != null )
484             {
485                 List<ArtifactMetadata> sourceArtifacts = metadataRepository.getArtifacts( stagingId );
486
487                 if ( repoConfig.isReleases() && !repoConfig.isSnapshots() )
488                 {
489                     log.info( "Repository to be merged contains releases only.." );
490                     if ( skipConflicts )
491                     {
492                         List<ArtifactMetadata> conflicts = repositoryMerger.getConflictingArtifacts( repoId,
493                                                                                                      stagingId );
494
495                         if ( log.isDebugEnabled() )
496                         {
497                             log.debug( "Artifacts in conflict.." );
498                             for ( ArtifactMetadata metadata : conflicts )
499                             {
500                                 log.debug( metadata.getNamespace() + ":" + metadata.getProject() + ":" +
501                                                metadata.getProjectVersion() );
502                             }
503                         }
504
505                         sourceArtifacts.removeAll( conflicts );
506
507                         log.debug( "Source artifacts size :: " + sourceArtifacts.size() );
508                         mergeWithOutSnapshots( sourceArtifacts, stagingId, repoId );
509                     }
510                     else
511                     {
512                         log.debug( "Source artifacts size :: " + sourceArtifacts.size() );
513                         mergeWithOutSnapshots( sourceArtifacts, stagingId, repoId );
514                     }
515                 }
516                 else
517                 {
518                     log.info( "Repository to be merged has snapshot artifacts.." );
519                     if ( skipConflicts )
520                     {
521                         List<ArtifactMetadata> conflicts = repositoryMerger.getConflictingArtifacts( repoId,
522                                                                                                      stagingId );
523
524                         if ( log.isDebugEnabled() )
525                         {
526                             log.debug( "Artifacts in conflict.." );
527                             for ( ArtifactMetadata metadata : conflicts )
528                             {
529                                 log.debug( metadata.getNamespace() + ":" + metadata.getProject() + ":" +
530                                                metadata.getProjectVersion() );
531                             }
532                         }
533
534                         sourceArtifacts.removeAll( conflicts );
535
536                         log.debug( "Source artifacts size :: " + sourceArtifacts.size() );
537
538                         Filter<ArtifactMetadata> artifactsWithOutConflicts = new IncludesFilter<ArtifactMetadata>(
539                             sourceArtifacts );
540                         repositoryMerger.merge( stagingId, repoId, artifactsWithOutConflicts );
541
542                         log.info(
543                             "Staging repository '" + stagingId + "' merged successfully with managed repo '" + repoId +
544                                 "'." );
545                     }
546                     else
547                     {
548                         repositoryMerger.merge( stagingId, repoId );
549
550                         log.info(
551                             "Staging repository '" + stagingId + "' merged successfully with managed repo '" + repoId +
552                                 "'." );
553                     }
554                 }
555             }
556             else
557             {
558                 throw new Exception( "Staging Id : " + stagingId + " not found." );
559             }
560         }
561         else
562         {
563             throw new Exception( "Repository Id : " + repoId + " not found." );
564         }
565
566         if ( !repositoryTaskScheduler.isProcessingRepositoryTask( repoId ) )
567         {
568             RepositoryTask task = new RepositoryTask();
569             task.setRepositoryId( repoId );
570
571             repositoryTaskScheduler.queueTask( task );
572         }
573
574         AuditEvent event = createAuditEvent( repoConfig );
575
576         // add event for audit log reports
577         metadataRepository.addMetadataFacet( event.getRepositoryId(), event );
578
579         // log event in archiva audit log
580         auditListener.auditEvent( createAuditEvent( repoConfig ) );
581
582         return true;
583     }
584
585     protected void addRepository( ManagedRepositoryConfiguration repository, Configuration configuration )
586         throws IOException
587     {
588         // Normalize the path
589         File file = new File( repository.getLocation() );
590         repository.setLocation( file.getCanonicalPath() );
591         if ( !file.exists() )
592         {
593             file.mkdirs();
594         }
595         if ( !file.exists() || !file.isDirectory() )
596         {
597             throw new IOException(
598                 "Unable to add repository - no write access, can not create the root directory: " + file );
599         }
600
601         configuration.addManagedRepository( repository );
602     }
603
604     // todo: setting userid of audit event
605     private AuditEvent createAuditEvent( ManagedRepositoryConfiguration repoConfig )
606     {
607
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() );
613
614         return event;
615     }
616
617     private void mergeWithOutSnapshots( List<ArtifactMetadata> sourceArtifacts, String sourceRepoId, String repoid )
618         throws Exception
619     {
620         List<ArtifactMetadata> artifactsWithOutSnapshots = new ArrayList<ArtifactMetadata>();
621         for ( ArtifactMetadata metadata : sourceArtifacts )
622         {
623
624             if ( metadata.getProjectVersion().contains( "SNAPSHOT" ) )
625             {
626                 artifactsWithOutSnapshots.add( metadata );
627             }
628
629         }
630         sourceArtifacts.removeAll( artifactsWithOutSnapshots );
631
632         Filter<ArtifactMetadata> artifactListWithOutSnapShots = new IncludesFilter<ArtifactMetadata>( sourceArtifacts );
633
634         repositoryMerger.merge( sourceRepoId, repoid, artifactListWithOutSnapShots );
635     }
636
637     private ManagedRepositoryConfiguration getStageRepoConfig( ManagedRepositoryConfiguration repository )
638     {
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;
656     }
657 }