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