]> source.dussan.org Git - archiva.git/blob
b909e24de0b15e18277d268dc5588cc6083f8e15
[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.configuration.*;
23 import org.apache.archiva.event.Event;
24 import org.apache.archiva.event.EventManager;
25 import org.apache.archiva.event.EventType;
26 import org.apache.archiva.indexer.*;
27 import org.apache.archiva.components.registry.RegistryException;
28 import org.apache.archiva.repository.EditableManagedRepository;
29 import org.apache.archiva.repository.EditableRemoteRepository;
30 import org.apache.archiva.repository.EditableRepository;
31 import org.apache.archiva.repository.EditableRepositoryGroup;
32 import org.apache.archiva.repository.ManagedRepository;
33 import org.apache.archiva.repository.RemoteRepository;
34 import org.apache.archiva.repository.Repository;
35 import org.apache.archiva.repository.RepositoryContentFactory;
36 import org.apache.archiva.repository.RepositoryException;
37 import org.apache.archiva.repository.RepositoryGroup;
38 import org.apache.archiva.repository.RepositoryProvider;
39 import org.apache.archiva.repository.RepositoryRegistry;
40 import org.apache.archiva.repository.RepositoryType;
41 import org.apache.archiva.repository.UnsupportedRepositoryTypeException;
42 import org.apache.archiva.repository.event.*;
43 import org.apache.archiva.event.EventHandler;
44 import org.apache.archiva.repository.features.IndexCreationFeature;
45 import org.apache.archiva.repository.features.StagingRepositoryFeature;
46 import org.apache.archiva.repository.metadata.MetadataReader;
47 import org.apache.archiva.repository.storage.StorageAsset;
48 import org.apache.commons.lang3.StringUtils;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51 import org.springframework.stereotype.Service;
52
53 import javax.annotation.PostConstruct;
54 import javax.annotation.PreDestroy;
55 import javax.inject.Inject;
56 import javax.inject.Named;
57 import java.util.*;
58 import java.util.concurrent.locks.ReentrantReadWriteLock;
59 import java.util.stream.Collectors;
60 import java.util.stream.Stream;
61
62 import static org.apache.archiva.indexer.ArchivaIndexManager.DEFAULT_INDEX_PATH;
63
64 /**
65  * Registry for repositories. This is the central entry point for repositories. It provides methods for
66  * retrieving, adding and removing repositories.
67  * <p>
68  * The modification methods addXX and removeXX persist the changes immediately to the configuration. If the
69  * configuration save fails the changes are rolled back.
70  * <p>
71  * TODO: Audit events
72  *
73  * @since 3.0
74  */
75 @Service("repositoryRegistry")
76 public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHandler<Event>,
77     RepositoryRegistry
78 {
79
80     private static final Logger log = LoggerFactory.getLogger(RepositoryRegistry.class);
81
82     /**
83      * We inject all repository providers
84      */
85     @Inject
86     List<RepositoryProvider> repositoryProviders;
87
88     @Inject
89     IndexManagerFactory indexManagerFactory;
90
91     @Inject
92     ArchivaConfiguration archivaConfiguration;
93
94     @Inject
95     List<MetadataReader> metadataReaderList;
96
97     @Inject
98     @Named("repositoryContentFactory#default")
99     RepositoryContentFactory repositoryContentFactory;
100
101     private final EventManager eventManager;
102
103
104     private Map<String, ManagedRepository> managedRepositories = new HashMap<>();
105     private Map<String, ManagedRepository> uManagedRepository = Collections.unmodifiableMap(managedRepositories);
106
107     private Map<String, RemoteRepository> remoteRepositories = new HashMap<>();
108     private Map<String, RemoteRepository> uRemoteRepositories = Collections.unmodifiableMap(remoteRepositories);
109
110     private Map<String, RepositoryGroup> repositoryGroups = new HashMap<>();
111     private Map<String, RepositoryGroup> uRepositoryGroups = Collections.unmodifiableMap(repositoryGroups);
112
113     private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
114
115     private volatile boolean ignoreConfigEvents = false;
116
117     public ArchivaRepositoryRegistry() {
118         this.eventManager = new EventManager(this);
119     }
120
121     @Override
122     public void setArchivaConfiguration( ArchivaConfiguration archivaConfiguration ) {
123         this.archivaConfiguration = archivaConfiguration;
124     }
125
126     @PostConstruct
127     private void initialize() {
128         rwLock.writeLock().lock();
129         try {
130             log.debug("Initializing repository registry");
131             updateManagedRepositoriesFromConfig();
132             updateRemoteRepositoriesFromConfig();
133
134             repositoryGroups.clear();
135             Map<String, RepositoryGroup> repositoryGroups = getRepositorGroupsFromConfig();
136             this.repositoryGroups.putAll(repositoryGroups);
137
138             // archivaConfiguration.addChangeListener(this);
139             archivaConfiguration.addListener(this);
140         } finally {
141             rwLock.writeLock().unlock();
142         }
143         pushEvent(new RepositoryRegistryEvent(RepositoryRegistryEvent.RELOADED, this));
144     }
145
146     @PreDestroy
147     public void destroy() {
148         for (ManagedRepository rep : managedRepositories.values()) {
149             rep.close();
150         }
151         managedRepositories.clear();
152         for (RemoteRepository repo : remoteRepositories.values()) {
153             repo.close();
154         }
155         remoteRepositories.clear();
156         pushEvent(new RepositoryRegistryEvent(RepositoryRegistryEvent.DESTROYED, this));
157     }
158
159
160     private Map<RepositoryType, RepositoryProvider> createProviderMap() {
161         Map<RepositoryType, RepositoryProvider> map = new HashMap<>();
162         if (repositoryProviders != null) {
163             for (RepositoryProvider provider : repositoryProviders) {
164                 for (RepositoryType type : provider.provides()) {
165                     map.put(type, provider);
166                 }
167             }
168         }
169         return map;
170     }
171
172     private RepositoryProvider getProvider(RepositoryType type) throws RepositoryException
173     {
174         return repositoryProviders.stream().filter(repositoryProvider -> repositoryProvider.provides().contains(type)).findFirst().orElseThrow(() -> new RepositoryException("Repository type cannot be handled: " + type));
175     }
176
177     /*
178      * Updates the repositories
179      */
180     private void updateManagedRepositoriesFromConfig() {
181         try {
182
183             Set<String> configRepoIds = new HashSet<>();
184             List<ManagedRepositoryConfiguration> managedRepoConfigs =
185                     getArchivaConfiguration().getConfiguration().getManagedRepositories();
186
187             if (managedRepoConfigs == null) {
188                 return;
189             }
190
191             for (ManagedRepositoryConfiguration repoConfig : managedRepoConfigs) {
192                 ManagedRepository repo = putRepository(repoConfig, null);
193                 configRepoIds.add(repoConfig.getId());
194                 if (repo.supportsFeature(StagingRepositoryFeature.class)) {
195                     StagingRepositoryFeature stagF = repo.getFeature(StagingRepositoryFeature.class).get();
196                     if (stagF.getStagingRepository() != null) {
197                         configRepoIds.add(stagF.getStagingRepository().getId());
198                     }
199                 }
200             }
201             List<String> toRemove = managedRepositories.keySet().stream().filter(id -> !configRepoIds.contains(id)).collect(Collectors.toList());
202             for (String id : toRemove) {
203                 ManagedRepository removed = managedRepositories.remove(id);
204                 removed.close();
205             }
206         } catch (Throwable e) {
207             log.error("Could not initialize repositories from config: {}", e.getMessage(), e);
208             return;
209         }
210     }
211
212     private ManagedRepository createNewManagedRepository(RepositoryProvider provider, ManagedRepositoryConfiguration cfg) throws RepositoryException {
213         log.debug("Creating repo {}", cfg.getId());
214         ManagedRepository repo = provider.createManagedInstance(cfg);
215         repo.registerEventHandler(RepositoryEvent.ANY,  this);
216         updateRepositoryReferences(provider, repo, cfg, null);
217         return repo;
218
219     }
220
221     private String getStagingId(String repoId) {
222         return repoId + StagingRepositoryFeature.STAGING_REPO_POSTFIX;
223     }
224
225     @SuppressWarnings("unchecked")
226     private void updateRepositoryReferences(RepositoryProvider provider, ManagedRepository repo, ManagedRepositoryConfiguration cfg, Configuration configuration) throws RepositoryException {
227         log.debug("Updating references of repo {}", repo.getId());
228         if (repo.supportsFeature(StagingRepositoryFeature.class)) {
229             StagingRepositoryFeature feature = repo.getFeature(StagingRepositoryFeature.class).get();
230             if (feature.isStageRepoNeeded() && feature.getStagingRepository() == null) {
231                 ManagedRepository stageRepo = getManagedRepository(getStagingId(repo.getId()));
232                 if (stageRepo == null) {
233                     stageRepo = getStagingRepository(provider, cfg, configuration);
234                     managedRepositories.put(stageRepo.getId(), stageRepo);
235                     if (configuration != null) {
236                         replaceOrAddRepositoryConfig(provider.getManagedConfiguration(stageRepo), configuration);
237                     }
238                     pushEvent(new LifecycleEvent(LifecycleEvent.REGISTERED, this, stageRepo));
239                 }
240                 feature.setStagingRepository(stageRepo);
241             }
242         }
243         if (repo instanceof EditableManagedRepository ) {
244             EditableManagedRepository editableRepo = (EditableManagedRepository) repo;
245             if (repo.getContent() == null) {
246                 editableRepo.setContent(repositoryContentFactory.getManagedRepositoryContent(repo));
247                 editableRepo.getContent().setRepository(editableRepo);
248             }
249             log.debug("Index repo: " + repo.hasIndex());
250             if (repo.hasIndex() && ( repo.getIndexingContext() == null || !repo.getIndexingContext().isOpen() )) {
251                 log.debug("Creating indexing context for {}", repo.getId());
252                 createIndexingContext(editableRepo);
253             }
254         }
255         repo.registerEventHandler(RepositoryEvent.ANY, this);
256     }
257
258     @Override
259     public ArchivaIndexManager getIndexManager( RepositoryType type ) {
260         return indexManagerFactory.getIndexManager(type);
261     }
262
263     @Override
264     public MetadataReader getMetadataReader( final RepositoryType type ) throws UnsupportedRepositoryTypeException
265     {
266         if (metadataReaderList!=null) {
267             return metadataReaderList.stream( ).filter( mr -> mr.isValidForType( type ) ).findFirst( ).orElseThrow( ( ) -> new UnsupportedRepositoryTypeException( type ) );
268         } else {
269             throw new UnsupportedRepositoryTypeException( type );
270         }
271     }
272
273     private void createIndexingContext( EditableRepository editableRepo) throws RepositoryException {
274         if (editableRepo.supportsFeature(IndexCreationFeature.class)) {
275             ArchivaIndexManager idxManager = getIndexManager(editableRepo.getType());
276             try {
277                 editableRepo.setIndexingContext(idxManager.createContext(editableRepo));
278                 idxManager.updateLocalIndexPath(editableRepo);
279             } catch (IndexCreationFailedException e) {
280                 throw new RepositoryException("Could not create index for repository " + editableRepo.getId() + ": " + e.getMessage(), e);
281             }
282         }
283     }
284
285     private ManagedRepository getStagingRepository(RepositoryProvider provider, ManagedRepositoryConfiguration baseRepoCfg, Configuration configuration) throws RepositoryException {
286         ManagedRepository stageRepo = getManagedRepository(getStagingId(baseRepoCfg.getId()));
287         if (stageRepo == null) {
288             stageRepo = provider.createStagingInstance(baseRepoCfg);
289             if (stageRepo.supportsFeature(StagingRepositoryFeature.class)) {
290                 stageRepo.getFeature(StagingRepositoryFeature.class).get().setStageRepoNeeded(false);
291             }
292             ManagedRepositoryConfiguration stageCfg = provider.getManagedConfiguration(stageRepo);
293             updateRepositoryReferences(provider, stageRepo, stageCfg, configuration);
294         }
295         return stageRepo;
296     }
297
298
299     private void updateRemoteRepositoriesFromConfig() {
300         try {
301             List<RemoteRepositoryConfiguration> remoteRepoConfigs =
302                     getArchivaConfiguration().getConfiguration().getRemoteRepositories();
303
304             if (remoteRepoConfigs == null) {
305                 return;
306             }
307             Set<String> repoIds = new HashSet<>();
308             for (RemoteRepositoryConfiguration repoConfig : remoteRepoConfigs) {
309                 putRepository(repoConfig, null);
310                 repoIds.add(repoConfig.getId());
311             }
312
313             List<String> toRemove = remoteRepositories.keySet().stream().filter(id -> !repoIds.contains(id)).collect(Collectors.toList());
314             for (String id : toRemove) {
315                 RemoteRepository removed = remoteRepositories.remove(id);
316                 removed.close();
317             }
318
319         } catch (Throwable e) {
320             log.error("Could not initialize remote repositories from config: {}", e.getMessage(), e);
321             return;
322         }
323     }
324
325     private RemoteRepository createNewRemoteRepository(RepositoryProvider provider, RemoteRepositoryConfiguration cfg) throws RepositoryException {
326         log.debug("Creating remote repo {}", cfg.getId());
327         RemoteRepository repo = provider.createRemoteInstance(cfg);
328         updateRepositoryReferences(provider, repo, cfg, null);
329         return repo;
330
331     }
332
333     private void updateRepositoryReferences(RepositoryProvider provider, RemoteRepository repo, RemoteRepositoryConfiguration cfg, Configuration configuration) throws RepositoryException {
334         if (repo instanceof EditableRemoteRepository && repo.getContent() == null) {
335             EditableRemoteRepository editableRepo = (EditableRemoteRepository) repo;
336             editableRepo.setContent(repositoryContentFactory.getRemoteRepositoryContent(repo));
337             if (repo.supportsFeature(IndexCreationFeature.class) && repo.getIndexingContext() == null) {
338                 createIndexingContext(editableRepo);
339             }
340         }
341         repo.registerEventHandler(RepositoryEvent.ANY, this);
342     }
343
344     private Map<String, RepositoryGroup> getRepositorGroupsFromConfig() {
345         try {
346             List<RepositoryGroupConfiguration> repositoryGroupConfigurations =
347                     getArchivaConfiguration().getConfiguration().getRepositoryGroups();
348
349             if (repositoryGroupConfigurations == null) {
350                 return Collections.emptyMap();
351             }
352
353             Map<String, RepositoryGroup> repositoryGroupMap = new LinkedHashMap<>(repositoryGroupConfigurations.size());
354
355             Map<RepositoryType, RepositoryProvider> providerMap = createProviderMap();
356             for (RepositoryGroupConfiguration repoConfig : repositoryGroupConfigurations) {
357                 RepositoryType repositoryType = RepositoryType.valueOf(repoConfig.getType());
358                 if (providerMap.containsKey(repositoryType)) {
359                     try {
360                         RepositoryGroup repo = createNewRepositoryGroup(providerMap.get(repositoryType), repoConfig);
361                         repositoryGroupMap.put(repo.getId(), repo);
362                     } catch (Exception e) {
363                         log.error("Could not create repository group {}: {}", repoConfig.getId(), e.getMessage(), e);
364                     }
365                 }
366             }
367             return repositoryGroupMap;
368         } catch (Throwable e) {
369             log.error("Could not initialize repositories from config: {}", e.getMessage(), e);
370             return Collections.emptyMap();
371         }
372     }
373
374     private RepositoryGroup createNewRepositoryGroup(RepositoryProvider provider, RepositoryGroupConfiguration config) throws RepositoryException {
375         RepositoryGroup repositoryGroup = provider.createRepositoryGroup(config);
376         repositoryGroup.registerEventHandler(RepositoryEvent.ANY, this);
377         updateRepositoryReferences(provider, repositoryGroup, config);
378         return repositoryGroup;
379     }
380
381     private void updateRepositoryReferences(RepositoryProvider provider, RepositoryGroup group, RepositoryGroupConfiguration configuration) {
382         if (group instanceof EditableRepositoryGroup ) {
383             EditableRepositoryGroup eGroup = (EditableRepositoryGroup) group;
384             eGroup.setRepositories(configuration.getRepositories().stream().map(r -> getManagedRepository(r)).collect(Collectors.toList()));
385         }
386     }
387
388     private ArchivaConfiguration getArchivaConfiguration() {
389         return this.archivaConfiguration;
390     }
391
392     /**
393      * Returns all repositories that are registered. There is no defined order of the returned repositories.
394      *
395      * @return a list of managed and remote repositories
396      */
397     @Override
398     public Collection<Repository> getRepositories( ) {
399         rwLock.readLock().lock();
400         try {
401             return Stream.concat(managedRepositories.values().stream(), remoteRepositories.values().stream()).collect(Collectors.toList());
402         } finally {
403             rwLock.readLock().unlock();
404         }
405     }
406
407     /**
408      * Returns only the managed repositories. There is no defined order of the returned repositories.
409      *
410      * @return a list of managed repositories
411      */
412     @Override
413     public Collection<ManagedRepository> getManagedRepositories( ) {
414         rwLock.readLock().lock();
415         try {
416             return uManagedRepository.values();
417         } finally {
418             rwLock.readLock().unlock();
419         }
420     }
421
422     /**
423      * Returns only the remote repositories. There is no defined order of the returned repositories.
424      *
425      * @return a list of remote repositories
426      */
427     @Override
428     public Collection<RemoteRepository> getRemoteRepositories( ) {
429         rwLock.readLock().lock();
430         try {
431             return uRemoteRepositories.values();
432         } finally {
433             rwLock.readLock().unlock();
434         }
435     }
436
437     @Override
438     public Collection<RepositoryGroup> getRepositoryGroups( ) {
439         rwLock.readLock().lock();
440         try {
441             return uRepositoryGroups.values();
442         } finally {
443             rwLock.readLock().unlock();
444         }
445     }
446
447     /**
448      * Returns the repository with the given id. The returned repository may be a managed or remote repository.
449      * It returns null, if no repository is registered with the given id.
450      *
451      * @param repoId the repository id
452      * @return the repository if found, otherwise null
453      */
454     @Override
455     public Repository getRepository( String repoId ) {
456         rwLock.readLock().lock();
457         try {
458             log.debug("getRepository {}", repoId);
459             if (managedRepositories.containsKey(repoId)) {
460                 log.debug("Managed repo");
461                 return managedRepositories.get(repoId);
462             } else if (remoteRepositories.containsKey(repoId)) {
463                 log.debug("Remote repo");
464                 return remoteRepositories.get(repoId);
465             } else if (repositoryGroups.containsKey(repoId)) {
466                 return repositoryGroups.get(repoId);
467             } else {
468                 return null;
469             }
470         } finally {
471             rwLock.readLock().unlock();
472         }
473     }
474
475     /**
476      * Convenience method, that returns the managed repository with the given id.
477      * It returns null, if no managed repository is registered with this id.
478      *
479      * @param repoId the repository id
480      * @return the managed repository if found, otherwise null
481      */
482     @Override
483     public ManagedRepository getManagedRepository( String repoId ) {
484         rwLock.readLock().lock();
485         try {
486             return managedRepositories.get(repoId);
487         } finally {
488             rwLock.readLock().unlock();
489         }
490     }
491
492     /**
493      * Convenience method, that returns the remote repository with the given id.
494      * It returns null, if no remote repository is registered with this id.
495      *
496      * @param repoId the repository id
497      * @return the remote repository if found, otherwise null
498      */
499     @Override
500     public RemoteRepository getRemoteRepository( String repoId ) {
501         rwLock.readLock().lock();
502         try {
503             return remoteRepositories.get(repoId);
504         } finally {
505             rwLock.readLock().unlock();
506         }
507     }
508
509     @Override
510     public RepositoryGroup getRepositoryGroup( String groupId ) {
511         rwLock.readLock().lock();
512         try {
513             return repositoryGroups.get(groupId);
514         } finally {
515             rwLock.readLock().unlock();
516         }
517     }
518
519     /*
520      * The <code>ignoreConfigEvents</code> works only for synchronized configuration events.
521      * If the configuration throws async events, we cannot know, if the event is caused by this instance or another thread.
522      */
523     private void saveConfiguration(Configuration configuration) throws IndeterminateConfigurationException, RegistryException {
524         ignoreConfigEvents = true;
525         try {
526             getArchivaConfiguration().save(configuration);
527         } finally {
528             ignoreConfigEvents = false;
529         }
530     }
531
532     /**
533      * Adds a new repository to the current list, or replaces the repository definition with
534      * the same id, if it exists already.
535      * The change is saved to the configuration immediately.
536      *
537      * @param managedRepository the new repository.
538      * @throws RepositoryException if the new repository could not be saved to the configuration.
539      */
540     @Override
541     public ManagedRepository putRepository( ManagedRepository managedRepository ) throws RepositoryException {
542         rwLock.writeLock().lock();
543         try {
544             final String id = managedRepository.getId();
545             if (remoteRepositories.containsKey(id)) {
546                 throw new RepositoryException("There exists a remote repository with id " + id + ". Could not update with managed repository.");
547             }
548             ManagedRepository originRepo = managedRepositories.put(id, managedRepository);
549             try {
550                 if (originRepo != null && originRepo != managedRepository) {
551                     originRepo.close();
552                 }
553                 RepositoryProvider provider = getProvider(managedRepository.getType());
554                 ManagedRepositoryConfiguration newCfg = provider.getManagedConfiguration(managedRepository);
555                 Configuration configuration = getArchivaConfiguration().getConfiguration();
556                 updateRepositoryReferences(provider, managedRepository, newCfg, configuration);
557                 ManagedRepositoryConfiguration oldCfg = configuration.findManagedRepositoryById(id);
558                 if (oldCfg != null) {
559                     configuration.removeManagedRepository(oldCfg);
560                 }
561                 configuration.addManagedRepository(newCfg);
562                 saveConfiguration(configuration);
563                 if (originRepo != managedRepository) {
564                     pushEvent(new LifecycleEvent(LifecycleEvent.REGISTERED, this, managedRepository));
565                 } else {
566                     pushEvent(new LifecycleEvent(LifecycleEvent.UPDATED, this, managedRepository));
567                 }
568                 return managedRepository;
569             } catch (Exception e) {
570                 // Rollback only partly, because repository is closed already
571                 if (originRepo != null) {
572                     managedRepositories.put(id, originRepo);
573                 } else {
574                     managedRepositories.remove(id);
575                 }
576                 log.error("Exception during configuration update {}", e.getMessage(), e);
577                 throw new RepositoryException("Could not save the configuration" + (e.getMessage() == null ? "" : ": " + e.getMessage()));
578             }
579         } finally {
580             rwLock.writeLock().unlock();
581         }
582     }
583
584     /**
585      * Adds a new repository or updates the repository with the same id, if it exists already.
586      * The configuration is saved immediately.
587      *
588      * @param managedRepositoryConfiguration the repository configuration
589      * @return the updated or created repository
590      * @throws RepositoryException if an error occurs, or the configuration is not valid.
591      */
592     @Override
593     public ManagedRepository putRepository( ManagedRepositoryConfiguration managedRepositoryConfiguration ) throws RepositoryException {
594         rwLock.writeLock().lock();
595         try {
596             final String id = managedRepositoryConfiguration.getId();
597             final RepositoryType repositoryType = RepositoryType.valueOf(managedRepositoryConfiguration.getType());
598             Configuration configuration = getArchivaConfiguration().getConfiguration();
599             ManagedRepository repo = managedRepositories.get(id);
600             ManagedRepositoryConfiguration oldCfg = repo != null ? getProvider(repositoryType).getManagedConfiguration(repo) : null;
601             repo = putRepository(managedRepositoryConfiguration, configuration);
602             try {
603                 saveConfiguration(configuration);
604             } catch (IndeterminateConfigurationException | RegistryException e) {
605                 if (oldCfg != null) {
606                     getProvider(repositoryType).updateManagedInstance((EditableManagedRepository) repo, oldCfg);
607                 }
608                 log.error("Could not save the configuration for repository {}: {}", id, e.getMessage(), e);
609                 throw new RepositoryException("Could not save the configuration for repository " + id + ": " + e.getMessage());
610             }
611             return repo;
612         } finally {
613             rwLock.writeLock().unlock();
614         }
615
616     }
617
618     /**
619      * Adds a new repository or updates the repository with the same id. The given configuration object is updated, but
620      * the configuration is not saved.
621      *
622      * @param managedRepositoryConfiguration the new or changed managed repository configuration
623      * @param configuration                  the configuration object (may be <code>null</code>)
624      * @return the new or updated repository
625      * @throws RepositoryException if the configuration cannot be saved or updated
626      */
627     @Override
628     public ManagedRepository putRepository( ManagedRepositoryConfiguration managedRepositoryConfiguration, Configuration configuration ) throws RepositoryException {
629         rwLock.writeLock().lock();
630         try {
631             final String id = managedRepositoryConfiguration.getId();
632             final RepositoryType repoType = RepositoryType.valueOf(managedRepositoryConfiguration.getType());
633             ManagedRepository repo;
634             boolean registeredNew = false;
635             repo = managedRepositories.get(id);
636             if (repo != null && repo.isOpen()) {
637                 if (repo instanceof EditableManagedRepository) {
638                     getProvider(repoType).updateManagedInstance((EditableManagedRepository) repo, managedRepositoryConfiguration);
639                 } else {
640                     throw new RepositoryException("The repository is not editable " + id);
641                 }
642             } else {
643                 repo = getProvider(repoType).createManagedInstance(managedRepositoryConfiguration);
644                 managedRepositories.put(id, repo);
645                 registeredNew = true;
646             }
647             updateRepositoryReferences(getProvider(repoType), repo, managedRepositoryConfiguration, configuration);
648             replaceOrAddRepositoryConfig(managedRepositoryConfiguration, configuration);
649             if (registeredNew) {
650                 pushEvent(new LifecycleEvent(LifecycleEvent.REGISTERED, this, repo));
651             } else {
652                 pushEvent(new LifecycleEvent(LifecycleEvent.UPDATED, this, repo));
653             }
654             return repo;
655         } finally {
656             rwLock.writeLock().unlock();
657         }
658     }
659
660
661     /**
662      * Adds a new repository group to the current list, or replaces the repository group definition with
663      * the same id, if it exists already.
664      * The change is saved to the configuration immediately.
665      *
666      * @param repositoryGroup the new repository group.
667      * @throws RepositoryException if the new repository group could not be saved to the configuration.
668      */
669     @Override
670     public RepositoryGroup putRepositoryGroup( RepositoryGroup repositoryGroup ) throws RepositoryException {
671         rwLock.writeLock().lock();
672         try {
673             final String id = repositoryGroup.getId();
674             RepositoryGroup originRepoGroup = repositoryGroups.put(id, repositoryGroup);
675             try {
676                 if (originRepoGroup != null && originRepoGroup != repositoryGroup) {
677                     originRepoGroup.close();
678                 }
679                 RepositoryProvider provider = getProvider(repositoryGroup.getType());
680                 RepositoryGroupConfiguration newCfg = provider.getRepositoryGroupConfiguration(repositoryGroup);
681                 Configuration configuration = getArchivaConfiguration().getConfiguration();
682                 updateRepositoryReferences(provider, repositoryGroup, newCfg);
683                 RepositoryGroupConfiguration oldCfg = configuration.findRepositoryGroupById(id);
684                 if (oldCfg != null) {
685                     configuration.removeRepositoryGroup(oldCfg);
686                 }
687                 configuration.addRepositoryGroup(newCfg);
688                 saveConfiguration(configuration);
689                 return repositoryGroup;
690             } catch (Exception e) {
691                 // Rollback
692                 if (originRepoGroup != null) {
693                     repositoryGroups.put(id, originRepoGroup);
694                 } else {
695                     repositoryGroups.remove(id);
696                 }
697                 log.error("Exception during configuration update {}", e.getMessage(), e);
698                 throw new RepositoryException("Could not save the configuration" + (e.getMessage() == null ? "" : ": " + e.getMessage()));
699             }
700         } finally {
701             rwLock.writeLock().unlock();
702         }
703     }
704
705     /**
706      * Adds a new repository group or updates the repository with the same id, if it exists already.
707      * The configuration is saved immediately.
708      *
709      * @param repositoryGroupConfiguration the repository configuration
710      * @return the updated or created repository
711      * @throws RepositoryException if an error occurs, or the configuration is not valid.
712      */
713     @Override
714     public RepositoryGroup putRepositoryGroup( RepositoryGroupConfiguration repositoryGroupConfiguration ) throws RepositoryException {
715         rwLock.writeLock().lock();
716         try {
717             final String id = repositoryGroupConfiguration.getId();
718             final RepositoryType repositoryType = RepositoryType.valueOf(repositoryGroupConfiguration.getType());
719             Configuration configuration = getArchivaConfiguration().getConfiguration();
720             RepositoryGroup repo = repositoryGroups.get(id);
721             RepositoryGroupConfiguration oldCfg = repo != null ? getProvider(repositoryType).getRepositoryGroupConfiguration(repo) : null;
722             repo = putRepositoryGroup(repositoryGroupConfiguration, configuration);
723             try {
724                 saveConfiguration(configuration);
725             } catch (IndeterminateConfigurationException | RegistryException e) {
726                 if (oldCfg != null) {
727                     getProvider(repositoryType).updateRepositoryGroupInstance((EditableRepositoryGroup) repo, oldCfg);
728                 }
729                 log.error("Could not save the configuration for repository group {}: {}", id, e.getMessage(), e);
730                 throw new RepositoryException("Could not save the configuration for repository group " + id + ": " + e.getMessage());
731             }
732             return repo;
733         } finally {
734             rwLock.writeLock().unlock();
735         }
736
737     }
738
739     /**
740      * Adds a new repository group or updates the repository group with the same id. The given configuration object is updated, but
741      * the configuration is not saved.
742      *
743      * @param repositoryGroupConfiguration The configuration of the new or changed repository group.
744      * @param configuration                The configuration object. If it is <code>null</code>, the configuration is not saved.
745      * @return The new or updated repository group
746      * @throws RepositoryException if the configuration cannot be saved or updated
747      */
748     @Override
749     public RepositoryGroup putRepositoryGroup( RepositoryGroupConfiguration repositoryGroupConfiguration, Configuration configuration ) throws RepositoryException {
750         rwLock.writeLock().lock();
751         try {
752             final String id = repositoryGroupConfiguration.getId();
753             final RepositoryType repoType = RepositoryType.valueOf(repositoryGroupConfiguration.getType());
754             RepositoryGroup repo;
755             setRepositoryGroupDefaults(repositoryGroupConfiguration);
756             if (repositoryGroups.containsKey(id)) {
757                 repo = repositoryGroups.get(id);
758                 if (repo instanceof EditableRepositoryGroup) {
759                     getProvider(repoType).updateRepositoryGroupInstance((EditableRepositoryGroup) repo, repositoryGroupConfiguration);
760                 } else {
761                     throw new RepositoryException("The repository is not editable " + id);
762                 }
763             } else {
764                 repo = getProvider(repoType).createRepositoryGroup(repositoryGroupConfiguration);
765                 repositoryGroups.put(id, repo);
766             }
767             updateRepositoryReferences(getProvider(repoType), repo, repositoryGroupConfiguration);
768             replaceOrAddRepositoryConfig(repositoryGroupConfiguration, configuration);
769             return repo;
770         } finally {
771             rwLock.writeLock().unlock();
772         }
773     }
774
775     private void setRepositoryGroupDefaults(RepositoryGroupConfiguration repositoryGroupConfiguration) {
776         if (StringUtils.isEmpty(repositoryGroupConfiguration.getMergedIndexPath())) {
777             repositoryGroupConfiguration.setMergedIndexPath(DEFAULT_INDEX_PATH);
778         }
779         if (repositoryGroupConfiguration.getMergedIndexTtl() <= 0) {
780             repositoryGroupConfiguration.setMergedIndexTtl(300);
781         }
782         if (StringUtils.isEmpty(repositoryGroupConfiguration.getCronExpression())) {
783             repositoryGroupConfiguration.setCronExpression("0 0 03 ? * MON");
784         }
785     }
786
787     private void replaceOrAddRepositoryConfig(ManagedRepositoryConfiguration managedRepositoryConfiguration, Configuration configuration) {
788         if (configuration != null) {
789             ManagedRepositoryConfiguration oldCfg = configuration.findManagedRepositoryById(managedRepositoryConfiguration.getId());
790             if (oldCfg != null) {
791                 configuration.removeManagedRepository(oldCfg);
792             }
793             configuration.addManagedRepository(managedRepositoryConfiguration);
794         }
795     }
796
797     private void replaceOrAddRepositoryConfig(RemoteRepositoryConfiguration remoteRepositoryConfiguration, Configuration configuration) {
798         if (configuration != null) {
799             RemoteRepositoryConfiguration oldCfg = configuration.findRemoteRepositoryById(remoteRepositoryConfiguration.getId());
800             if (oldCfg != null) {
801                 configuration.removeRemoteRepository(oldCfg);
802             }
803             configuration.addRemoteRepository(remoteRepositoryConfiguration);
804         }
805     }
806
807     private void replaceOrAddRepositoryConfig(RepositoryGroupConfiguration repositoryGroupConfiguration, Configuration configuration) {
808         RepositoryGroupConfiguration oldCfg = configuration.findRepositoryGroupById(repositoryGroupConfiguration.getId());
809         if (oldCfg != null) {
810             configuration.removeRepositoryGroup(oldCfg);
811         }
812         configuration.addRepositoryGroup(repositoryGroupConfiguration);
813     }
814
815     @Override
816     public RemoteRepository putRepository( RemoteRepository remoteRepository, Configuration configuration ) throws RepositoryException {
817         rwLock.writeLock().lock();
818         try {
819             final String id = remoteRepository.getId();
820             if (managedRepositories.containsKey(id)) {
821                 throw new RepositoryException("There exists a managed repository with id " + id + ". Could not update with remote repository.");
822             }
823             RemoteRepository originRepo = remoteRepositories.put(id, remoteRepository);
824             RemoteRepositoryConfiguration oldCfg = null;
825             RemoteRepositoryConfiguration newCfg;
826             try {
827                 if (originRepo != null && originRepo != remoteRepository) {
828                     originRepo.close();
829                 }
830                 final RepositoryProvider provider = getProvider(remoteRepository.getType());
831                 newCfg = provider.getRemoteConfiguration(remoteRepository);
832                 updateRepositoryReferences(provider, remoteRepository, newCfg, configuration);
833                 oldCfg = configuration.findRemoteRepositoryById(id);
834                 if (oldCfg != null) {
835                     configuration.removeRemoteRepository(oldCfg);
836                 }
837                 configuration.addRemoteRepository(newCfg);
838                 if (remoteRepository != originRepo) {
839                     pushEvent(new LifecycleEvent(LifecycleEvent.REGISTERED, this, remoteRepository));
840                 } else {
841                     pushEvent(new LifecycleEvent(LifecycleEvent.UPDATED, this, remoteRepository));
842                 }
843                 return remoteRepository;
844             } catch (Exception e) {
845                 // Rollback
846                 if (originRepo != null) {
847                     remoteRepositories.put(id, originRepo);
848                 } else {
849                     remoteRepositories.remove(id);
850                 }
851                 if (oldCfg != null) {
852                     RemoteRepositoryConfiguration cfg = configuration.findRemoteRepositoryById(id);
853                     if (cfg != null) {
854                         configuration.removeRemoteRepository(cfg);
855                         configuration.addRemoteRepository(oldCfg);
856                     }
857                 }
858                 log.error("Error while adding remote repository {}", e.getMessage(), e);
859                 throw new RepositoryException("Could not save the configuration" + (e.getMessage() == null ? "" : ": " + e.getMessage()));
860             }
861         } finally {
862             rwLock.writeLock().unlock();
863         }
864     }
865
866     /**
867      * Adds a remote repository, or overwrites the repository definition with the same id, if it exists already.
868      * The modification is saved to the configuration immediately.
869      *
870      * @param remoteRepository the remote repository to add
871      * @throws RepositoryException if an error occurs during configuration save
872      */
873     @Override
874     public RemoteRepository putRepository( RemoteRepository remoteRepository ) throws RepositoryException {
875         rwLock.writeLock().lock();
876         try {
877             Configuration configuration = getArchivaConfiguration().getConfiguration();
878             try {
879                 RemoteRepository repo = putRepository(remoteRepository, configuration);
880                 saveConfiguration(configuration);
881                 return repo;
882             } catch (RegistryException | IndeterminateConfigurationException e) {
883                 log.error("Error while saving remote repository {}", e.getMessage(), e);
884                 throw new RepositoryException("Could not save the configuration" + (e.getMessage() == null ? "" : ": " + e.getMessage()));
885             }
886         } finally {
887             rwLock.writeLock().unlock();
888         }
889     }
890
891     /**
892      * Adds a new repository or updates the repository with the same id, if it exists already.
893      * The configuration is saved immediately.
894      *
895      * @param remoteRepositoryConfiguration the repository configuration
896      * @return the updated or created repository
897      * @throws RepositoryException if an error occurs, or the configuration is not valid.
898      */
899     @Override
900     public RemoteRepository putRepository( RemoteRepositoryConfiguration remoteRepositoryConfiguration ) throws RepositoryException {
901         rwLock.writeLock().lock();
902         try {
903             final String id = remoteRepositoryConfiguration.getId();
904             final RepositoryType repositoryType = RepositoryType.valueOf(remoteRepositoryConfiguration.getType());
905             Configuration configuration = getArchivaConfiguration().getConfiguration();
906             RemoteRepository repo = remoteRepositories.get(id);
907             RemoteRepositoryConfiguration oldCfg = repo != null ? getProvider(repositoryType).getRemoteConfiguration(repo) : null;
908             repo = putRepository(remoteRepositoryConfiguration, configuration);
909             try {
910                 saveConfiguration(configuration);
911             } catch (IndeterminateConfigurationException | RegistryException e) {
912                 if (oldCfg != null) {
913                     getProvider(repositoryType).updateRemoteInstance((EditableRemoteRepository) repo, oldCfg);
914                 }
915                 log.error("Could not save the configuration for repository {}: {}", id, e.getMessage(), e);
916                 throw new RepositoryException("Could not save the configuration for repository " + id + ": " + e.getMessage());
917             }
918             return repo;
919         } finally {
920             rwLock.writeLock().unlock();
921         }
922
923     }
924
925     /**
926      * Adds a new repository or updates the repository with the same id. The given configuration object is updated, but
927      * the configuration is not saved.
928      *
929      * @param remoteRepositoryConfiguration the new or changed repository configuration
930      * @param configuration                 the configuration object
931      * @return the new or updated repository
932      * @throws RepositoryException if the configuration cannot be saved or updated
933      */
934     @Override
935     @SuppressWarnings("unchecked")
936     public RemoteRepository putRepository( RemoteRepositoryConfiguration remoteRepositoryConfiguration, Configuration configuration ) throws RepositoryException {
937         rwLock.writeLock().lock();
938         try {
939             final String id = remoteRepositoryConfiguration.getId();
940             final RepositoryType repoType = RepositoryType.valueOf(remoteRepositoryConfiguration.getType());
941             RemoteRepository repo;
942             boolean registeredNew = false;
943             repo = remoteRepositories.get(id);
944             if (repo != null && repo.isOpen()) {
945                 if (repo instanceof EditableRemoteRepository) {
946                     getProvider(repoType).updateRemoteInstance((EditableRemoteRepository) repo, remoteRepositoryConfiguration);
947                 } else {
948                     throw new RepositoryException("The repository is not editable " + id);
949                 }
950             } else {
951                 repo = getProvider(repoType).createRemoteInstance(remoteRepositoryConfiguration);
952                 remoteRepositories.put(id, repo);
953                 registeredNew = true;
954             }
955             updateRepositoryReferences(getProvider(repoType), repo, remoteRepositoryConfiguration, configuration);
956             replaceOrAddRepositoryConfig(remoteRepositoryConfiguration, configuration);
957             if (registeredNew) {
958                 pushEvent(new LifecycleEvent(LifecycleEvent.REGISTERED, this, repo));
959             } else {
960                 pushEvent(new LifecycleEvent(LifecycleEvent.UPDATED, this, repo));
961             }
962             return repo;
963         } finally {
964             rwLock.writeLock().unlock();
965         }
966
967
968     }
969
970     @Override
971     public void removeRepository( String repoId ) throws RepositoryException {
972         Repository repo = getRepository(repoId);
973         if (repo != null) {
974             removeRepository(repo);
975         }
976     }
977
978     @Override
979     public void removeRepository( Repository repo ) throws RepositoryException {
980         if (repo == null) {
981             log.warn("Trying to remove null repository");
982             return;
983         }
984         if (repo instanceof RemoteRepository) {
985             removeRepository((RemoteRepository) repo);
986         } else if (repo instanceof ManagedRepository) {
987             removeRepository((ManagedRepository) repo);
988         } else if (repo instanceof RepositoryGroup) {
989             removeRepositoryGroup((RepositoryGroup) repo);
990         } else {
991             throw new RepositoryException("Repository type not known: " + repo.getClass());
992         }
993     }
994
995     /**
996      * Removes a managed repository from the registry and configuration, if it exists.
997      * The change is saved to the configuration immediately.
998      *
999      * @param managedRepository the managed repository to remove
1000      * @throws RepositoryException if a error occurs during configuration save
1001      */
1002     @Override
1003     public void removeRepository( ManagedRepository managedRepository ) throws RepositoryException {
1004         if (managedRepository == null) {
1005             return;
1006         }
1007         final String id = managedRepository.getId();
1008         ManagedRepository repo = getManagedRepository(id);
1009         if (repo != null) {
1010             rwLock.writeLock().lock();
1011             try {
1012                 repo = managedRepositories.remove(id);
1013                 if (repo != null) {
1014                     repo.close();
1015                     removeRepositoryFromGroups(repo);
1016                     Configuration configuration = getArchivaConfiguration().getConfiguration();
1017                     ManagedRepositoryConfiguration cfg = configuration.findManagedRepositoryById(id);
1018                     if (cfg != null) {
1019                         configuration.removeManagedRepository(cfg);
1020                     }
1021                     saveConfiguration(configuration);
1022                 }
1023                 pushEvent(new LifecycleEvent(LifecycleEvent.UNREGISTERED, this, repo));
1024             } catch (RegistryException | IndeterminateConfigurationException e) {
1025                 // Rollback
1026                 log.error("Could not save config after repository removal: {}", e.getMessage(), e);
1027                 managedRepositories.put(repo.getId(), repo);
1028                 throw new RepositoryException("Could not save configuration after repository removal: " + e.getMessage());
1029             } finally {
1030                 rwLock.writeLock().unlock();
1031             }
1032         }
1033     }
1034
1035     private void removeRepositoryFromGroups(ManagedRepository repo) {
1036         if (repo != null) {
1037             repositoryGroups.values().stream().filter(repoGroup -> repoGroup instanceof EditableRepository).
1038                     map(repoGroup -> (EditableRepositoryGroup) repoGroup).forEach(repoGroup -> repoGroup.removeRepository(repo));
1039         }
1040     }
1041
1042     @Override
1043     public void removeRepository( ManagedRepository managedRepository, Configuration configuration ) throws RepositoryException {
1044         if (managedRepository == null) {
1045             return;
1046         }
1047         final String id = managedRepository.getId();
1048         ManagedRepository repo = getManagedRepository(id);
1049         if (repo != null) {
1050             rwLock.writeLock().lock();
1051             try {
1052                 repo = managedRepositories.remove(id);
1053                 if (repo != null) {
1054                     repo.close();
1055                     removeRepositoryFromGroups(repo);
1056                     ManagedRepositoryConfiguration cfg = configuration.findManagedRepositoryById(id);
1057                     if (cfg != null) {
1058                         configuration.removeManagedRepository(cfg);
1059                     }
1060                 }
1061                 pushEvent(new LifecycleEvent(LifecycleEvent.UNREGISTERED, this, repo));
1062             } finally {
1063                 rwLock.writeLock().unlock();
1064             }
1065         }
1066
1067     }
1068
1069
1070     /**
1071      * Removes a repository group from the registry and configuration, if it exists.
1072      * The change is saved to the configuration immediately.
1073      *
1074      * @param repositoryGroup the repository group to remove
1075      * @throws RepositoryException if a error occurs during configuration save
1076      */
1077     @Override
1078     public void removeRepositoryGroup( RepositoryGroup repositoryGroup ) throws RepositoryException {
1079         if (repositoryGroup == null) {
1080             return;
1081         }
1082         final String id = repositoryGroup.getId();
1083         RepositoryGroup repo = getRepositoryGroup(id);
1084         if (repo != null) {
1085             rwLock.writeLock().lock();
1086             try {
1087                 repo = repositoryGroups.remove(id);
1088                 if (repo != null) {
1089                     repo.close();
1090                     Configuration configuration = getArchivaConfiguration().getConfiguration();
1091                     RepositoryGroupConfiguration cfg = configuration.findRepositoryGroupById(id);
1092                     if (cfg != null) {
1093                         configuration.removeRepositoryGroup(cfg);
1094                     }
1095                     saveConfiguration(configuration);
1096                 }
1097
1098             } catch (RegistryException | IndeterminateConfigurationException e) {
1099                 // Rollback
1100                 log.error("Could not save config after repository removal: {}", e.getMessage(), e);
1101                 repositoryGroups.put(repo.getId(), repo);
1102                 throw new RepositoryException("Could not save configuration after repository removal: " + e.getMessage());
1103             } finally {
1104                 rwLock.writeLock().unlock();
1105             }
1106         }
1107     }
1108
1109     @Override
1110     public void removeRepositoryGroup( RepositoryGroup repositoryGroup, Configuration configuration ) throws RepositoryException {
1111         if (repositoryGroup == null) {
1112             return;
1113         }
1114         final String id = repositoryGroup.getId();
1115         RepositoryGroup repo = getRepositoryGroup(id);
1116         if (repo != null) {
1117             rwLock.writeLock().lock();
1118             try {
1119                 repo = repositoryGroups.remove(id);
1120                 if (repo != null) {
1121                     repo.close();
1122                     RepositoryGroupConfiguration cfg = configuration.findRepositoryGroupById(id);
1123                     if (cfg != null) {
1124                         configuration.removeRepositoryGroup(cfg);
1125                     }
1126                 }
1127             } finally {
1128                 rwLock.writeLock().unlock();
1129             }
1130         }
1131
1132     }
1133
1134     private void doRemoveRepo(RemoteRepository repo, Configuration configuration) {
1135         repo.close();
1136         RemoteRepositoryConfiguration cfg = configuration.findRemoteRepositoryById(repo.getId());
1137         if (cfg != null) {
1138             configuration.removeRemoteRepository(cfg);
1139         }
1140         List<ProxyConnectorConfiguration> proxyConnectors = new ArrayList<>(configuration.getProxyConnectors());
1141         for (ProxyConnectorConfiguration proxyConnector : proxyConnectors) {
1142             if (StringUtils.equals(proxyConnector.getTargetRepoId(), repo.getId())) {
1143                 configuration.removeProxyConnector(proxyConnector);
1144             }
1145         }
1146     }
1147
1148     /**
1149      * Removes the remote repository from the registry and configuration.
1150      * The change is saved to the configuration immediately.
1151      *
1152      * @param remoteRepository the remote repository to remove
1153      * @throws RepositoryException if a error occurs during configuration save
1154      */
1155     @Override
1156     public void removeRepository( RemoteRepository remoteRepository ) throws RepositoryException {
1157         if (remoteRepository == null) {
1158             return;
1159         }
1160         final String id = remoteRepository.getId();
1161         RemoteRepository repo = getRemoteRepository(id);
1162         if (repo != null) {
1163             rwLock.writeLock().lock();
1164             try {
1165                 repo = remoteRepositories.remove(id);
1166                 if (repo != null) {
1167                     Configuration configuration = getArchivaConfiguration().getConfiguration();
1168                     doRemoveRepo(repo, configuration);
1169                     saveConfiguration(configuration);
1170                 }
1171                 pushEvent(new LifecycleEvent(LifecycleEvent.UNREGISTERED, this, repo));
1172             } catch (RegistryException | IndeterminateConfigurationException e) {
1173                 // Rollback
1174                 log.error("Could not save config after repository removal: {}", e.getMessage(), e);
1175                 remoteRepositories.put(repo.getId(), repo);
1176                 throw new RepositoryException("Could not save configuration after repository removal: " + e.getMessage());
1177             } finally {
1178                 rwLock.writeLock().unlock();
1179             }
1180         }
1181     }
1182
1183     @Override
1184     public void removeRepository( RemoteRepository remoteRepository, Configuration configuration ) throws RepositoryException {
1185         if (remoteRepository == null) {
1186             return;
1187         }
1188         final String id = remoteRepository.getId();
1189         RemoteRepository repo = getRemoteRepository(id);
1190         if (repo != null) {
1191             rwLock.writeLock().lock();
1192             try {
1193                 repo = remoteRepositories.remove(id);
1194                 if (repo != null) {
1195                     doRemoveRepo(repo, configuration);
1196                 }
1197                 pushEvent(new LifecycleEvent(LifecycleEvent.UNREGISTERED, this, repo));
1198             } finally {
1199                 rwLock.writeLock().unlock();
1200             }
1201         }
1202
1203     }
1204
1205     /**
1206      * Reloads the registry from the configuration.
1207      */
1208     @Override
1209     public void reload( ) {
1210         initialize();
1211     }
1212
1213     /**
1214      * Resets the indexing context of a given repository.
1215      *
1216      * @param repository The repository
1217      * @throws IndexUpdateFailedException If the index could not be resetted.
1218      */
1219     @Override
1220     public void resetIndexingContext( Repository repository ) throws IndexUpdateFailedException {
1221         if (repository.hasIndex() && repository instanceof EditableRepository) {
1222             EditableRepository eRepo = (EditableRepository) repository;
1223             ArchivaIndexingContext newCtx = getIndexManager(repository.getType()).reset(repository.getIndexingContext());
1224             eRepo.setIndexingContext(newCtx);
1225         }
1226     }
1227
1228
1229     /**
1230      * Creates a new repository instance with the same settings as this one. The cloned repository is not
1231      * registered or saved to the configuration.
1232      *
1233      * @param repo The origin repository
1234      * @return The cloned repository.
1235      */
1236     @Override
1237     public ManagedRepository clone( ManagedRepository repo, String newId ) throws RepositoryException {
1238         if (managedRepositories.containsKey(newId) || remoteRepositories.containsKey(newId)) {
1239             throw new RepositoryException("The given id exists already " + newId);
1240         }
1241         RepositoryProvider provider = getProvider(repo.getType());
1242         ManagedRepositoryConfiguration cfg = provider.getManagedConfiguration(repo);
1243         cfg.setId(newId);
1244         ManagedRepository cloned = provider.createManagedInstance(cfg);
1245         cloned.registerEventHandler(RepositoryEvent.ANY, this);
1246         return cloned;
1247     }
1248
1249     @Override
1250     public <T extends Repository> Repository clone( T repo, String newId ) throws RepositoryException {
1251         if (repo instanceof RemoteRepository) {
1252             return this.clone((RemoteRepository) repo, newId);
1253         } else if (repo instanceof ManagedRepository) {
1254             return this.clone((ManagedRepository) repo, newId);
1255         } else {
1256             throw new RepositoryException("This repository class is not supported " + repo.getClass().getName());
1257         }
1258     }
1259
1260     /**
1261      * Creates a new repository instance with the same settings as this one. The cloned repository is not
1262      * registered or saved to the configuration.
1263      *
1264      * @param repo The origin repository
1265      * @return The cloned repository.
1266      */
1267     @Override
1268     public RemoteRepository clone( RemoteRepository repo, String newId ) throws RepositoryException {
1269         if (managedRepositories.containsKey(newId) || remoteRepositories.containsKey(newId)) {
1270             throw new RepositoryException("The given id exists already " + newId);
1271         }
1272         RepositoryProvider provider = getProvider(repo.getType());
1273         RemoteRepositoryConfiguration cfg = provider.getRemoteConfiguration(repo);
1274         cfg.setId(newId);
1275         RemoteRepository cloned = provider.createRemoteInstance(cfg);
1276         cloned.registerEventHandler(RepositoryEvent.ANY, this);
1277         return cloned;
1278     }
1279
1280     @Override
1281     public Repository getRepositoryOfAsset( StorageAsset asset )
1282     {
1283         if (asset instanceof Repository) {
1284             return (Repository)asset;
1285         } else
1286         {
1287             return getRepositories( ).stream( ).filter( r -> r.getRoot()
1288                 .getStorage( ).equals( asset.getStorage( ) ) ).findFirst( ).orElse( null );
1289         }
1290     }
1291
1292
1293     @Override
1294     public void configurationEvent(ConfigurationEvent event) {
1295         // Note: the ignoreConfigEvents flag does not work, if the config events are asynchronous.
1296         if (!ignoreConfigEvents) {
1297             reload();
1298         }
1299     }
1300
1301
1302     @Override
1303     public <T extends Event> void registerEventHandler( EventType<T> type, EventHandler<? super T> eventHandler) {
1304         eventManager.registerEventHandler(type, eventHandler);
1305     }
1306
1307
1308     @Override
1309     public <T extends Event> void unregisterEventHandler(EventType<T> type, EventHandler<? super T> eventHandler) {
1310         eventManager.unregisterEventHandler(type, eventHandler);
1311     }
1312
1313
1314     @Override
1315     public void handle(Event event) {
1316         // To avoid event cycles:
1317         if (sameOriginator(event)) {
1318             return;
1319         }
1320         if (event instanceof RepositoryIndexEvent) {
1321             handleIndexCreationEvent((RepositoryIndexEvent) event);
1322         }
1323         // We propagate all events to our listeners, but with context of repository registry
1324         pushEvent(event);
1325     }
1326
1327     private void handleIndexCreationEvent(RepositoryIndexEvent event) {
1328         RepositoryIndexEvent idxEvent = event;
1329         if (managedRepositories.containsKey(idxEvent.getRepository().getId()) ||
1330                 remoteRepositories.containsKey(idxEvent.getRepository().getId())) {
1331             EditableRepository repo = (EditableRepository) idxEvent.getRepository();
1332             if (repo != null && repo.getIndexingContext() != null) {
1333                 try {
1334                     ArchivaIndexManager idxmgr = getIndexManager(repo.getType());
1335                     if (idxmgr != null) {
1336                         ArchivaIndexingContext newCtx = idxmgr.move(repo.getIndexingContext(), repo);
1337                         repo.setIndexingContext(newCtx);
1338                         idxmgr.updateLocalIndexPath(repo);
1339                     }
1340
1341                 } catch (IndexCreationFailedException e) {
1342                     log.error("Could not move index to new directory {}", e.getMessage(), e);
1343                 }
1344             }
1345         }
1346     }
1347
1348     private boolean sameOriginator(Event event) {
1349         if (event.getSource() == this) {
1350             return true;
1351         } else if (event.hasPreviousEvent()) {
1352             return sameOriginator(event.getPreviousEvent());
1353         } else {
1354             return false;
1355         }
1356     }
1357
1358     private void pushEvent(Event event) {
1359         eventManager.fireEvent(event);
1360     }
1361
1362
1363
1364 }