]> source.dussan.org Git - archiva.git/blob
a2c7dc39f7fffa63d12f1bd5c02b821160857d35
[archiva.git] /
1 package org.apache.archiva.repository.base;
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.components.registry.RegistryException;
23 import org.apache.archiva.configuration.AbstractRepositoryConfiguration;
24 import org.apache.archiva.configuration.ArchivaConfiguration;
25 import org.apache.archiva.configuration.Configuration;
26 import org.apache.archiva.configuration.ConfigurationEvent;
27 import org.apache.archiva.configuration.ConfigurationListener;
28 import org.apache.archiva.configuration.IndeterminateConfigurationException;
29 import org.apache.archiva.configuration.ManagedRepositoryConfiguration;
30 import org.apache.archiva.configuration.RemoteRepositoryConfiguration;
31 import org.apache.archiva.configuration.RepositoryGroupConfiguration;
32 import org.apache.archiva.event.Event;
33 import org.apache.archiva.event.EventHandler;
34 import org.apache.archiva.event.EventManager;
35 import org.apache.archiva.event.EventType;
36 import org.apache.archiva.indexer.ArchivaIndexManager;
37 import org.apache.archiva.indexer.ArchivaIndexingContext;
38 import org.apache.archiva.indexer.IndexCreationFailedException;
39 import org.apache.archiva.indexer.IndexManagerFactory;
40 import org.apache.archiva.indexer.IndexUpdateFailedException;
41 import org.apache.archiva.repository.EditableRepository;
42 import org.apache.archiva.repository.ManagedRepository;
43 import org.apache.archiva.repository.RemoteRepository;
44 import org.apache.archiva.repository.Repository;
45 import org.apache.archiva.repository.RepositoryException;
46 import org.apache.archiva.repository.RepositoryGroup;
47 import org.apache.archiva.repository.RepositoryHandler;
48 import org.apache.archiva.repository.RepositoryProvider;
49 import org.apache.archiva.repository.RepositoryRegistry;
50 import org.apache.archiva.repository.RepositoryType;
51 import org.apache.archiva.repository.UnsupportedRepositoryTypeException;
52 import org.apache.archiva.repository.event.RepositoryIndexEvent;
53 import org.apache.archiva.repository.event.RepositoryRegistryEvent;
54 import org.apache.archiva.repository.metadata.MetadataReader;
55 import org.apache.archiva.repository.storage.StorageAsset;
56 import org.apache.archiva.repository.validation.CheckedResult;
57 import org.apache.archiva.repository.validation.RepositoryValidator;
58 import org.apache.archiva.repository.validation.ValidationError;
59 import org.apache.archiva.repository.validation.ValidationResponse;
60 import org.apache.commons.collections4.ListUtils;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63 import org.springframework.stereotype.Service;
64
65 import javax.annotation.PostConstruct;
66 import javax.annotation.PreDestroy;
67 import javax.inject.Inject;
68 import java.util.Collection;
69 import java.util.Collections;
70 import java.util.HashMap;
71 import java.util.List;
72 import java.util.Map;
73 import java.util.Set;
74 import java.util.TreeSet;
75 import java.util.concurrent.atomic.AtomicBoolean;
76 import java.util.concurrent.locks.ReentrantReadWriteLock;
77 import java.util.stream.Collectors;
78 import java.util.stream.Stream;
79
80 /**
81  * Registry for repositories. This is the central entry point for repositories. It provides methods for
82  * retrieving, adding and removing repositories.
83  * <p>
84  * The modification methods addXX and removeXX persist the changes immediately to the configuration. If the
85  * configuration save fails the changes are rolled back.
86  * <p>
87  * TODO: Audit events
88  *
89  * @since 3.0
90  */
91 @Service( "repositoryRegistry" )
92 public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHandler<Event>,
93     RepositoryRegistry
94 {
95
96     private static final Logger log = LoggerFactory.getLogger( RepositoryRegistry.class );
97
98     /**
99      * We inject all repository providers
100      */
101     @Inject
102     List<RepositoryProvider> repositoryProviders;
103
104     @SuppressWarnings( "SpringJavaInjectionPointsAutowiringInspection" )
105     @Inject
106     IndexManagerFactory indexManagerFactory;
107
108     @Inject
109     List<MetadataReader> metadataReaderList;
110
111     @Inject
112     List<RepositoryValidator<? extends Repository>> repositoryValidatorList;
113
114     private boolean ignoreIndexing = false;
115
116     private final EventManager eventManager;
117
118
119     private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock( );
120
121     private RepositoryHandler<RepositoryGroup, RepositoryGroupConfiguration> groupHandler;
122     private RepositoryHandler<ManagedRepository, ManagedRepositoryConfiguration> managedRepositoryHandler;
123     private RepositoryHandler<RemoteRepository, RemoteRepositoryConfiguration> remoteRepositoryHandler;
124
125     private final Set<RepositoryValidator<? extends Repository>> validators;
126     private final ConfigurationHandler configurationHandler;
127
128
129     private final AtomicBoolean groups_initalized = new AtomicBoolean( false );
130     private final AtomicBoolean managed_initialized = new AtomicBoolean( false );
131     private final AtomicBoolean remote_initialized = new AtomicBoolean( false );
132
133
134     public ArchivaRepositoryRegistry( ConfigurationHandler configurationHandler, List<RepositoryValidator<? extends Repository>> validatorList )
135     {
136         this.eventManager = new EventManager( this );
137         this.configurationHandler = configurationHandler;
138         this.validators = initValidatorList( validatorList );
139     }
140
141
142     private Set<RepositoryValidator<? extends Repository>> initValidatorList( List<RepositoryValidator<? extends Repository>> validators )
143     {
144         TreeSet<RepositoryValidator<? extends Repository>> val = new TreeSet<>( );
145         for ( RepositoryValidator<? extends Repository> validator : validators )
146         {
147             val.add( validator );
148             validator.setRepositoryRegistry( this );
149         }
150         return val;
151     }
152
153     @Override
154     public void setArchivaConfiguration( ArchivaConfiguration archivaConfiguration )
155     {
156         this.configurationHandler.setArchivaConfiguration( archivaConfiguration );
157     }
158
159     @PostConstruct
160     private void initialize( )
161     {
162         rwLock.writeLock( ).lock( );
163         try
164         {
165             log.debug( "Initializing repository registry" );
166             initializeManagedRepositories();
167             initializeRemoteRepositories();
168             initializeRepositoryGroups( );
169
170             for ( RepositoryProvider provider : repositoryProviders )
171             {
172                 provider.addRepositoryEventHandler( this );
173             }
174             this.configurationHandler.addListener( this );
175         }
176         finally
177         {
178             rwLock.writeLock( ).unlock( );
179         }
180         pushEvent( new RepositoryRegistryEvent( RepositoryRegistryEvent.RELOADED, this ) );
181         if ( managed_initialized.get( ) && remote_initialized.get( ) && groups_initalized.get( ) )
182         {
183             pushEvent( new RepositoryRegistryEvent( RepositoryRegistryEvent.INITIALIZED, this ) );
184         }
185     }
186
187     private void initializeRepositoryGroups( )
188     {
189         if ( this.groupHandler != null )
190         {
191             this.groupHandler.initializeFromConfig( );
192             this.groups_initalized.set( true );
193             pushEvent( new RepositoryRegistryEvent( RepositoryRegistryEvent.GROUPS_INITIALIZED, this ) );
194         }
195     }
196
197     private void initializeManagedRepositories( )
198     {
199         if ( this.managedRepositoryHandler != null )
200         {
201             this.managedRepositoryHandler.initializeFromConfig( );
202             this.managed_initialized.set( true );
203             pushEvent( new RepositoryRegistryEvent( RepositoryRegistryEvent.MANAGED_REPOS_INITIALIZED, this ) );
204         }
205     }
206
207     private void initializeRemoteRepositories() {
208         if (this.remoteRepositoryHandler != null ){
209             this.remoteRepositoryHandler.initializeFromConfig( );
210             this.remote_initialized.set( true );
211             pushEvent( new RepositoryRegistryEvent( RepositoryRegistryEvent.REMOTE_REPOS_INITIALIZED, this ) );
212
213         }
214     }
215
216     public void registerGroupHandler( RepositoryHandler<RepositoryGroup, RepositoryGroupConfiguration> groupHandler )
217     {
218         this.groupHandler = groupHandler;
219         doRegister( groupHandler );
220         initializeRepositoryGroups( );
221         if ( managed_initialized.get( ) && remote_initialized.get( ) && groups_initalized.get( ) )
222         {
223             pushEvent( new RepositoryRegistryEvent( RepositoryRegistryEvent.INITIALIZED, this ) );
224         }
225     }
226
227     public void registerManagedRepositoryHandler( RepositoryHandler<ManagedRepository, ManagedRepositoryConfiguration> managedRepositoryHandler )
228     {
229         this.managedRepositoryHandler = managedRepositoryHandler;
230         doRegister( managedRepositoryHandler );
231         initializeManagedRepositories();
232         if ( managed_initialized.get( ) && remote_initialized.get( ) && groups_initalized.get( ) )
233         {
234             pushEvent( new RepositoryRegistryEvent( RepositoryRegistryEvent.INITIALIZED, this ) );
235         }
236     }
237
238     public void registerRemoteRepositoryHandler( RepositoryHandler<RemoteRepository, RemoteRepositoryConfiguration> remoteRepositoryHandler )
239     {
240         this.remoteRepositoryHandler = remoteRepositoryHandler;
241         doRegister( remoteRepositoryHandler );
242         initializeRemoteRepositories();
243         if ( managed_initialized.get( ) && remote_initialized.get( ) && groups_initalized.get( ) )
244         {
245             pushEvent( new RepositoryRegistryEvent( RepositoryRegistryEvent.INITIALIZED, this ) );
246         }
247     }
248
249     @PreDestroy
250     public void destroy( )
251     {
252         managedRepositoryHandler.close( );
253         remoteRepositoryHandler.close();
254         groupHandler.close( );
255         pushEvent( new RepositoryRegistryEvent( RepositoryRegistryEvent.DESTROYED, this ) );
256     }
257
258
259     public Map<RepositoryType, RepositoryProvider> getRepositoryProviderMap( )
260     {
261         Map<RepositoryType, RepositoryProvider> map = new HashMap<>( );
262         if ( repositoryProviders != null )
263         {
264             for ( RepositoryProvider provider : repositoryProviders )
265             {
266                 for ( RepositoryType type : provider.provides( ) )
267                 {
268                     map.put( type, provider );
269                 }
270             }
271         }
272         return map;
273     }
274
275     public RepositoryProvider getProvider( RepositoryType type ) throws RepositoryException
276     {
277         return repositoryProviders.stream( ).filter( repositoryProvider -> repositoryProvider.provides( ).contains( type ) ).findFirst( ).orElseThrow( ( ) -> new RepositoryException( "Repository type cannot be handled: " + type ) );
278     }
279
280
281     @Override
282     public ArchivaIndexManager getIndexManager( RepositoryType type )
283     {
284         return indexManagerFactory.getIndexManager( type );
285     }
286
287     @Override
288     public MetadataReader getMetadataReader( final RepositoryType type ) throws UnsupportedRepositoryTypeException
289     {
290         if ( metadataReaderList != null )
291         {
292             return metadataReaderList.stream( ).filter( mr -> mr.isValidForType( type ) ).findFirst( ).orElseThrow( ( ) -> new UnsupportedRepositoryTypeException( type ) );
293         }
294         else
295         {
296             throw new UnsupportedRepositoryTypeException( type );
297         }
298     }
299
300
301     /**
302      * Returns all repositories that are registered. There is no defined order of the returned repositories.
303      *
304      * @return a list of managed and remote repositories
305      */
306     @Override
307     public Collection<Repository> getRepositories( )
308     {
309         rwLock.readLock( ).lock( );
310         try
311         {
312             return Stream.concat( managedRepositoryHandler.getAll().stream( ), remoteRepositoryHandler.getAll().stream( ) ).collect( Collectors.toList( ) );
313         }
314         finally
315         {
316             rwLock.readLock( ).unlock( );
317         }
318     }
319
320     /**
321      * Returns only the managed repositories. There is no defined order of the returned repositories.
322      *
323      * @return a list of managed repositories
324      */
325     @Override
326     public Collection<ManagedRepository> getManagedRepositories( )
327     {
328         rwLock.readLock( ).lock( );
329         try
330         {
331             return managed_initialized.get() ? managedRepositoryHandler.getAll( ) : Collections.emptyList();
332         }
333         finally
334         {
335             rwLock.readLock( ).unlock( );
336         }
337     }
338
339     /**
340      * Returns only the remote repositories. There is no defined order of the returned repositories.
341      *
342      * @return a list of remote repositories
343      */
344     @Override
345     public Collection<RemoteRepository> getRemoteRepositories( )
346     {
347         rwLock.readLock( ).lock( );
348         try
349         {
350             return remote_initialized.get() ? remoteRepositoryHandler.getAll( ) : Collections.emptyList();
351         }
352         finally
353         {
354             rwLock.readLock( ).unlock( );
355         }
356     }
357
358     @Override
359     public Collection<RepositoryGroup> getRepositoryGroups( )
360     {
361         rwLock.readLock( ).lock( );
362         try
363         {
364             return groupHandler.getAll( );
365         }
366         finally
367         {
368             rwLock.readLock( ).unlock( );
369         }
370     }
371
372     /**
373      * Returns the repository with the given id. The returned repository may be a managed or remote repository.
374      * It returns null, if no repository is registered with the given id.
375      *
376      * @param repoId the repository id
377      * @return the repository if found, otherwise null
378      */
379     @Override
380     public Repository getRepository( String repoId )
381     {
382         rwLock.readLock( ).lock( );
383         try
384         {
385             log.debug( "getRepository {}", repoId );
386             if ( managedRepositoryHandler.hasRepository( repoId ) )
387             {
388                 log.debug( "Managed repo" );
389                 return managedRepositoryHandler.get( repoId );
390             }
391             else if ( remoteRepositoryHandler.hasRepository( repoId ) )
392             {
393                 log.debug( "Remote repo" );
394                 return remoteRepositoryHandler.get( repoId );
395             }
396             else if ( groupHandler.hasRepository( repoId ) )
397             {
398                 return groupHandler.get( repoId );
399             }
400             else
401             {
402                 return null;
403             }
404         }
405         finally
406         {
407             rwLock.readLock( ).unlock( );
408         }
409     }
410
411     /**
412      * Convenience method, that returns the managed repository with the given id.
413      * It returns null, if no managed repository is registered with this id.
414      *
415      * @param repoId the repository id
416      * @return the managed repository if found, otherwise null
417      */
418     @Override
419     public ManagedRepository getManagedRepository( String repoId )
420     {
421         rwLock.readLock( ).lock( );
422         try
423         {
424             return managed_initialized.get() ? managedRepositoryHandler.get( repoId ) : null;
425         }
426         finally
427         {
428             rwLock.readLock( ).unlock( );
429         }
430     }
431
432     /**
433      * Convenience method, that returns the remote repository with the given id.
434      * It returns null, if no remote repository is registered with this id.
435      *
436      * @param repoId the repository id
437      * @return the remote repository if found, otherwise null
438      */
439     @Override
440     public RemoteRepository getRemoteRepository( String repoId )
441     {
442         rwLock.readLock( ).lock( );
443         try
444         {
445             return remote_initialized.get() ? remoteRepositoryHandler.get( repoId ) : null;
446         }
447         finally
448         {
449             rwLock.readLock( ).unlock( );
450         }
451     }
452
453     @Override
454     public RepositoryGroup getRepositoryGroup( String groupId )
455     {
456         rwLock.readLock( ).lock( );
457         try
458         {
459             return groupHandler.get( groupId );
460         }
461         finally
462         {
463             rwLock.readLock( ).unlock( );
464         }
465     }
466
467     @Override
468     public boolean hasRepository( String repoId )
469     {
470         return ( managedRepositoryHandler != null && managedRepositoryHandler.hasRepository( repoId ) )
471             || ( remoteRepositoryHandler != null && remoteRepositoryHandler.hasRepository( repoId ) )
472             || ( this.groupHandler != null && groupHandler.hasRepository( repoId ) );
473     }
474
475     @Override
476     public boolean hasManagedRepository( String repoId )
477     {
478         return managedRepositoryHandler!=null && managedRepositoryHandler.hasRepository( repoId );
479     }
480
481     @Override
482     public boolean hasRemoteRepository( String repoId )
483     {
484         return remoteRepositoryHandler!=null && remoteRepositoryHandler.hasRepository( repoId );
485     }
486
487     @Override
488     public boolean hasRepositoryGroup( String groupId )
489     {
490         return this.groupHandler != null && groupHandler.hasRepository( groupId );
491     }
492
493     protected void saveConfiguration( Configuration configuration ) throws IndeterminateConfigurationException, RegistryException
494     {
495         configurationHandler.save( configuration, ConfigurationHandler.REGISTRY_EVENT_TAG );
496     }
497
498     /**
499      * Adds a new repository to the current list, or replaces the repository definition with
500      * the same id, if it exists already.
501      * The change is saved to the configuration immediately.
502      *
503      * @param managedRepository the new repository.
504      * @throws RepositoryException if the new repository could not be saved to the configuration.
505      */
506     @Override
507     public ManagedRepository putRepository( ManagedRepository managedRepository ) throws RepositoryException
508     {
509         rwLock.writeLock( ).lock( );
510         try
511         {
512             return managed_initialized.get() ? managedRepositoryHandler.put( managedRepository ) : null;
513         }
514         finally
515         {
516             rwLock.writeLock( ).unlock( );
517         }
518     }
519
520     /**
521      * Adds a new repository or updates the repository with the same id, if it exists already.
522      * The configuration is saved immediately.
523      *
524      * @param managedRepositoryConfiguration the repository configuration
525      * @return the updated or created repository
526      * @throws RepositoryException if an error occurs, or the configuration is not valid.
527      */
528     @Override
529     public ManagedRepository putRepository( ManagedRepositoryConfiguration managedRepositoryConfiguration ) throws RepositoryException
530     {
531         rwLock.writeLock( ).lock( );
532         try
533         {
534             return managedRepositoryHandler.put( managedRepositoryConfiguration );
535         }
536         finally
537         {
538             rwLock.writeLock( ).unlock( );
539         }
540
541     }
542
543     /**
544      * Adds a new repository or updates the repository with the same id. The given configuration object is updated, but
545      * the configuration is not saved.
546      *
547      * @param managedRepositoryConfiguration the new or changed managed repository configuration
548      * @param configuration                  the configuration object (may be <code>null</code>)
549      * @return the new or updated repository
550      * @throws RepositoryException if the configuration cannot be saved or updated
551      */
552     @Override
553     public ManagedRepository putRepository( ManagedRepositoryConfiguration managedRepositoryConfiguration, Configuration configuration ) throws RepositoryException
554     {
555         rwLock.writeLock( ).lock( );
556         try
557         {
558             return managedRepositoryHandler.put( managedRepositoryConfiguration, configuration );
559         }
560         finally
561         {
562             rwLock.writeLock( ).unlock( );
563         }
564     }
565
566
567     /**
568      * Adds a new repository group to the current list, or replaces the repository group definition with
569      * the same id, if it exists already.
570      * The change is saved to the configuration immediately.
571      *
572      * @param repositoryGroup the new repository group.
573      * @throws RepositoryException if the new repository group could not be saved to the configuration.
574      */
575     @Override
576     public RepositoryGroup putRepositoryGroup( RepositoryGroup repositoryGroup ) throws RepositoryException
577     {
578         rwLock.writeLock( ).lock( );
579         try
580         {
581             if ( this.groupHandler == null )
582             {
583                 throw new RepositoryException( "Fatal error. RepositoryGroupHandler not registered!" );
584             }
585             return this.groupHandler.put( repositoryGroup );
586         }
587         finally
588         {
589             rwLock.writeLock( ).unlock( );
590         }
591     }
592
593     /**
594      * Adds a new repository group or updates the repository with the same id, if it exists already.
595      * The configuration is saved immediately.
596      *
597      * @param repositoryGroupConfiguration the repository configuration
598      * @return the updated or created repository
599      * @throws RepositoryException if an error occurs, or the configuration is not valid.
600      */
601     @Override
602     public RepositoryGroup putRepositoryGroup( RepositoryGroupConfiguration repositoryGroupConfiguration ) throws RepositoryException
603     {
604         rwLock.writeLock( ).lock( );
605         try
606         {
607             return groupHandler.put( repositoryGroupConfiguration );
608         }
609         finally
610         {
611             rwLock.writeLock( ).unlock( );
612         }
613
614     }
615
616     @Override
617     public CheckedResult<RepositoryGroup, Map<String, List<ValidationError>>> putRepositoryGroupAndValidate( RepositoryGroupConfiguration repositoryGroupConfiguration )
618         throws RepositoryException
619     {
620         rwLock.writeLock( ).lock( );
621         try
622         {
623             return groupHandler.putWithCheck( repositoryGroupConfiguration, groupHandler.getValidator( ) );
624         }
625         finally
626         {
627             rwLock.writeLock( ).unlock( );
628         }
629     }
630
631     /**
632      * Adds a new repository group or updates the repository group with the same id. The given configuration object is updated, but
633      * the configuration is not saved.
634      *
635      * @param repositoryGroupConfiguration The configuration of the new or changed repository group.
636      * @param configuration                The configuration object. If it is <code>null</code>, the configuration is not saved.
637      * @return The new or updated repository group
638      * @throws RepositoryException if the configuration cannot be saved or updated
639      */
640     @Override
641     public RepositoryGroup putRepositoryGroup( RepositoryGroupConfiguration repositoryGroupConfiguration, Configuration configuration ) throws RepositoryException
642     {
643         rwLock.writeLock( ).lock( );
644         try
645         {
646             return groupHandler.put( repositoryGroupConfiguration, configuration );
647         }
648         finally
649         {
650             rwLock.writeLock( ).unlock( );
651         }
652     }
653
654
655     /**
656      * Adds a remote repository, or overwrites the repository definition with the same id, if it exists already.
657      * The modification is saved to the configuration immediately.
658      *
659      * @param remoteRepository the remote repository to add
660      * @throws RepositoryException if an error occurs during configuration save
661      */
662     @Override
663     public RemoteRepository putRepository( RemoteRepository remoteRepository ) throws RepositoryException
664     {
665         rwLock.writeLock( ).lock( );
666         try
667         {
668             return remoteRepositoryHandler.put( remoteRepository );
669         }
670         finally
671         {
672             rwLock.writeLock( ).unlock( );
673         }
674     }
675
676     /**
677      * Adds a new repository or updates the repository with the same id, if it exists already.
678      * The configuration is saved immediately.
679      *
680      * @param remoteRepositoryConfiguration the repository configuration
681      * @return the updated or created repository
682      * @throws RepositoryException if an error occurs, or the configuration is not valid.
683      */
684     @Override
685     public RemoteRepository putRepository( RemoteRepositoryConfiguration remoteRepositoryConfiguration ) throws RepositoryException
686     {
687         rwLock.writeLock( ).lock( );
688         try
689         {
690             return remoteRepositoryHandler.put( remoteRepositoryConfiguration );
691         }
692         finally
693         {
694             rwLock.writeLock( ).unlock( );
695         }
696     }
697
698     /**
699      * Adds a new repository or updates the repository with the same id. The given configuration object is updated, but
700      * the configuration is not saved.
701      *
702      * @param remoteRepositoryConfiguration the new or changed repository configuration
703      * @param configuration                 the configuration object
704      * @return the new or updated repository
705      * @throws RepositoryException if the configuration cannot be saved or updated
706      */
707     @Override
708     public RemoteRepository putRepository( RemoteRepositoryConfiguration remoteRepositoryConfiguration, Configuration configuration ) throws RepositoryException
709     {
710         rwLock.writeLock( ).lock( );
711         try
712         {
713             return remoteRepositoryHandler.put( remoteRepositoryConfiguration, configuration );
714         }
715         finally
716         {
717             rwLock.writeLock( ).unlock( );
718         }
719     }
720
721     @Override
722     public void removeRepository( String repoId ) throws RepositoryException
723     {
724         Repository repo = getRepository( repoId );
725         if ( repo != null )
726         {
727             removeRepository( repo );
728         }
729     }
730
731     @Override
732     public void removeRepository( Repository repo ) throws RepositoryException
733     {
734         if ( repo == null )
735         {
736             log.warn( "Trying to remove null repository" );
737             return;
738         }
739         if ( repo instanceof RemoteRepository )
740         {
741             removeRepository( (RemoteRepository) repo );
742         }
743         else if ( repo instanceof ManagedRepository )
744         {
745             removeRepository( (ManagedRepository) repo );
746         }
747         else if ( repo instanceof RepositoryGroup )
748         {
749             removeRepositoryGroup( (RepositoryGroup) repo );
750         }
751         else
752         {
753             throw new RepositoryException( "Repository type not known: " + repo.getClass( ) );
754         }
755     }
756
757     /**
758      * Removes a managed repository from the registry and configuration, if it exists.
759      * The change is saved to the configuration immediately.
760      *
761      * @param managedRepository the managed repository to remove
762      * @throws RepositoryException if a error occurs during configuration save
763      */
764     @Override
765     public void removeRepository( ManagedRepository managedRepository ) throws RepositoryException
766     {
767         if ( managedRepository == null )
768         {
769             return;
770         }
771         rwLock.writeLock( ).lock( );
772         try
773         {
774             if (managed_initialized.get() ) managedRepositoryHandler.remove( managedRepository.getId( ) );
775         }
776         finally
777         {
778             rwLock.writeLock( ).unlock( );
779         }
780     }
781
782
783     @Override
784     public void removeRepository( ManagedRepository managedRepository, Configuration configuration ) throws RepositoryException
785     {
786         if ( managedRepository == null )
787         {
788             return;
789         }
790             rwLock.writeLock( ).lock( );
791             try
792             {
793                 if (managed_initialized.get()) managedRepositoryHandler.remove( managedRepository.getId( ), configuration );
794             }
795             finally
796             {
797                 rwLock.writeLock( ).unlock( );
798             }
799
800     }
801
802
803     /**
804      * Removes a repository group from the registry and configuration, if it exists.
805      * The change is saved to the configuration immediately.
806      *
807      * @param repositoryGroup the repository group to remove
808      * @throws RepositoryException if a error occurs during configuration save
809      */
810     @Override
811     public void removeRepositoryGroup( RepositoryGroup repositoryGroup ) throws RepositoryException
812     {
813         if ( repositoryGroup == null )
814         {
815             return;
816         }
817         final String id = repositoryGroup.getId( );
818         if ( groupHandler.hasRepository( id ) )
819         {
820             rwLock.writeLock( ).lock( );
821             try
822             {
823                 groupHandler.remove( id );
824             }
825             finally
826             {
827                 rwLock.writeLock( ).unlock( );
828             }
829         }
830     }
831
832     @Override
833     public void removeRepositoryGroup( RepositoryGroup repositoryGroup, Configuration configuration ) throws RepositoryException
834     {
835         if ( repositoryGroup == null )
836         {
837             return;
838         }
839         final String id = repositoryGroup.getId( );
840         if ( groupHandler.hasRepository( id ) )
841         {
842             rwLock.writeLock( ).lock( );
843             try
844             {
845                 groupHandler.remove( id, configuration );
846             }
847             finally
848             {
849                 rwLock.writeLock( ).unlock( );
850             }
851         }
852     }
853
854     /**
855      * Removes the remote repository from the registry and configuration.
856      * The change is saved to the configuration immediately.
857      *
858      * @param remoteRepository the remote repository to remove
859      * @throws RepositoryException if a error occurs during configuration save
860      */
861     @Override
862     public void removeRepository( RemoteRepository remoteRepository ) throws RepositoryException
863     {
864         if ( remoteRepository == null )
865         {
866             return;
867         }
868         final String id = remoteRepository.getId( );
869         if ( remoteRepositoryHandler.hasRepository( id ) )
870         {
871             rwLock.writeLock( ).lock( );
872             try
873             {
874                 remoteRepositoryHandler.remove( id );
875             }
876             finally
877             {
878                 rwLock.writeLock( ).unlock( );
879             }
880         }
881     }
882
883     @Override
884     public void removeRepository( RemoteRepository remoteRepository, Configuration configuration ) throws RepositoryException
885     {
886         if ( remoteRepository == null )
887         {
888             return;
889         }
890         final String id = remoteRepository.getId( );
891         if ( remoteRepositoryHandler.hasRepository( id ) )
892         {
893             rwLock.writeLock( ).lock( );
894             try
895             {
896                 remoteRepositoryHandler.remove( id, configuration );
897             }
898             finally
899             {
900                 rwLock.writeLock( ).unlock( );
901             }
902         }
903     }
904
905     /**
906      * Reloads the registry from the configuration.
907      */
908     @Override
909     public void reload( )
910     {
911         initialize( );
912     }
913
914     /**
915      * Resets the indexing context of a given repository.
916      *
917      * @param repository The repository
918      * @throws IndexUpdateFailedException If the index could not be resetted.
919      */
920     @Override
921     public void resetIndexingContext( Repository repository ) throws IndexUpdateFailedException
922     {
923         if ( repository.hasIndex( ) && repository instanceof EditableRepository )
924         {
925             EditableRepository eRepo = (EditableRepository) repository;
926             ArchivaIndexingContext newCtx = getIndexManager( repository.getType( ) ).reset( repository.getIndexingContext( ) );
927             eRepo.setIndexingContext( newCtx );
928         }
929     }
930
931
932     /**
933      * Creates a new repository instance with the same settings as this one. The cloned repository is not
934      * registered or saved to the configuration.
935      *
936      * @param repo The origin repository
937      * @return The cloned repository.
938      */
939     public ManagedRepository clone( ManagedRepository repo, String newId ) throws RepositoryException
940     {
941         if (isRegisteredId( newId )) {
942             throw new RepositoryException( "The new id exists already: " + newId );
943         }
944         return managedRepositoryHandler.clone( repo, newId );
945     }
946
947     /**
948      * Creates a new repository instance with the same settings as this one. The cloned repository is not
949      * registered or saved to the configuration.
950      *
951      * @param repo The origin repository
952      * @return The cloned repository.
953      */
954     public RemoteRepository clone( RemoteRepository repo, String newId ) throws RepositoryException
955     {
956         if (isRegisteredId( newId )) {
957             throw new RepositoryException( "The new id exists already: " + newId );
958         }
959         return remoteRepositoryHandler.clone( repo, newId );
960     }
961
962     @SuppressWarnings( "unchecked" )
963     @Override
964     public <T extends Repository> T clone( T repo, String newId ) throws RepositoryException
965     {
966         if (isRegisteredId( newId )) {
967             throw new RepositoryException( "The new id exists already: " + newId );
968         }
969         if ( repo instanceof RemoteRepository )
970         {
971             return (T) remoteRepositoryHandler.clone( (RemoteRepository) repo, newId );
972         }
973         else if ( repo instanceof ManagedRepository )
974         {
975             return (T) managedRepositoryHandler.clone( (ManagedRepository) repo, newId );
976         }
977         else if (repo instanceof RepositoryGroup) {
978             return (T) groupHandler.clone( (RepositoryGroup) repo, newId );
979         }
980         else
981         {
982             throw new RepositoryException( "This repository class is not supported " + repo.getClass( ).getName( ) );
983         }
984     }
985
986
987     @Override
988     public Repository getRepositoryOfAsset( StorageAsset asset )
989     {
990         if ( asset instanceof Repository )
991         {
992             return (Repository) asset;
993         }
994         else
995         {
996             return getRepositories( ).stream( ).filter( r -> r.getRoot( )
997                 .getStorage( ).equals( asset.getStorage( ) ) ).findFirst( ).orElse( null );
998         }
999     }
1000
1001     @Override
1002     public <R extends Repository> ValidationResponse<R> validateRepository( R repository )
1003     {
1004         @SuppressWarnings( "unchecked" ) Map<String, List<ValidationError>> errorMap = this.validators.stream( )
1005             .filter( ( validator ) -> validator.getType( ).equals( RepositoryType.ALL ) || repository.getType( ).equals( validator.getType( ) ) )
1006             .filter( val -> val.isFlavour( repository.getClass( ) ) )
1007             .flatMap( validator -> ( (RepositoryValidator<R>) validator ).apply( repository ).getResult( ).entrySet( ).stream( ) )
1008             .collect( Collectors.toMap(
1009                 Map.Entry::getKey,
1010                 Map.Entry::getValue,
1011                 ListUtils::union
1012             ) );
1013         return new ValidationResponse<>( repository, errorMap );
1014     }
1015
1016     @Override
1017     public <R extends Repository> ValidationResponse<R> validateRepositoryForUpdate( R repository )
1018     {
1019         @SuppressWarnings( "unchecked" ) Map<String, List<ValidationError>> errorMap = this.validators.stream( )
1020             .filter( ( validator ) -> validator.getType( ).equals( RepositoryType.ALL ) || repository.getType( ).equals( validator.getType( ) ) )
1021             .filter( val -> val.isFlavour( repository.getClass( ) ) )
1022             .flatMap( validator -> ( (RepositoryValidator<R>) validator ).applyForUpdate( repository ).getResult( ).entrySet( ).stream( ) )
1023             .collect( Collectors.toMap(
1024                 Map.Entry::getKey,
1025                 Map.Entry::getValue,
1026                 ListUtils::union
1027             ) );
1028         return new ValidationResponse<>( repository, errorMap );
1029     }
1030
1031     @Override
1032     public void configurationEvent( ConfigurationEvent event )
1033     {
1034         // We ignore the event, if the save was triggered by ourself
1035         if ( !ConfigurationHandler.REGISTRY_EVENT_TAG.equals( event.getTag( ) ) )
1036         {
1037             reload( );
1038         }
1039     }
1040
1041
1042     @Override
1043     public <T extends Event> void registerEventHandler( EventType<T> type, EventHandler<? super T> eventHandler )
1044     {
1045         eventManager.registerEventHandler( type, eventHandler );
1046     }
1047
1048
1049     @Override
1050     public <T extends Event> void unregisterEventHandler( EventType<T> type, EventHandler<? super T> eventHandler )
1051     {
1052         eventManager.unregisterEventHandler( type, eventHandler );
1053     }
1054
1055
1056     @Override
1057     public void handle( Event event )
1058     {
1059         // To avoid event cycles:
1060         if ( sameOriginator( event ) )
1061         {
1062             return;
1063         }
1064         if ( event instanceof RepositoryIndexEvent )
1065         {
1066             handleIndexCreationEvent( (RepositoryIndexEvent) event );
1067         }
1068         // We propagate all events to our listeners, but with context of repository registry
1069         pushEvent( event );
1070     }
1071
1072     private void handleIndexCreationEvent( RepositoryIndexEvent event )
1073     {
1074         if (!ignoreIndexing && !( event.getRepository() instanceof  ManagedRepository ))
1075         {
1076             EditableRepository repo = (EditableRepository) event.getRepository( );
1077             if ( repo != null )
1078             {
1079                 ArchivaIndexManager idxmgr = getIndexManager( repo.getType( ) );
1080                 if ( repo.getIndexingContext( ) != null )
1081                 {
1082                     try
1083                     {
1084                         ArchivaIndexingContext newCtx = idxmgr.move( repo.getIndexingContext( ), repo );
1085                         repo.setIndexingContext( newCtx );
1086                         idxmgr.updateLocalIndexPath( repo );
1087
1088                     }
1089                     catch ( IndexCreationFailedException e )
1090                     {
1091                         log.error( "Could not move index to new directory: '{}'", e.getMessage( ), e );
1092                     }
1093                 }
1094                 else
1095                 {
1096                     try
1097                     {
1098                         ArchivaIndexingContext context = idxmgr.createContext( repo );
1099                         repo.setIndexingContext( context );
1100                         idxmgr.updateLocalIndexPath( repo );
1101                     }
1102                     catch ( IndexCreationFailedException e )
1103                     {
1104                         log.error( "Could not create index:  '{}'", e.getMessage( ), e );
1105                     }
1106                 }
1107             }
1108         }
1109     }
1110
1111     private boolean sameOriginator( Event event )
1112     {
1113         if ( event.getSource( ) == this )
1114         {
1115             return true;
1116         }
1117         else if ( event.hasPreviousEvent( ) )
1118         {
1119             return sameOriginator( event.getPreviousEvent( ) );
1120         }
1121         else
1122         {
1123             return false;
1124         }
1125     }
1126
1127     private void pushEvent( Event event )
1128     {
1129         eventManager.fireEvent( event );
1130     }
1131
1132     private <R extends Repository, C extends AbstractRepositoryConfiguration> void doRegister( RepositoryHandler<R, C> repositoryHandler )
1133     {
1134         repositoryHandler.setRepositoryProviders( this.repositoryProviders );
1135         repositoryHandler.setRepositoryValidator( this.repositoryValidatorList );
1136     }
1137
1138     @SuppressWarnings( "unchecked" )
1139     @Override
1140     public void registerHandler( RepositoryHandler<?, ?> handler )
1141     {
1142         if ( handler.getVariant( ).isAssignableFrom( RepositoryGroup.class ) )
1143         {
1144             registerGroupHandler( (RepositoryHandler<RepositoryGroup, RepositoryGroupConfiguration>) handler );
1145         }
1146         else if ( handler.getVariant( ).isAssignableFrom( ManagedRepository.class ) )
1147         {
1148             registerManagedRepositoryHandler( (RepositoryHandler<ManagedRepository, ManagedRepositoryConfiguration>) handler );
1149         }
1150         else if ( handler.getVariant().isAssignableFrom( RemoteRepository.class )) {
1151             registerRemoteRepositoryHandler( (RepositoryHandler<RemoteRepository, RemoteRepositoryConfiguration>) handler );
1152         }
1153     }
1154
1155     @Override
1156     public boolean isRegisteredId( String id )
1157     {
1158         return hasRepository( id );
1159     }
1160
1161     @SuppressWarnings( "unchecked" )
1162     @Override
1163     public <R extends Repository, C extends AbstractRepositoryConfiguration> RepositoryHandler<R, C> getHandler( Class<R> repositoryClazz, Class<C> configurationClazz )
1164     {
1165         if ( repositoryClazz.isAssignableFrom( RepositoryGroup.class ) )
1166         {
1167             return (RepositoryHandler<R, C>) this.groupHandler;
1168         }
1169         else if ( repositoryClazz.isAssignableFrom( ManagedRepository.class ) )
1170         {
1171             return (RepositoryHandler<R, C>) this.managedRepositoryHandler;
1172         }
1173         else if ( repositoryClazz.isAssignableFrom( RemoteRepository.class )) {
1174             return (RepositoryHandler<R, C>) this.remoteRepositoryHandler;
1175         }
1176         else
1177         {
1178             return null;
1179         }
1180     }
1181
1182     public boolean isIgnoreIndexing( )
1183     {
1184         return ignoreIndexing;
1185     }
1186
1187     public void setIgnoreIndexing( boolean ignoreIndexing )
1188     {
1189         this.ignoreIndexing = ignoreIndexing;
1190     }
1191
1192
1193 }