]> source.dussan.org Git - archiva.git/blob
1d0c32207dab3ec57014f186bce95c9458dd76d8
[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.model.AbstractRepositoryConfiguration;
24 import org.apache.archiva.configuration.provider.ArchivaConfiguration;
25 import org.apache.archiva.configuration.model.Configuration;
26 import org.apache.archiva.configuration.provider.ConfigurationEvent;
27 import org.apache.archiva.configuration.provider.ConfigurationListener;
28 import org.apache.archiva.configuration.provider.IndeterminateConfigurationException;
29 import org.apache.archiva.configuration.model.ManagedRepositoryConfiguration;
30 import org.apache.archiva.configuration.model.RemoteRepositoryConfiguration;
31 import org.apache.archiva.configuration.model.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     @Override
567     public CheckedResult<ManagedRepository, Map<String, List<ValidationError>>> putRepositoryAndValidate( ManagedRepositoryConfiguration configuration ) throws RepositoryException
568     {
569         rwLock.writeLock().lock();
570         try {
571             return managedRepositoryHandler.putWithCheck( configuration );
572         } finally
573         {
574             rwLock.writeLock( ).unlock( );
575         }
576     }
577
578     /**
579      * Adds a new repository group to the current list, or replaces the repository group definition with
580      * the same id, if it exists already.
581      * The change is saved to the configuration immediately.
582      *
583      * @param repositoryGroup the new repository group.
584      * @throws RepositoryException if the new repository group could not be saved to the configuration.
585      */
586     @Override
587     public RepositoryGroup putRepositoryGroup( RepositoryGroup repositoryGroup ) throws RepositoryException
588     {
589         rwLock.writeLock( ).lock( );
590         try
591         {
592             if ( this.groupHandler == null )
593             {
594                 throw new RepositoryException( "Fatal error. RepositoryGroupHandler not registered!" );
595             }
596             return this.groupHandler.put( repositoryGroup );
597         }
598         finally
599         {
600             rwLock.writeLock( ).unlock( );
601         }
602     }
603
604     /**
605      * Adds a new repository group or updates the repository with the same id, if it exists already.
606      * The configuration is saved immediately.
607      *
608      * @param repositoryGroupConfiguration the repository configuration
609      * @return the updated or created repository
610      * @throws RepositoryException if an error occurs, or the configuration is not valid.
611      */
612     @Override
613     public RepositoryGroup putRepositoryGroup( RepositoryGroupConfiguration repositoryGroupConfiguration ) throws RepositoryException
614     {
615         rwLock.writeLock( ).lock( );
616         try
617         {
618             return groupHandler.put( repositoryGroupConfiguration );
619         }
620         finally
621         {
622             rwLock.writeLock( ).unlock( );
623         }
624
625     }
626
627     @Override
628     public CheckedResult<RepositoryGroup, Map<String, List<ValidationError>>> putRepositoryGroupAndValidate( RepositoryGroupConfiguration repositoryGroupConfiguration )
629         throws RepositoryException
630     {
631         rwLock.writeLock( ).lock( );
632         try
633         {
634             return groupHandler.putWithCheck( repositoryGroupConfiguration );
635         }
636         finally
637         {
638             rwLock.writeLock( ).unlock( );
639         }
640     }
641
642     /**
643      * Adds a new repository group or updates the repository group with the same id. The given configuration object is updated, but
644      * the configuration is not saved.
645      *
646      * @param repositoryGroupConfiguration The configuration of the new or changed repository group.
647      * @param configuration                The configuration object. If it is <code>null</code>, the configuration is not saved.
648      * @return The new or updated repository group
649      * @throws RepositoryException if the configuration cannot be saved or updated
650      */
651     @Override
652     public RepositoryGroup putRepositoryGroup( RepositoryGroupConfiguration repositoryGroupConfiguration, Configuration configuration ) throws RepositoryException
653     {
654         rwLock.writeLock( ).lock( );
655         try
656         {
657             return groupHandler.put( repositoryGroupConfiguration, configuration );
658         }
659         finally
660         {
661             rwLock.writeLock( ).unlock( );
662         }
663     }
664
665
666     /**
667      * Adds a remote repository, or overwrites the repository definition with the same id, if it exists already.
668      * The modification is saved to the configuration immediately.
669      *
670      * @param remoteRepository the remote repository to add
671      * @throws RepositoryException if an error occurs during configuration save
672      */
673     @Override
674     public RemoteRepository putRepository( RemoteRepository remoteRepository ) throws RepositoryException
675     {
676         rwLock.writeLock( ).lock( );
677         try
678         {
679             return remoteRepositoryHandler.put( remoteRepository );
680         }
681         finally
682         {
683             rwLock.writeLock( ).unlock( );
684         }
685     }
686
687     /**
688      * Adds a new repository or updates the repository with the same id, if it exists already.
689      * The configuration is saved immediately.
690      *
691      * @param remoteRepositoryConfiguration the repository configuration
692      * @return the updated or created repository
693      * @throws RepositoryException if an error occurs, or the configuration is not valid.
694      */
695     @Override
696     public RemoteRepository putRepository( RemoteRepositoryConfiguration remoteRepositoryConfiguration ) throws RepositoryException
697     {
698         rwLock.writeLock( ).lock( );
699         try
700         {
701             return remoteRepositoryHandler.put( remoteRepositoryConfiguration );
702         }
703         finally
704         {
705             rwLock.writeLock( ).unlock( );
706         }
707     }
708
709     @Override
710     public CheckedResult<RemoteRepository, Map<String, List<ValidationError>>> putRepositoryAndValidate( RemoteRepositoryConfiguration remoteRepositoryConfiguration ) throws RepositoryException
711     {
712         rwLock.writeLock().lock();
713         try {
714             return remoteRepositoryHandler.putWithCheck( remoteRepositoryConfiguration );
715         } finally
716         {
717             rwLock.writeLock().unlock();
718         }
719     }
720
721     /**
722      * Adds a new repository or updates the repository with the same id. The given configuration object is updated, but
723      * the configuration is not saved.
724      *
725      * @param remoteRepositoryConfiguration the new or changed repository configuration
726      * @param configuration                 the configuration object
727      * @return the new or updated repository
728      * @throws RepositoryException if the configuration cannot be saved or updated
729      */
730     @Override
731     public RemoteRepository putRepository( RemoteRepositoryConfiguration remoteRepositoryConfiguration, Configuration configuration ) throws RepositoryException
732     {
733         rwLock.writeLock( ).lock( );
734         try
735         {
736             return remoteRepositoryHandler.put( remoteRepositoryConfiguration, configuration );
737         }
738         finally
739         {
740             rwLock.writeLock( ).unlock( );
741         }
742     }
743
744     @Override
745     public void removeRepository( String repoId ) throws RepositoryException
746     {
747         Repository repo = getRepository( repoId );
748         if ( repo != null )
749         {
750             removeRepository( repo );
751         }
752     }
753
754     @Override
755     public void removeRepository( Repository repo ) throws RepositoryException
756     {
757         if ( repo == null )
758         {
759             log.warn( "Trying to remove null repository" );
760             return;
761         }
762         if ( repo instanceof RemoteRepository )
763         {
764             removeRepository( (RemoteRepository) repo );
765         }
766         else if ( repo instanceof ManagedRepository )
767         {
768             removeRepository( (ManagedRepository) repo );
769         }
770         else if ( repo instanceof RepositoryGroup )
771         {
772             removeRepositoryGroup( (RepositoryGroup) repo );
773         }
774         else
775         {
776             throw new RepositoryException( "Repository type not known: " + repo.getClass( ) );
777         }
778     }
779
780     /**
781      * Removes a managed repository from the registry and configuration, if it exists.
782      * The change is saved to the configuration immediately.
783      *
784      * @param managedRepository the managed repository to remove
785      * @throws RepositoryException if a error occurs during configuration save
786      */
787     @Override
788     public void removeRepository( ManagedRepository managedRepository ) throws RepositoryException
789     {
790         if ( managedRepository == null )
791         {
792             return;
793         }
794         rwLock.writeLock( ).lock( );
795         try
796         {
797             if (managed_initialized.get() ) managedRepositoryHandler.remove( managedRepository.getId( ) );
798         }
799         finally
800         {
801             rwLock.writeLock( ).unlock( );
802         }
803     }
804
805
806     @Override
807     public void removeRepository( ManagedRepository managedRepository, Configuration configuration ) throws RepositoryException
808     {
809         if ( managedRepository == null )
810         {
811             return;
812         }
813             rwLock.writeLock( ).lock( );
814             try
815             {
816                 if (managed_initialized.get()) managedRepositoryHandler.remove( managedRepository.getId( ), configuration );
817             }
818             finally
819             {
820                 rwLock.writeLock( ).unlock( );
821             }
822
823     }
824
825
826     /**
827      * Removes a repository group from the registry and configuration, if it exists.
828      * The change is saved to the configuration immediately.
829      *
830      * @param repositoryGroup the repository group to remove
831      * @throws RepositoryException if a error occurs during configuration save
832      */
833     @Override
834     public void removeRepositoryGroup( RepositoryGroup repositoryGroup ) throws RepositoryException
835     {
836         if ( repositoryGroup == null )
837         {
838             return;
839         }
840         final String id = repositoryGroup.getId( );
841         if ( groupHandler.hasRepository( id ) )
842         {
843             rwLock.writeLock( ).lock( );
844             try
845             {
846                 groupHandler.remove( id );
847             }
848             finally
849             {
850                 rwLock.writeLock( ).unlock( );
851             }
852         }
853     }
854
855     @Override
856     public void removeRepositoryGroup( RepositoryGroup repositoryGroup, Configuration configuration ) throws RepositoryException
857     {
858         if ( repositoryGroup == null )
859         {
860             return;
861         }
862         final String id = repositoryGroup.getId( );
863         if ( groupHandler.hasRepository( id ) )
864         {
865             rwLock.writeLock( ).lock( );
866             try
867             {
868                 groupHandler.remove( id, configuration );
869             }
870             finally
871             {
872                 rwLock.writeLock( ).unlock( );
873             }
874         }
875     }
876
877     /**
878      * Removes the remote repository from the registry and configuration.
879      * The change is saved to the configuration immediately.
880      *
881      * @param remoteRepository the remote repository to remove
882      * @throws RepositoryException if a error occurs during configuration save
883      */
884     @Override
885     public void removeRepository( RemoteRepository remoteRepository ) throws RepositoryException
886     {
887         if ( remoteRepository == null )
888         {
889             return;
890         }
891         final String id = remoteRepository.getId( );
892         if ( remoteRepositoryHandler.hasRepository( id ) )
893         {
894             rwLock.writeLock( ).lock( );
895             try
896             {
897                 remoteRepositoryHandler.remove( id );
898             }
899             finally
900             {
901                 rwLock.writeLock( ).unlock( );
902             }
903         }
904     }
905
906     @Override
907     public void removeRepository( RemoteRepository remoteRepository, Configuration configuration ) throws RepositoryException
908     {
909         if ( remoteRepository == null )
910         {
911             return;
912         }
913         final String id = remoteRepository.getId( );
914         if ( remoteRepositoryHandler.hasRepository( id ) )
915         {
916             rwLock.writeLock( ).lock( );
917             try
918             {
919                 remoteRepositoryHandler.remove( id, configuration );
920             }
921             finally
922             {
923                 rwLock.writeLock( ).unlock( );
924             }
925         }
926     }
927
928     /**
929      * Reloads the registry from the configuration.
930      */
931     @Override
932     public void reload( )
933     {
934         initialize( );
935     }
936
937     /**
938      * Resets the indexing context of a given repository.
939      *
940      * @param repository The repository
941      * @throws IndexUpdateFailedException If the index could not be resetted.
942      */
943     @Override
944     public void resetIndexingContext( Repository repository ) throws IndexUpdateFailedException
945     {
946         if ( repository.hasIndex( ) && repository instanceof EditableRepository )
947         {
948             EditableRepository eRepo = (EditableRepository) repository;
949             ArchivaIndexingContext newCtx = getIndexManager( repository.getType( ) ).reset( repository.getIndexingContext( ) );
950             eRepo.setIndexingContext( newCtx );
951         }
952     }
953
954
955     /**
956      * Creates a new repository instance with the same settings as this one. The cloned repository is not
957      * registered or saved to the configuration.
958      *
959      * @param repo The origin repository
960      * @return The cloned repository.
961      */
962     public ManagedRepository clone( ManagedRepository repo, String newId ) throws RepositoryException
963     {
964         if (isRegisteredId( newId )) {
965             throw new RepositoryException( "The new id exists already: " + newId );
966         }
967         return managedRepositoryHandler.clone( repo, newId );
968     }
969
970     /**
971      * Creates a new repository instance with the same settings as this one. The cloned repository is not
972      * registered or saved to the configuration.
973      *
974      * @param repo The origin repository
975      * @return The cloned repository.
976      */
977     public RemoteRepository clone( RemoteRepository repo, String newId ) throws RepositoryException
978     {
979         if (isRegisteredId( newId )) {
980             throw new RepositoryException( "The new id exists already: " + newId );
981         }
982         return remoteRepositoryHandler.clone( repo, newId );
983     }
984
985     @SuppressWarnings( "unchecked" )
986     @Override
987     public <T extends Repository> T clone( T repo, String newId ) throws RepositoryException
988     {
989         if (isRegisteredId( newId )) {
990             throw new RepositoryException( "The new id exists already: " + newId );
991         }
992         if ( repo instanceof RemoteRepository )
993         {
994             return (T) remoteRepositoryHandler.clone( (RemoteRepository) repo, newId );
995         }
996         else if ( repo instanceof ManagedRepository )
997         {
998             return (T) managedRepositoryHandler.clone( (ManagedRepository) repo, newId );
999         }
1000         else if (repo instanceof RepositoryGroup) {
1001             return (T) groupHandler.clone( (RepositoryGroup) repo, newId );
1002         }
1003         else
1004         {
1005             throw new RepositoryException( "This repository class is not supported " + repo.getClass( ).getName( ) );
1006         }
1007     }
1008
1009
1010     @Override
1011     public Repository getRepositoryOfAsset( StorageAsset asset )
1012     {
1013         if ( asset instanceof Repository )
1014         {
1015             return (Repository) asset;
1016         }
1017         else
1018         {
1019             return getRepositories( ).stream( ).filter( r -> r.getRoot( )
1020                 .getStorage( ).equals( asset.getStorage( ) ) ).findFirst( ).orElse( null );
1021         }
1022     }
1023
1024     @Override
1025     public <R extends Repository> ValidationResponse<R> validateRepository( R repository )
1026     {
1027         @SuppressWarnings( "unchecked" ) Map<String, List<ValidationError>> errorMap = this.validators.stream( )
1028             .filter( ( validator ) -> validator.getType( ).equals( RepositoryType.ALL ) || repository.getType( ).equals( validator.getType( ) ) )
1029             .filter( val -> val.isFlavour( repository.getClass( ) ) )
1030             .flatMap( validator -> ( (RepositoryValidator<R>) validator ).apply( repository ).getResult( ).entrySet( ).stream( ) )
1031             .collect( Collectors.toMap(
1032                 Map.Entry::getKey,
1033                 Map.Entry::getValue,
1034                 ListUtils::union
1035             ) );
1036         return new ValidationResponse<>( repository, errorMap );
1037     }
1038
1039     @Override
1040     public <R extends Repository> ValidationResponse<R> validateRepositoryForUpdate( R repository )
1041     {
1042         @SuppressWarnings( "unchecked" ) Map<String, List<ValidationError>> errorMap = this.validators.stream( )
1043             .filter( ( validator ) -> validator.getType( ).equals( RepositoryType.ALL ) || repository.getType( ).equals( validator.getType( ) ) )
1044             .filter( val -> val.isFlavour( repository.getClass( ) ) )
1045             .flatMap( validator -> ( (RepositoryValidator<R>) validator ).applyForUpdate( repository ).getResult( ).entrySet( ).stream( ) )
1046             .collect( Collectors.toMap(
1047                 Map.Entry::getKey,
1048                 Map.Entry::getValue,
1049                 ListUtils::union
1050             ) );
1051         return new ValidationResponse<>( repository, errorMap );
1052     }
1053
1054     @Override
1055     public void configurationEvent( ConfigurationEvent event )
1056     {
1057         // We ignore the event, if the save was triggered by ourself
1058         if ( !ConfigurationHandler.REGISTRY_EVENT_TAG.equals( event.getTag( ) ) )
1059         {
1060             reload( );
1061         }
1062     }
1063
1064
1065     @Override
1066     public <T extends Event> void registerEventHandler( EventType<T> type, EventHandler<? super T> eventHandler )
1067     {
1068         eventManager.registerEventHandler( type, eventHandler );
1069     }
1070
1071
1072     @Override
1073     public <T extends Event> void unregisterEventHandler( EventType<T> type, EventHandler<? super T> eventHandler )
1074     {
1075         eventManager.unregisterEventHandler( type, eventHandler );
1076     }
1077
1078
1079     @Override
1080     public void handle( Event event )
1081     {
1082         // To avoid event cycles:
1083         if ( sameOriginator( event ) )
1084         {
1085             return;
1086         }
1087         if ( event instanceof RepositoryIndexEvent )
1088         {
1089             handleIndexCreationEvent( (RepositoryIndexEvent) event );
1090         }
1091         // We propagate all events to our listeners, but with context of repository registry
1092         pushEvent( event );
1093     }
1094
1095     private void handleIndexCreationEvent( RepositoryIndexEvent event )
1096     {
1097         if (!ignoreIndexing && !( event.getRepository() instanceof  ManagedRepository ))
1098         {
1099             EditableRepository repo = (EditableRepository) event.getRepository( );
1100             if ( repo != null )
1101             {
1102                 ArchivaIndexManager idxmgr = getIndexManager( repo.getType( ) );
1103                 if ( repo.getIndexingContext( ) != null )
1104                 {
1105                     try
1106                     {
1107                         ArchivaIndexingContext newCtx = idxmgr.move( repo.getIndexingContext( ), repo );
1108                         repo.setIndexingContext( newCtx );
1109                         idxmgr.updateLocalIndexPath( repo );
1110
1111                     }
1112                     catch ( IndexCreationFailedException e )
1113                     {
1114                         log.error( "Could not move index to new directory: '{}'", e.getMessage( ), e );
1115                     }
1116                 }
1117                 else
1118                 {
1119                     try
1120                     {
1121                         ArchivaIndexingContext context = idxmgr.createContext( repo );
1122                         repo.setIndexingContext( context );
1123                         idxmgr.updateLocalIndexPath( repo );
1124                     }
1125                     catch ( IndexCreationFailedException e )
1126                     {
1127                         log.error( "Could not create index:  '{}'", e.getMessage( ), e );
1128                     }
1129                 }
1130             }
1131         }
1132     }
1133
1134     private boolean sameOriginator( Event event )
1135     {
1136         if ( event.getSource( ) == this )
1137         {
1138             return true;
1139         }
1140         else if ( event.hasPreviousEvent( ) )
1141         {
1142             return sameOriginator( event.getPreviousEvent( ) );
1143         }
1144         else
1145         {
1146             return false;
1147         }
1148     }
1149
1150     private void pushEvent( Event event )
1151     {
1152         eventManager.fireEvent( event );
1153     }
1154
1155     private <R extends Repository, C extends AbstractRepositoryConfiguration> void doRegister( RepositoryHandler<R, C> repositoryHandler )
1156     {
1157         repositoryHandler.setRepositoryProviders( this.repositoryProviders );
1158         repositoryHandler.setRepositoryValidator( this.repositoryValidatorList );
1159     }
1160
1161     @SuppressWarnings( "unchecked" )
1162     @Override
1163     public void registerHandler( RepositoryHandler<?, ?> handler )
1164     {
1165         if ( handler.getVariant( ).isAssignableFrom( RepositoryGroup.class ) )
1166         {
1167             registerGroupHandler( (RepositoryHandler<RepositoryGroup, RepositoryGroupConfiguration>) handler );
1168         }
1169         else if ( handler.getVariant( ).isAssignableFrom( ManagedRepository.class ) )
1170         {
1171             registerManagedRepositoryHandler( (RepositoryHandler<ManagedRepository, ManagedRepositoryConfiguration>) handler );
1172         }
1173         else if ( handler.getVariant().isAssignableFrom( RemoteRepository.class )) {
1174             registerRemoteRepositoryHandler( (RepositoryHandler<RemoteRepository, RemoteRepositoryConfiguration>) handler );
1175         }
1176     }
1177
1178     @Override
1179     public boolean isRegisteredId( String id )
1180     {
1181         return hasRepository( id );
1182     }
1183
1184     @SuppressWarnings( "unchecked" )
1185     @Override
1186     public <R extends Repository, C extends AbstractRepositoryConfiguration> RepositoryHandler<R, C> getHandler( Class<R> repositoryClazz, Class<C> configurationClazz )
1187     {
1188         if ( repositoryClazz.isAssignableFrom( RepositoryGroup.class ) )
1189         {
1190             return (RepositoryHandler<R, C>) this.groupHandler;
1191         }
1192         else if ( repositoryClazz.isAssignableFrom( ManagedRepository.class ) )
1193         {
1194             return (RepositoryHandler<R, C>) this.managedRepositoryHandler;
1195         }
1196         else if ( repositoryClazz.isAssignableFrom( RemoteRepository.class )) {
1197             return (RepositoryHandler<R, C>) this.remoteRepositoryHandler;
1198         }
1199         else
1200         {
1201             return null;
1202         }
1203     }
1204
1205     public boolean isIgnoreIndexing( )
1206     {
1207         return ignoreIndexing;
1208     }
1209
1210     public void setIgnoreIndexing( boolean ignoreIndexing )
1211     {
1212         this.ignoreIndexing = ignoreIndexing;
1213     }
1214
1215
1216 }