]> source.dussan.org Git - archiva.git/blob
c34cc5559f39995bb75d521059598b9e44950453
[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 java.io.File;
23 import java.io.IOException;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Date;
27 import java.util.List;
28 import java.util.Map;
29
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.filter.Filter;
35 import org.apache.archiva.metadata.repository.filter.IncludesFilter;
36 import org.apache.archiva.metadata.repository.stats.RepositoryStatisticsManager;
37 import org.apache.archiva.repository.events.RepositoryListener;
38 import org.apache.archiva.repository.scanner.RepositoryContentConsumers;
39 import org.apache.archiva.scheduler.repository.RepositoryArchivaTaskScheduler;
40 import org.apache.archiva.scheduler.repository.RepositoryTask;
41 import org.apache.archiva.stagerepository.merge.RepositoryMerger;
42 import org.apache.archiva.web.xmlrpc.api.AdministrationService;
43 import org.apache.archiva.web.xmlrpc.api.beans.ManagedRepository;
44 import org.apache.archiva.web.xmlrpc.api.beans.RemoteRepository;
45 import org.apache.commons.io.FileUtils;
46 import org.apache.commons.lang.StringUtils;
47 import org.apache.maven.archiva.configuration.ArchivaConfiguration;
48 import org.apache.maven.archiva.configuration.Configuration;
49 import org.apache.maven.archiva.configuration.IndeterminateConfigurationException;
50 import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
51 import org.apache.maven.archiva.configuration.ProxyConnectorConfiguration;
52 import org.apache.maven.archiva.configuration.RemoteRepositoryConfiguration;
53 import org.apache.maven.archiva.configuration.RepositoryScanningConfiguration;
54 import org.apache.maven.archiva.consumers.InvalidRepositoryContentConsumer;
55 import org.apache.maven.archiva.consumers.KnownRepositoryContentConsumer;
56 import org.apache.maven.archiva.model.VersionedReference;
57 import org.apache.maven.archiva.repository.ContentNotFoundException;
58 import org.apache.maven.archiva.repository.ManagedRepositoryContent;
59 import org.apache.maven.archiva.repository.RepositoryContentFactory;
60 import org.apache.maven.archiva.repository.RepositoryException;
61 import org.apache.maven.archiva.repository.RepositoryNotFoundException;
62 import org.codehaus.plexus.registry.RegistryException;
63 import org.codehaus.plexus.scheduler.CronExpressionValidator;
64 import org.slf4j.Logger;
65 import org.slf4j.LoggerFactory;
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 =
201                 metadataRepository.getArtifacts( repoId, groupId, artifactId, 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.deleteArtifact( 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 =
299                 new ManagedRepository( repoConfig.getId(), repoConfig.getName(), "URL", repoConfig.getLayout(),
300                                        repoConfig.isSnapshots(), 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 =
320                 new RemoteRepository( repoConfig.getId(), repoConfig.getName(), repoConfig.getUrl(),
321                                       repoConfig.getLayout() );
322             remoteRepos.add( repo );
323         }
324
325         return remoteRepos;
326     }
327
328     private void saveConfiguration( Configuration config )
329         throws Exception
330     {
331         try
332         {
333             archivaConfiguration.save( config );
334         }
335         catch ( RegistryException e )
336         {
337             throw new Exception( "Error occurred in the registry." );
338         }
339         catch ( IndeterminateConfigurationException e )
340         {
341             throw new Exception( "Error occurred while saving the configuration." );
342         }
343     }
344
345     public Boolean addManagedRepository( String repoId, String layout, String name, String location,
346                                          boolean blockRedeployments, boolean releasesIncluded,
347                                          boolean snapshotsIncluded, boolean stageRepoNeeded, String cronExpression )
348         throws Exception
349     {
350
351         Configuration config = archivaConfiguration.getConfiguration();
352
353         CronExpressionValidator validator = new CronExpressionValidator();
354
355         if ( config.getManagedRepositoriesAsMap().containsKey( repoId ) )
356         {
357             throw new Exception( "Unable to add new repository with id [" + repoId
358                 + "], that id already exists as a managed repository." );
359         }
360         else if ( config.getRemoteRepositoriesAsMap().containsKey( repoId ) )
361         {
362             throw new Exception( "Unable to add new repository with id [" + repoId
363                 + "], that id already exists as a remote repository." );
364         }
365         else if ( config.getRepositoryGroupsAsMap().containsKey( repoId ) )
366         {
367             throw new Exception( "Unable to add new repository with id [" + repoId
368                 + "], that id already exists as a repository group." );
369         }
370
371         if ( !validator.validate( cronExpression ) )
372         {
373             throw new Exception( "Invalid cron expression." );
374         }
375
376         ManagedRepositoryConfiguration repository = new ManagedRepositoryConfiguration();
377
378         repository.setId( repoId );
379         repository.setBlockRedeployments( blockRedeployments );
380         repository.setReleases( releasesIncluded );
381         repository.setSnapshots( snapshotsIncluded );
382         repository.setName( name );
383         repository.setLocation( location );
384         repository.setLayout( layout );
385         repository.setRefreshCronExpression( cronExpression );
386
387         addRepository( repository, config );
388
389         if ( stageRepoNeeded )
390         {
391             ManagedRepositoryConfiguration stagingRepository = getStageRepoConfig( repository );
392             addRepository( stagingRepository, config );
393         }
394
395         saveConfiguration( config );
396         return Boolean.TRUE;
397     }
398
399     public Boolean deleteManagedRepository( String repoId )
400         throws Exception
401     {
402         Configuration config = archivaConfiguration.getConfiguration();
403
404         ManagedRepositoryConfiguration repository = config.findManagedRepositoryById( repoId );
405
406         if ( repository == null )
407         {
408             throw new Exception( "A repository with that id does not exist" );
409         }
410
411         metadataRepository.deleteRepository( repository.getId() );
412         repositoryStatisticsManager.deleteStatistics( repository.getId() );
413         config.removeManagedRepository( repository );
414
415         try
416         {
417             saveConfiguration( config );
418         }
419         catch ( Exception e )
420         {
421             throw new Exception( "Error saving configuration for delete action" + e.getMessage() );
422         }
423
424         FileUtils.deleteDirectory( new File( repository.getLocation() ) );
425
426         List<ProxyConnectorConfiguration> proxyConnectors = config.getProxyConnectors();
427         for ( ProxyConnectorConfiguration proxyConnector : proxyConnectors )
428         {
429             if ( StringUtils.equals( proxyConnector.getSourceRepoId(), repository.getId() ) )
430             {
431                 archivaConfiguration.getConfiguration().removeProxyConnector( proxyConnector );
432             }
433         }
434
435         Map<String, List<String>> repoToGroupMap = archivaConfiguration.getConfiguration().getRepositoryToGroupMap();
436         if ( repoToGroupMap != null )
437         {
438             if ( repoToGroupMap.containsKey( repository.getId() ) )
439             {
440                 List<String> repoGroups = repoToGroupMap.get( repository.getId() );
441                 for ( String repoGroup : repoGroups )
442                 {
443                     archivaConfiguration.getConfiguration().findRepositoryGroupById( repoGroup ).removeRepository( 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 =
461             new ManagedRepository( managedRepository.getId(), managedRepository.getName(), "URL",
462                                    managedRepository.getLayout(), managedRepository.isSnapshots(),
463                                    managedRepository.isReleases() );
464
465         return repo;
466     }
467
468     public boolean merge( String repoId, boolean skipConflicts )
469         throws Exception
470     {
471         String stagingId = repoId + STAGE;
472         ManagedRepositoryConfiguration repoConfig;
473         ManagedRepositoryConfiguration stagingConfig;
474
475         Configuration config = archivaConfiguration.getConfiguration();
476         repoConfig = config.findManagedRepositoryById( repoId );
477
478         log.debug( "Retrieved repository configuration for repo '" + repoId + "'" );
479
480         if ( repoConfig != null )
481         {
482             stagingConfig = config.findManagedRepositoryById( stagingId );
483
484             if ( stagingConfig != null )
485             {
486                 List<ArtifactMetadata> sourceArtifacts = metadataRepository.getArtifacts( stagingId );
487
488                 if ( repoConfig.isReleases() && !repoConfig.isSnapshots() )
489                 {
490                     log.info( "Repository to be merged contains releases only.." );
491                     if ( skipConflicts )
492                     {
493                         List<ArtifactMetadata> conflicts =
494                             repositoryMerger.getConflictingArtifacts( repoId, stagingId );
495
496                         log.debug( "Artifacts in conflict.." );
497                         for( ArtifactMetadata metadata : conflicts )
498                         {
499                             log.debug( metadata.getNamespace() + ":" + metadata.getProject() + ":" +
500                                 metadata.getProjectVersion() );
501                         }
502
503                         sourceArtifacts.removeAll( conflicts );
504
505                         log.debug( "Source artifacts size :: " + sourceArtifacts.size() );
506                         mergeWithOutSnapshots( sourceArtifacts, stagingId, repoId );
507                     }
508                     else
509                     {
510                         log.debug( "Source artifacts size :: " + sourceArtifacts.size() );
511                         mergeWithOutSnapshots( sourceArtifacts, stagingId, repoId );
512                     }
513                 }
514                 else
515                 {
516                     log.info( "Repository to be merged has snapshot artifacts.." );
517                     if ( skipConflicts )
518                     {
519                         List<ArtifactMetadata> conflicts =
520                             repositoryMerger.getConflictingArtifacts( repoId, stagingId );
521
522                         log.debug( "Artifacts in conflict.." );
523                         for( ArtifactMetadata metadata : conflicts )
524                         {
525                             log.debug( metadata.getNamespace() + ":" + metadata.getProject() + ":" +
526                                 metadata.getProjectVersion() );
527                         }
528                         
529                         sourceArtifacts.removeAll( conflicts );
530
531                         log.debug( "Source artifacts size :: " + sourceArtifacts.size() );
532
533                         Filter<ArtifactMetadata> artifactsWithOutConflicts =
534                             new IncludesFilter<ArtifactMetadata>( sourceArtifacts );
535                         repositoryMerger.merge( stagingId, repoId, artifactsWithOutConflicts );
536
537                         log.info( "Staging repository '" + stagingId + "' merged successfully with managed repo '" +
538                             repoId + "'." );
539                     }
540                     else
541                     {
542                         repositoryMerger.merge( stagingId, repoId );
543                         
544                         log.info( "Staging repository '" + stagingId + "' merged successfully with managed repo '" +
545                             repoId + "'." );
546                     }
547                 }
548             }
549             else
550             {
551                 throw new Exception( "Staging Id : " + stagingId + " not found." );
552             }
553         }
554         else
555         {
556             throw new Exception( "Repository Id : " + repoId + " not found." );
557         }
558
559         if ( !repositoryTaskScheduler.isProcessingRepositoryTask( repoId ) )
560         {
561             RepositoryTask task = new RepositoryTask();
562             task.setRepositoryId( repoId );
563
564             repositoryTaskScheduler.queueTask( task );
565         }
566
567         AuditEvent event = createAuditEvent( repoConfig );
568
569         // add event for audit log reports
570         metadataRepository.addMetadataFacet( event.getRepositoryId(), event );
571
572         // log event in archiva audit log
573         auditListener.auditEvent( createAuditEvent( repoConfig ) );
574
575         return true;
576     }
577
578     protected void addRepository( ManagedRepositoryConfiguration repository, Configuration configuration )
579         throws IOException
580     {
581         // Normalize the path
582         File file = new File( repository.getLocation() );
583         repository.setLocation( file.getCanonicalPath() );
584         if ( !file.exists() )
585         {
586             file.mkdirs();
587         }
588         if ( !file.exists() || !file.isDirectory() )
589         {
590             throw new IOException( "Unable to add repository - no write access, can not create the root directory: "
591                 + file );
592         }
593
594         configuration.addManagedRepository( repository );
595     }
596
597     // todo: setting userid of audit event
598     private AuditEvent createAuditEvent( ManagedRepositoryConfiguration repoConfig )
599     {
600
601         AuditEvent event = new AuditEvent();
602         event.setAction( AuditEvent.MERGE_REPO_REMOTE );
603         event.setRepositoryId( repoConfig.getId() );
604         event.setResource( repoConfig.getLocation() );
605         event.setTimestamp( new Date() );
606
607         return event;
608     }
609
610     private void mergeWithOutSnapshots( List<ArtifactMetadata> sourceArtifacts, String sourceRepoId, String repoid )
611         throws Exception
612     {
613         List<ArtifactMetadata> artifactsWithOutSnapshots = new ArrayList<ArtifactMetadata>();
614         for ( ArtifactMetadata metadata : sourceArtifacts )
615         {
616
617             if ( metadata.getProjectVersion().contains( "SNAPSHOT" ) )
618             {
619                 artifactsWithOutSnapshots.add( metadata );
620             }
621
622         }
623         sourceArtifacts.removeAll( artifactsWithOutSnapshots );
624
625         Filter<ArtifactMetadata> artifactListWithOutSnapShots = new IncludesFilter<ArtifactMetadata>( sourceArtifacts );
626
627         repositoryMerger.merge( sourceRepoId, repoid, artifactListWithOutSnapShots );
628     }
629
630     private ManagedRepositoryConfiguration getStageRepoConfig( ManagedRepositoryConfiguration repository )
631     {
632         ManagedRepositoryConfiguration stagingRepository = new ManagedRepositoryConfiguration();
633         stagingRepository.setId( repository.getId() + "-stage" );
634         stagingRepository.setLayout( repository.getLayout() );
635         stagingRepository.setName( repository.getName() + "-stage" );
636         stagingRepository.setBlockRedeployments( repository.isBlockRedeployments() );
637         stagingRepository.setDaysOlder( repository.getDaysOlder() );
638         stagingRepository.setDeleteReleasedSnapshots( repository.isDeleteReleasedSnapshots() );
639         stagingRepository.setIndexDir( repository.getIndexDir() );
640         String path = repository.getLocation();
641         int lastIndex = path.lastIndexOf( '/' );
642         stagingRepository.setLocation( path.substring( 0, lastIndex ) + "/" + stagingRepository.getId() );
643         stagingRepository.setRefreshCronExpression( repository.getRefreshCronExpression() );
644         stagingRepository.setReleases( repository.isReleases() );
645         stagingRepository.setRetentionCount( repository.getRetentionCount() );
646         stagingRepository.setScanned( repository.isScanned() );
647         stagingRepository.setSnapshots( repository.isSnapshots() );
648         return stagingRepository;
649     }
650 }