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