]> source.dussan.org Git - archiva.git/blob
78ff181340553bb64c9015f92b4c59ee5387c7bc
[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.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;
59
60 import java.io.File;
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;
66 import java.util.Map;
67
68 /**
69  * AdministrationServiceImpl
70  *
71  * @version $Id: AdministrationServiceImpl.java
72  */
73 public class AdministrationServiceImpl
74     implements AdministrationService
75 {
76     protected Logger log = LoggerFactory.getLogger( getClass() );
77
78     private RepositoryContentConsumers repoConsumersUtil;
79
80     private RepositoryContentFactory repoFactory;
81
82     private RepositoryArchivaTaskScheduler repositoryTaskScheduler;
83
84     private Collection<RepositoryListener> listeners;
85
86     private RepositoryStatisticsManager repositoryStatisticsManager;
87
88     private RepositoryMerger repositoryMerger;
89
90     private static final String STAGE = "-stage";
91
92     private AuditListener auditListener;
93
94     private RepositorySessionFactory repositorySessionFactory;
95
96     private ManagedRepositoryAdmin managedRepositoryAdmin;
97
98     private RemoteRepositoryAdmin remoteRepositoryAdmin;
99
100     private ArchivaAdministration archivaAdministration;
101
102     private ProxyConnectorAdmin proxyConnectorAdmin;
103
104     private RepositoryGroupAdmin repositoryGroupAdmin;
105
106     private static final String REPOSITORY_ID_VALID_EXPRESSION = "^[a-zA-Z0-9._-]+$";
107
108     private static final String REPOSITORY_NAME_VALID_EXPRESSION = "^([a-zA-Z0-9.)/_(-]|\\s)+$";
109
110     private static final String REPOSITORY_LOCATION_VALID_EXPRESSION = "^[-a-zA-Z0-9._/~:?!&amp;=\\\\]+$";
111
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 )
124     {
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;
138     }
139
140     /**
141      * @see AdministrationService#configureRepositoryConsumer(String, String, boolean)
142      */
143     public Boolean configureRepositoryConsumer( String repoId, String consumerId, boolean enable )
144         throws Exception
145     {
146         // TODO use repoId once consumers are configured per repository! (MRM-930)
147
148         List<KnownRepositoryContentConsumer> knownConsumers = repoConsumersUtil.getAvailableKnownConsumers();
149         List<InvalidRepositoryContentConsumer> invalidConsumers = repoConsumersUtil.getAvailableInvalidConsumers();
150
151         boolean found = false;
152         boolean isKnownContentConsumer = false;
153         for ( KnownRepositoryContentConsumer consumer : knownConsumers )
154         {
155             if ( consumer.getId().equals( consumerId ) )
156             {
157                 found = true;
158                 isKnownContentConsumer = true;
159                 break;
160             }
161         }
162
163         if ( !found )
164         {
165             for ( InvalidRepositoryContentConsumer consumer : invalidConsumers )
166             {
167                 if ( consumer.getId().equals( consumerId ) )
168                 {
169                     found = true;
170                     break;
171                 }
172             }
173         }
174
175         if ( !found )
176         {
177             throw new Exception( "Invalid repository consumer." );
178         }
179
180         if ( isKnownContentConsumer )
181         {
182             if ( enable )
183             {
184                 archivaAdministration.addKnownContentConsumer( consumerId, getAuditInformation() );
185             }
186             else
187             {
188                 archivaAdministration.removeKnownContentConsumer( consumerId, getAuditInformation() );
189             }
190
191         }
192         else
193         {
194             if ( enable )
195             {
196                 archivaAdministration.addInvalidContentConsumer( consumerId, getAuditInformation() );
197             }
198             else
199             {
200                 archivaAdministration.removeInvalidContentConsumer( consumerId, getAuditInformation() );
201             }
202         }
203
204         return true;
205     }
206
207     /**
208      * @see AdministrationService#deleteArtifact(String, String, String, String)
209      */
210     public Boolean deleteArtifact( String repoId, String groupId, String artifactId, String version )
211         throws Exception
212     {
213         // TODO: remove duplication with web
214
215         org.apache.archiva.admin.model.beans.ManagedRepository repoConfig =
216             managedRepositoryAdmin.getManagedRepository( repoId );
217
218         if ( repoConfig == null )
219         {
220             throw new Exception( "Repository does not exist." );
221         }
222
223         RepositorySession repositorySession = repositorySessionFactory.createSession();
224         try
225         {
226             ManagedRepositoryContent repoContent = repoFactory.getManagedRepositoryContent( repoId );
227             VersionedReference ref = new VersionedReference();
228             ref.setGroupId( groupId );
229             ref.setArtifactId( artifactId );
230             ref.setVersion( version );
231
232             // delete from file system
233             repoContent.deleteVersion( ref );
234
235             MetadataRepository metadataRepository = repositorySession.getRepository();
236             Collection<ArtifactMetadata> artifacts =
237                 metadataRepository.getArtifacts( repoId, groupId, artifactId, version );
238
239             for ( ArtifactMetadata artifact : artifacts )
240             {
241                 // TODO: mismatch between artifact (snapshot) version and project (base) version here
242                 if ( artifact.getVersion().equals( version ) )
243                 {
244                     metadataRepository.removeArtifact( artifact.getRepositoryId(), artifact.getNamespace(),
245                                                        artifact.getProject(), artifact.getVersion(), artifact.getId() );
246
247                     // TODO: move into the metadata repository proper - need to differentiate attachment of
248                     // repository metadata to an artifact
249                     for ( RepositoryListener listener : listeners )
250                     {
251                         listener.deleteArtifact( metadataRepository, repoId, artifact.getNamespace(),
252                                                  artifact.getProject(), artifact.getVersion(), artifact.getId() );
253                     }
254                 }
255             }
256             repositorySession.save();
257         }
258         catch ( ContentNotFoundException e )
259         {
260             throw new Exception( "Artifact does not exist." );
261         }
262         catch ( RepositoryNotFoundException e )
263         {
264             throw new Exception( "Repository does not exist." );
265         }
266         catch ( RepositoryException e )
267         {
268             throw new Exception( "Repository exception occurred." );
269         }
270         finally
271         {
272             repositorySession.close();
273         }
274
275         return true;
276     }
277
278     /**
279      * @see AdministrationService#executeRepositoryScanner(String)
280      */
281     public Boolean executeRepositoryScanner( String repoId )
282         throws Exception
283     {
284         if ( managedRepositoryAdmin.getManagedRepository( repoId ) == null )
285         {
286             throw new Exception( "Repository does not exist." );
287         }
288
289         if ( repositoryTaskScheduler.isProcessingRepositoryTask( repoId ) )
290         {
291             return false;
292         }
293
294         RepositoryTask task = new RepositoryTask();
295         task.setRepositoryId( repoId );
296         repositoryTaskScheduler.queueTask( task );
297
298         return true;
299     }
300
301     /**
302      * @see AdministrationService#getAllRepositoryConsumers()
303      */
304     public List<String> getAllRepositoryConsumers()
305     {
306         List<String> consumers = new ArrayList<String>();
307
308         List<KnownRepositoryContentConsumer> knownConsumers = repoConsumersUtil.getAvailableKnownConsumers();
309         List<InvalidRepositoryContentConsumer> invalidConsumers = repoConsumersUtil.getAvailableInvalidConsumers();
310
311         for ( KnownRepositoryContentConsumer consumer : knownConsumers )
312         {
313             consumers.add( consumer.getId() );
314         }
315
316         for ( InvalidRepositoryContentConsumer consumer : invalidConsumers )
317         {
318             consumers.add( consumer.getId() );
319         }
320
321         return consumers;
322     }
323
324     /**
325      * @see AdministrationService#getAllManagedRepositories()
326      */
327     public List<ManagedRepository> getAllManagedRepositories()
328         throws RepositoryAdminException
329     {
330         List<ManagedRepository> managedRepos = new ArrayList<ManagedRepository>();
331
332         for ( org.apache.archiva.admin.model.beans.ManagedRepository repoConfig : managedRepositoryAdmin.getManagedRepositories() )
333         {
334             ManagedRepository repo =
335                 new ManagedRepository( repoConfig.getId(), repoConfig.getName(), repoConfig.getLocation(),
336                                        repoConfig.getLayout(), repoConfig.isSnapshots(), repoConfig.isReleases() );
337             managedRepos.add( repo );
338         }
339
340         return managedRepos;
341     }
342
343     /**
344      * @see AdministrationService#getAllRemoteRepositories()
345      */
346     public List<RemoteRepository> getAllRemoteRepositories()
347         throws RepositoryAdminException
348     {
349         List<RemoteRepository> remoteRepos = new ArrayList<RemoteRepository>();
350
351         for ( org.apache.archiva.admin.model.beans.RemoteRepository repoConfig : remoteRepositoryAdmin.getRemoteRepositories() )
352         {
353             RemoteRepository repo = new RemoteRepository( repoConfig.getId(), repoConfig.getName(), repoConfig.getUrl(),
354                                                           repoConfig.getLayout() );
355             remoteRepos.add( repo );
356         }
357
358         return remoteRepos;
359     }
360
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 )
365         throws Exception
366     {
367
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() );
375
376     }
377
378     public Boolean deleteManagedRepository( String repoId )
379         throws Exception
380     {
381
382         org.apache.archiva.admin.model.beans.ManagedRepository repository =
383             managedRepositoryAdmin.getManagedRepository( repoId );
384
385         if ( repository == null )
386         {
387             throw new Exception( "A repository with that id does not exist" );
388         }
389
390         RepositorySession repositorySession = repositorySessionFactory.createSession();
391         try
392         {
393             MetadataRepository metadataRepository = repositorySession.getRepository();
394             metadataRepository.removeRepository( repository.getId() );
395             repositoryStatisticsManager.deleteStatistics( metadataRepository, repository.getId() );
396             repositorySession.save();
397         }
398         finally
399         {
400             repositorySession.close();
401         }
402         managedRepositoryAdmin.deleteManagedRepository( repoId, getAuditInformation(), false );
403
404         File dir = new File( repository.getLocation() );
405         if ( !FileUtils.deleteQuietly( dir ) )
406         {
407             throw new IOException( "Cannot delete repository " + dir );
408         }
409
410         List<ProxyConnector> proxyConnectors = proxyConnectorAdmin.getProxyConnectors();
411         for ( ProxyConnector proxyConnector : proxyConnectors )
412         {
413             if ( StringUtils.equals( proxyConnector.getSourceRepoId(), repository.getId() ) )
414             {
415                 proxyConnectorAdmin.deleteProxyConnector( proxyConnector, getAuditInformation() );
416             }
417         }
418
419         Map<String, List<String>> repoToGroupMap = repositoryGroupAdmin.getRepositoryToGroupMap();
420         if ( repoToGroupMap != null )
421         {
422             if ( repoToGroupMap.containsKey( repository.getId() ) )
423             {
424                 List<String> repoGroups = repoToGroupMap.get( repository.getId() );
425                 for ( String repoGroup : repoGroups )
426                 {
427                     repositoryGroupAdmin.deleteRepositoryFromGroup( repoGroup, repository.getId(),
428                                                                     getAuditInformation() );
429                 }
430             }
431         }
432
433         return Boolean.TRUE;
434     }
435
436     public Boolean deleteManagedRepositoryContent( String repoId )
437         throws Exception
438     {
439
440         org.apache.archiva.admin.model.beans.ManagedRepository repository =
441             managedRepositoryAdmin.getManagedRepository( repoId );
442
443         if ( repository == null )
444         {
445             throw new Exception( "Repository Id : " + repoId + " not found." );
446         }
447
448         RepositorySession repositorySession = repositorySessionFactory.createSession();
449         try
450         {
451             MetadataRepository metadataRepository = repositorySession.getRepository();
452             metadataRepository.removeRepository( repository.getId() );
453             repositorySession.save();
454         }
455         finally
456         {
457             repositorySession.close();
458         }
459
460         File repoDir = new File( repository.getLocation() );
461         File[] children = repoDir.listFiles();
462
463         if ( children != null )
464         {
465             for ( File child : children )
466             {
467                 FileUtils.deleteQuietly( child );
468             }
469
470             if ( repoDir.listFiles().length > 0 )
471             {
472                 throw new IOException( "Cannot delete repository contents of " + repoDir );
473             }
474         }
475
476         return Boolean.TRUE;
477     }
478
479     public ManagedRepository getManagedRepository( String repoId )
480         throws Exception
481     {
482         org.apache.archiva.admin.model.beans.ManagedRepository managedRepository =
483             managedRepositoryAdmin.getManagedRepository( repoId );
484         if ( managedRepository == null )
485         {
486             throw new Exception( "A repository with that id does not exist" );
487         }
488         ManagedRepository repo = new ManagedRepository( managedRepository.getId(), managedRepository.getName(), "URL",
489                                                         managedRepository.getLayout(), managedRepository.isSnapshots(),
490                                                         managedRepository.isReleases() );
491
492         return repo;
493     }
494
495     public boolean merge( String repoId, boolean skipConflicts )
496         throws Exception
497     {
498         String stagingId = repoId + STAGE;
499         org.apache.archiva.admin.model.beans.ManagedRepository repoConfig;
500         org.apache.archiva.admin.model.beans.ManagedRepository stagingConfig;
501
502         repoConfig = managedRepositoryAdmin.getManagedRepository( repoId );
503
504         log.debug( "Retrieved repository configuration for repo '" + repoId + "'" );
505
506         RepositorySession repositorySession = repositorySessionFactory.createSession();
507         try
508         {
509             MetadataRepository metadataRepository = repositorySession.getRepository();
510             if ( repoConfig != null )
511             {
512                 stagingConfig = managedRepositoryAdmin.getManagedRepository( stagingId );
513
514                 if ( stagingConfig != null )
515                 {
516                     List<ArtifactMetadata> sourceArtifacts = metadataRepository.getArtifacts( stagingId );
517
518                     if ( repoConfig.isReleases() && !repoConfig.isSnapshots() )
519                     {
520                         log.info( "Repository to be merged contains releases only.." );
521                         if ( skipConflicts )
522                         {
523                             List<ArtifactMetadata> conflicts =
524                                 repositoryMerger.getConflictingArtifacts( metadataRepository, repoId, stagingId );
525
526                             if ( log.isDebugEnabled() )
527                             {
528                                 log.debug( "Artifacts in conflict.." );
529                                 for ( ArtifactMetadata metadata : conflicts )
530                                 {
531                                     log.debug( metadata.getNamespace() + ":" + metadata.getProject() + ":"
532                                                    + metadata.getProjectVersion() );
533                                 }
534                             }
535
536                             sourceArtifacts.removeAll( conflicts );
537
538                             log.debug( "Source artifacts size :: " + sourceArtifacts.size() );
539                             mergeWithOutSnapshots( sourceArtifacts, stagingId, repoId, metadataRepository );
540                         }
541                         else
542                         {
543                             log.debug( "Source artifacts size :: " + sourceArtifacts.size() );
544                             mergeWithOutSnapshots( sourceArtifacts, stagingId, repoId, metadataRepository );
545                         }
546                     }
547                     else
548                     {
549                         log.info( "Repository to be merged has snapshot artifacts.." );
550                         if ( skipConflicts )
551                         {
552                             List<ArtifactMetadata> conflicts =
553                                 repositoryMerger.getConflictingArtifacts( metadataRepository, repoId, stagingId );
554
555                             if ( log.isDebugEnabled() )
556                             {
557                                 log.debug( "Artifacts in conflict.." );
558                                 for ( ArtifactMetadata metadata : conflicts )
559                                 {
560                                     log.debug( metadata.getNamespace() + ":" + metadata.getProject() + ":"
561                                                    + metadata.getProjectVersion() );
562                                 }
563                             }
564
565                             sourceArtifacts.removeAll( conflicts );
566
567                             log.debug( "Source artifacts size :: " + sourceArtifacts.size() );
568
569                             Filter<ArtifactMetadata> artifactsWithOutConflicts =
570                                 new IncludesFilter<ArtifactMetadata>( sourceArtifacts );
571                             repositoryMerger.merge( metadataRepository, stagingId, repoId, artifactsWithOutConflicts );
572
573                             log.info( "Staging repository '" + stagingId + "' merged successfully with managed repo '"
574                                           + repoId + "'." );
575                         }
576                         else
577                         {
578                             repositoryMerger.merge( metadataRepository, stagingId, repoId );
579
580                             log.info( "Staging repository '" + stagingId + "' merged successfully with managed repo '"
581                                           + repoId + "'." );
582                         }
583                     }
584                 }
585                 else
586                 {
587                     throw new Exception( "Staging Id : " + stagingId + " not found." );
588                 }
589             }
590             else
591             {
592                 throw new Exception( "Repository Id : " + repoId + " not found." );
593             }
594
595             if ( !repositoryTaskScheduler.isProcessingRepositoryTask( repoId ) )
596             {
597                 RepositoryTask task = new RepositoryTask();
598                 task.setRepositoryId( repoId );
599
600                 repositoryTaskScheduler.queueTask( task );
601             }
602
603             AuditEvent event = createAuditEvent( repoConfig );
604
605             // add event for audit log reports
606             metadataRepository.addMetadataFacet( event.getRepositoryId(), event );
607
608             // log event in archiva audit log
609             auditListener.auditEvent( createAuditEvent( repoConfig ) );
610             repositorySession.save();
611         }
612         finally
613         {
614             repositorySession.close();
615         }
616
617         return true;
618     }
619
620     // todo: setting userid of audit event
621     private AuditEvent createAuditEvent( org.apache.archiva.admin.model.beans.ManagedRepository repoConfig )
622     {
623
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() );
629
630         return event;
631     }
632
633     private void mergeWithOutSnapshots( List<ArtifactMetadata> sourceArtifacts, String sourceRepoId, String repoid,
634                                         MetadataRepository metadataRepository )
635         throws Exception
636     {
637         List<ArtifactMetadata> artifactsWithOutSnapshots = new ArrayList<ArtifactMetadata>();
638         for ( ArtifactMetadata metadata : sourceArtifacts )
639         {
640
641             if ( metadata.getProjectVersion().contains( "SNAPSHOT" ) )
642             {
643                 artifactsWithOutSnapshots.add( metadata );
644             }
645
646         }
647         sourceArtifacts.removeAll( artifactsWithOutSnapshots );
648
649         Filter<ArtifactMetadata> artifactListWithOutSnapShots = new IncludesFilter<ArtifactMetadata>( sourceArtifacts );
650
651         repositoryMerger.merge( metadataRepository, sourceRepoId, repoid, artifactListWithOutSnapShots );
652     }
653
654
655     // FIXME find a way to get user id and adress
656     private AuditInformation getAuditInformation()
657     {
658         return new AuditInformation( null, null );
659     }
660 }