1 package org.apache.archiva.repository;
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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
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.features.IndexCreationFeature;
27 import org.apache.archiva.repository.features.StagingRepositoryFeature;
28 import org.apache.commons.lang3.StringUtils;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31 import org.springframework.stereotype.Service;
33 import javax.annotation.PostConstruct;
34 import javax.annotation.PreDestroy;
35 import javax.inject.Inject;
36 import javax.inject.Named;
38 import java.util.concurrent.locks.ReentrantReadWriteLock;
39 import java.util.stream.Collectors;
40 import java.util.stream.Stream;
42 import static org.apache.archiva.indexer.ArchivaIndexManager.DEFAULT_INDEX_PATH;
45 * Registry for repositories. This is the central entry point for repositories. It provides methods for
46 * retrieving, adding and removing repositories.
48 * The modification methods addXX and removeXX persist the changes immediately to the configuration. If the
49 * configuration save fails the changes are rolled back.
55 @Service("repositoryRegistry")
56 public class RepositoryRegistry implements ConfigurationListener, RepositoryEventHandler, RepositoryEventListener {
58 private static final Logger log = LoggerFactory.getLogger(RepositoryRegistry.class);
61 * We inject all repository providers
64 List<RepositoryProvider> repositoryProviders;
67 IndexManagerFactory indexManagerFactory;
70 ArchivaConfiguration archivaConfiguration;
73 @Named("repositoryContentFactory#default")
74 RepositoryContentFactory repositoryContentFactory;
76 private List<RepositoryEventListener> listeners = new ArrayList<>();
77 private Map<EventType, List<RepositoryEventListener>> typeListenerMap = new HashMap<>();
80 private Map<String, ManagedRepository> managedRepositories = new HashMap<>();
81 private Map<String, ManagedRepository> uManagedRepository = Collections.unmodifiableMap(managedRepositories);
83 private Map<String, RemoteRepository> remoteRepositories = new HashMap<>();
84 private Map<String, RemoteRepository> uRemoteRepositories = Collections.unmodifiableMap(remoteRepositories);
86 private Map<String, RepositoryGroup> repositoryGroups = new HashMap<>();
87 private Map<String, RepositoryGroup> uRepositoryGroups = Collections.unmodifiableMap(repositoryGroups);
89 private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
91 private volatile boolean ignoreConfigEvents = false;
93 public void setArchivaConfiguration(ArchivaConfiguration archivaConfiguration) {
94 this.archivaConfiguration = archivaConfiguration;
98 private void initialize() {
99 rwLock.writeLock().lock();
101 log.debug("Initializing repository registry");
102 updateManagedRepositoriesFromConfig();
103 updateRemoteRepositoriesFromConfig();
105 repositoryGroups.clear();
106 Map<String, RepositoryGroup> repositoryGroups = getRepositorGroupsFromConfig();
107 this.repositoryGroups.putAll(repositoryGroups);
109 // archivaConfiguration.addChangeListener(this);
110 archivaConfiguration.addListener(this);
112 rwLock.writeLock().unlock();
114 pushEvent(new RepositoryRegistryEvent<>(RepositoryRegistryEvent.RegistryEventType.RELOADED, this));
118 public void destroy() {
119 for (ManagedRepository rep : managedRepositories.values()) {
122 managedRepositories.clear();
123 for (RemoteRepository repo : remoteRepositories.values()) {
126 remoteRepositories.clear();
127 pushEvent(new RepositoryRegistryEvent<>(RepositoryRegistryEvent.RegistryEventType.DESTROYED, this));
131 private Map<RepositoryType, RepositoryProvider> createProviderMap() {
132 Map<RepositoryType, RepositoryProvider> map = new HashMap<>();
133 if (repositoryProviders != null) {
134 for (RepositoryProvider provider : repositoryProviders) {
135 for (RepositoryType type : provider.provides()) {
136 map.put(type, provider);
143 private RepositoryProvider getProvider(RepositoryType type) throws RepositoryException {
144 return repositoryProviders.stream().filter(repositoryProvider -> repositoryProvider.provides().contains(type)).findFirst().orElseThrow(() -> new RepositoryException("Repository type cannot be handled: " + type));
148 * Updates the repositories
150 private void updateManagedRepositoriesFromConfig() {
153 Set<String> configRepoIds = new HashSet<>();
154 List<ManagedRepositoryConfiguration> managedRepoConfigs =
155 getArchivaConfiguration().getConfiguration().getManagedRepositories();
157 if (managedRepoConfigs == null) {
161 for (ManagedRepositoryConfiguration repoConfig : managedRepoConfigs) {
162 ManagedRepository repo = putRepository(repoConfig, null);
163 configRepoIds.add(repoConfig.getId());
164 if (repo.supportsFeature(StagingRepositoryFeature.class)) {
165 StagingRepositoryFeature stagF = repo.getFeature(StagingRepositoryFeature.class).get();
166 if (stagF.getStagingRepository() != null) {
167 configRepoIds.add(stagF.getStagingRepository().getId());
171 List<String> toRemove = managedRepositories.keySet().stream().filter(id -> !configRepoIds.contains(id)).collect(Collectors.toList());
172 for (String id : toRemove) {
173 ManagedRepository removed = managedRepositories.remove(id);
176 } catch (Throwable e) {
177 log.error("Could not initialize repositories from config: {}", e.getMessage(), e);
182 private ManagedRepository createNewManagedRepository(RepositoryProvider provider, ManagedRepositoryConfiguration cfg) throws RepositoryException {
183 log.debug("Creating repo {}", cfg.getId());
184 ManagedRepository repo = provider.createManagedInstance(cfg);
186 updateRepositoryReferences(provider, repo, cfg, null);
191 private String getStagingId(String repoId) {
192 return repoId + StagingRepositoryFeature.STAGING_REPO_POSTFIX;
195 @SuppressWarnings("unchecked")
196 private void updateRepositoryReferences(RepositoryProvider provider, ManagedRepository repo, ManagedRepositoryConfiguration cfg, Configuration configuration) throws RepositoryException {
197 log.debug("Updating references of repo {}", repo.getId());
198 if (repo.supportsFeature(StagingRepositoryFeature.class)) {
199 StagingRepositoryFeature feature = repo.getFeature(StagingRepositoryFeature.class).get();
200 if (feature.isStageRepoNeeded() && feature.getStagingRepository() == null) {
201 ManagedRepository stageRepo = getManagedRepository(getStagingId(repo.getId()));
202 if (stageRepo == null) {
203 stageRepo = getStagingRepository(provider, cfg, configuration);
204 managedRepositories.put(stageRepo.getId(), stageRepo);
205 if (configuration != null) {
206 replaceOrAddRepositoryConfig(provider.getManagedConfiguration(stageRepo), configuration);
208 pushEvent(new LifecycleEvent(LifecycleEvent.LifecycleEventType.REGISTERED, this, stageRepo));
210 feature.setStagingRepository(stageRepo);
213 if (repo instanceof EditableManagedRepository) {
214 EditableManagedRepository editableRepo = (EditableManagedRepository) repo;
215 if (repo.getContent() == null) {
216 editableRepo.setContent(repositoryContentFactory.getManagedRepositoryContent(repo));
217 editableRepo.getContent().setRepository(editableRepo);
219 log.debug("Index repo: " + repo.hasIndex());
220 if (repo.hasIndex() && ( repo.getIndexingContext() == null || !repo.getIndexingContext().isOpen() )) {
221 log.debug("Creating indexing context for {}", repo.getId());
222 createIndexingContext(editableRepo);
228 public ArchivaIndexManager getIndexManager(RepositoryType type) {
229 return indexManagerFactory.getIndexManager(type);
232 private void createIndexingContext(EditableRepository editableRepo) throws RepositoryException {
233 if (editableRepo.supportsFeature(IndexCreationFeature.class)) {
234 ArchivaIndexManager idxManager = getIndexManager(editableRepo.getType());
236 editableRepo.setIndexingContext(idxManager.createContext(editableRepo));
237 idxManager.updateLocalIndexPath(editableRepo);
238 } catch (IndexCreationFailedException e) {
239 throw new RepositoryException("Could not create index for repository " + editableRepo.getId() + ": " + e.getMessage(), e);
244 private ManagedRepository getStagingRepository(RepositoryProvider provider, ManagedRepositoryConfiguration baseRepoCfg, Configuration configuration) throws RepositoryException {
245 ManagedRepository stageRepo = getManagedRepository(getStagingId(baseRepoCfg.getId()));
246 if (stageRepo == null) {
247 stageRepo = provider.createStagingInstance(baseRepoCfg);
248 if (stageRepo.supportsFeature(StagingRepositoryFeature.class)) {
249 stageRepo.getFeature(StagingRepositoryFeature.class).get().setStageRepoNeeded(false);
251 ManagedRepositoryConfiguration stageCfg = provider.getManagedConfiguration(stageRepo);
252 updateRepositoryReferences(provider, stageRepo, stageCfg, configuration);
258 private void updateRemoteRepositoriesFromConfig() {
260 List<RemoteRepositoryConfiguration> remoteRepoConfigs =
261 getArchivaConfiguration().getConfiguration().getRemoteRepositories();
263 if (remoteRepoConfigs == null) {
266 Set<String> repoIds = new HashSet<>();
267 for (RemoteRepositoryConfiguration repoConfig : remoteRepoConfigs) {
268 putRepository(repoConfig, null);
269 repoIds.add(repoConfig.getId());
272 List<String> toRemove = remoteRepositories.keySet().stream().filter(id -> !repoIds.contains(id)).collect(Collectors.toList());
273 for (String id : toRemove) {
274 RemoteRepository removed = remoteRepositories.remove(id);
278 } catch (Throwable e) {
279 log.error("Could not initialize remote repositories from config: {}", e.getMessage(), e);
284 private RemoteRepository createNewRemoteRepository(RepositoryProvider provider, RemoteRepositoryConfiguration cfg) throws RepositoryException {
285 log.debug("Creating remote repo {}", cfg.getId());
286 RemoteRepository repo = provider.createRemoteInstance(cfg);
287 updateRepositoryReferences(provider, repo, cfg, null);
292 private void updateRepositoryReferences(RepositoryProvider provider, RemoteRepository repo, RemoteRepositoryConfiguration cfg, Configuration configuration) throws RepositoryException {
293 if (repo instanceof EditableRemoteRepository && repo.getContent() == null) {
294 EditableRemoteRepository editableRepo = (EditableRemoteRepository) repo;
295 editableRepo.setContent(repositoryContentFactory.getRemoteRepositoryContent(repo));
296 if (repo.supportsFeature(IndexCreationFeature.class) && repo.getIndexingContext() == null) {
297 createIndexingContext(editableRepo);
303 private Map<String, RepositoryGroup> getRepositorGroupsFromConfig() {
305 List<RepositoryGroupConfiguration> repositoryGroupConfigurations =
306 getArchivaConfiguration().getConfiguration().getRepositoryGroups();
308 if (repositoryGroupConfigurations == null) {
309 return Collections.emptyMap();
312 Map<String, RepositoryGroup> repositoryGroupMap = new LinkedHashMap<>(repositoryGroupConfigurations.size());
314 Map<RepositoryType, RepositoryProvider> providerMap = createProviderMap();
315 for (RepositoryGroupConfiguration repoConfig : repositoryGroupConfigurations) {
316 RepositoryType repositoryType = RepositoryType.valueOf(repoConfig.getType());
317 if (providerMap.containsKey(repositoryType)) {
319 RepositoryGroup repo = createNewRepositoryGroup(providerMap.get(repositoryType), repoConfig);
320 repositoryGroupMap.put(repo.getId(), repo);
321 } catch (Exception e) {
322 log.error("Could not create repository group {}: {}", repoConfig.getId(), e.getMessage(), e);
326 return repositoryGroupMap;
327 } catch (Throwable e) {
328 log.error("Could not initialize repositories from config: {}", e.getMessage(), e);
329 return Collections.emptyMap();
333 private RepositoryGroup createNewRepositoryGroup(RepositoryProvider provider, RepositoryGroupConfiguration config) throws RepositoryException {
334 RepositoryGroup repositoryGroup = provider.createRepositoryGroup(config);
335 repositoryGroup.register(this);
336 updateRepositoryReferences(provider, repositoryGroup, config);
337 return repositoryGroup;
340 private void updateRepositoryReferences(RepositoryProvider provider, RepositoryGroup group, RepositoryGroupConfiguration configuration) {
341 if (group instanceof EditableRepositoryGroup) {
342 EditableRepositoryGroup eGroup = (EditableRepositoryGroup) group;
343 eGroup.setRepositories(configuration.getRepositories().stream().map(r -> getManagedRepository(r)).collect(Collectors.toList()));
347 private ArchivaConfiguration getArchivaConfiguration() {
348 return this.archivaConfiguration;
352 * Returns all repositories that are registered. There is no defined order of the returned repositories.
354 * @return a list of managed and remote repositories
356 public Collection<Repository> getRepositories() {
357 rwLock.readLock().lock();
359 return Stream.concat(managedRepositories.values().stream(), remoteRepositories.values().stream()).collect(Collectors.toList());
361 rwLock.readLock().unlock();
366 * Returns only the managed repositories. There is no defined order of the returned repositories.
368 * @return a list of managed repositories
370 public Collection<ManagedRepository> getManagedRepositories() {
371 rwLock.readLock().lock();
373 return uManagedRepository.values();
375 rwLock.readLock().unlock();
380 * Returns only the remote repositories. There is no defined order of the returned repositories.
382 * @return a list of remote repositories
384 public Collection<RemoteRepository> getRemoteRepositories() {
385 rwLock.readLock().lock();
387 return uRemoteRepositories.values();
389 rwLock.readLock().unlock();
393 public Collection<RepositoryGroup> getRepositoryGroups() {
394 rwLock.readLock().lock();
396 return uRepositoryGroups.values();
398 rwLock.readLock().unlock();
403 * Returns the repository with the given id. The returned repository may be a managed or remote repository.
404 * It returns null, if no repository is registered with the given id.
406 * @param repoId the repository id
407 * @return the repository if found, otherwise null
409 public Repository getRepository(String repoId) {
410 rwLock.readLock().lock();
412 log.debug("getRepository {}", repoId);
413 if (managedRepositories.containsKey(repoId)) {
414 log.debug("Managed repo");
415 return managedRepositories.get(repoId);
416 } else if (remoteRepositories.containsKey(repoId)) {
417 log.debug("Remote repo");
418 return remoteRepositories.get(repoId);
419 } else if (repositoryGroups.containsKey(repoId)) {
420 return repositoryGroups.get(repoId);
425 rwLock.readLock().unlock();
430 * Convenience method, that returns the managed repository with the given id.
431 * It returns null, if no managed repository is registered with this id.
433 * @param repoId the repository id
434 * @return the managed repository if found, otherwise null
436 public ManagedRepository getManagedRepository(String repoId) {
437 rwLock.readLock().lock();
439 return managedRepositories.get(repoId);
441 rwLock.readLock().unlock();
446 * Convenience method, that returns the remote repository with the given id.
447 * It returns null, if no remote repository is registered with this id.
449 * @param repoId the repository id
450 * @return the remote repository if found, otherwise null
452 public RemoteRepository getRemoteRepository(String repoId) {
453 rwLock.readLock().lock();
455 return remoteRepositories.get(repoId);
457 rwLock.readLock().unlock();
461 public RepositoryGroup getRepositoryGroup(String groupId) {
462 rwLock.readLock().lock();
464 return repositoryGroups.get(groupId);
466 rwLock.readLock().unlock();
471 * The <code>ignoreConfigEvents</code> works only for synchronized configuration events.
472 * If the configuration throws async events, we cannot know, if the event is caused by this instance or another thread.
474 private void saveConfiguration(Configuration configuration) throws IndeterminateConfigurationException, RegistryException {
475 ignoreConfigEvents = true;
477 getArchivaConfiguration().save(configuration);
479 ignoreConfigEvents = false;
484 * Adds a new repository to the current list, or replaces the repository definition with
485 * the same id, if it exists already.
486 * The change is saved to the configuration immediately.
488 * @param managedRepository the new repository.
489 * @throws RepositoryException if the new repository could not be saved to the configuration.
491 public ManagedRepository putRepository(ManagedRepository managedRepository) throws RepositoryException {
492 rwLock.writeLock().lock();
494 final String id = managedRepository.getId();
495 if (remoteRepositories.containsKey(id)) {
496 throw new RepositoryException("There exists a remote repository with id " + id + ". Could not update with managed repository.");
498 ManagedRepository originRepo = managedRepositories.put(id, managedRepository);
500 if (originRepo != null && originRepo != managedRepository) {
503 RepositoryProvider provider = getProvider(managedRepository.getType());
504 ManagedRepositoryConfiguration newCfg = provider.getManagedConfiguration(managedRepository);
505 Configuration configuration = getArchivaConfiguration().getConfiguration();
506 updateRepositoryReferences(provider, managedRepository, newCfg, configuration);
507 ManagedRepositoryConfiguration oldCfg = configuration.findManagedRepositoryById(id);
508 if (oldCfg != null) {
509 configuration.removeManagedRepository(oldCfg);
511 configuration.addManagedRepository(newCfg);
512 saveConfiguration(configuration);
513 if (originRepo != managedRepository) {
514 pushEvent(new LifecycleEvent<>(LifecycleEvent.LifecycleEventType.REGISTERED, this, managedRepository));
516 pushEvent(new LifecycleEvent<>(LifecycleEvent.LifecycleEventType.UPDATED, this, managedRepository));
518 return managedRepository;
519 } catch (Exception e) {
520 // Rollback only partly, because repository is closed already
521 if (originRepo != null) {
522 managedRepositories.put(id, originRepo);
524 managedRepositories.remove(id);
526 log.error("Exception during configuration update {}", e.getMessage(), e);
527 throw new RepositoryException("Could not save the configuration" + (e.getMessage() == null ? "" : ": " + e.getMessage()));
530 rwLock.writeLock().unlock();
535 * Adds a new repository or updates the repository with the same id, if it exists already.
536 * The configuration is saved immediately.
538 * @param managedRepositoryConfiguration the repository configuration
539 * @return the updated or created repository
540 * @throws RepositoryException if an error occurs, or the configuration is not valid.
542 public ManagedRepository putRepository(ManagedRepositoryConfiguration managedRepositoryConfiguration) throws RepositoryException {
543 rwLock.writeLock().lock();
545 final String id = managedRepositoryConfiguration.getId();
546 final RepositoryType repositoryType = RepositoryType.valueOf(managedRepositoryConfiguration.getType());
547 Configuration configuration = getArchivaConfiguration().getConfiguration();
548 ManagedRepository repo = managedRepositories.get(id);
549 ManagedRepositoryConfiguration oldCfg = repo != null ? getProvider(repositoryType).getManagedConfiguration(repo) : null;
550 repo = putRepository(managedRepositoryConfiguration, configuration);
552 saveConfiguration(configuration);
553 } catch (IndeterminateConfigurationException | RegistryException e) {
554 if (oldCfg != null) {
555 getProvider(repositoryType).updateManagedInstance((EditableManagedRepository) repo, oldCfg);
557 log.error("Could not save the configuration for repository {}: {}", id, e.getMessage(), e);
558 throw new RepositoryException("Could not save the configuration for repository " + id + ": " + e.getMessage());
562 rwLock.writeLock().unlock();
568 * Adds a new repository or updates the repository with the same id. The given configuration object is updated, but
569 * the configuration is not saved.
571 * @param managedRepositoryConfiguration the new or changed managed repository configuration
572 * @param configuration the configuration object (may be <code>null</code>)
573 * @return the new or updated repository
574 * @throws RepositoryException if the configuration cannot be saved or updated
576 public ManagedRepository putRepository(ManagedRepositoryConfiguration managedRepositoryConfiguration, Configuration configuration) throws RepositoryException {
577 rwLock.writeLock().lock();
579 final String id = managedRepositoryConfiguration.getId();
580 final RepositoryType repoType = RepositoryType.valueOf(managedRepositoryConfiguration.getType());
581 ManagedRepository repo;
582 boolean registeredNew = false;
583 repo = managedRepositories.get(id);
584 if (repo != null && repo.isOpen()) {
585 if (repo instanceof EditableManagedRepository) {
586 getProvider(repoType).updateManagedInstance((EditableManagedRepository) repo, managedRepositoryConfiguration);
588 throw new RepositoryException("The repository is not editable " + id);
591 repo = getProvider(repoType).createManagedInstance(managedRepositoryConfiguration);
592 managedRepositories.put(id, repo);
593 registeredNew = true;
595 updateRepositoryReferences(getProvider(repoType), repo, managedRepositoryConfiguration, configuration);
596 replaceOrAddRepositoryConfig(managedRepositoryConfiguration, configuration);
598 pushEvent(new LifecycleEvent<>(LifecycleEvent.LifecycleEventType.REGISTERED, this, repo));
600 pushEvent(new LifecycleEvent<>(LifecycleEvent.LifecycleEventType.UPDATED, this, repo));
604 rwLock.writeLock().unlock();
610 * Adds a new repository group to the current list, or replaces the repository group definition with
611 * the same id, if it exists already.
612 * The change is saved to the configuration immediately.
614 * @param repositoryGroup the new repository group.
615 * @throws RepositoryException if the new repository group could not be saved to the configuration.
617 public RepositoryGroup putRepositoryGroup(RepositoryGroup repositoryGroup) throws RepositoryException {
618 rwLock.writeLock().lock();
620 final String id = repositoryGroup.getId();
621 RepositoryGroup originRepoGroup = repositoryGroups.put(id, repositoryGroup);
623 if (originRepoGroup != null && originRepoGroup != repositoryGroup) {
624 originRepoGroup.close();
626 RepositoryProvider provider = getProvider(repositoryGroup.getType());
627 RepositoryGroupConfiguration newCfg = provider.getRepositoryGroupConfiguration(repositoryGroup);
628 Configuration configuration = getArchivaConfiguration().getConfiguration();
629 updateRepositoryReferences(provider, repositoryGroup, newCfg);
630 RepositoryGroupConfiguration oldCfg = configuration.findRepositoryGroupById(id);
631 if (oldCfg != null) {
632 configuration.removeRepositoryGroup(oldCfg);
634 configuration.addRepositoryGroup(newCfg);
635 saveConfiguration(configuration);
636 return repositoryGroup;
637 } catch (Exception e) {
639 if (originRepoGroup != null) {
640 repositoryGroups.put(id, originRepoGroup);
642 repositoryGroups.remove(id);
644 log.error("Exception during configuration update {}", e.getMessage(), e);
645 throw new RepositoryException("Could not save the configuration" + (e.getMessage() == null ? "" : ": " + e.getMessage()));
648 rwLock.writeLock().unlock();
653 * Adds a new repository group or updates the repository with the same id, if it exists already.
654 * The configuration is saved immediately.
656 * @param repositoryGroupConfiguration the repository configuration
657 * @return the updated or created repository
658 * @throws RepositoryException if an error occurs, or the configuration is not valid.
660 public RepositoryGroup putRepositoryGroup(RepositoryGroupConfiguration repositoryGroupConfiguration) throws RepositoryException {
661 rwLock.writeLock().lock();
663 final String id = repositoryGroupConfiguration.getId();
664 final RepositoryType repositoryType = RepositoryType.valueOf(repositoryGroupConfiguration.getType());
665 Configuration configuration = getArchivaConfiguration().getConfiguration();
666 RepositoryGroup repo = repositoryGroups.get(id);
667 RepositoryGroupConfiguration oldCfg = repo != null ? getProvider(repositoryType).getRepositoryGroupConfiguration(repo) : null;
668 repo = putRepositoryGroup(repositoryGroupConfiguration, configuration);
670 saveConfiguration(configuration);
671 } catch (IndeterminateConfigurationException | RegistryException e) {
672 if (oldCfg != null) {
673 getProvider(repositoryType).updateRepositoryGroupInstance((EditableRepositoryGroup) repo, oldCfg);
675 log.error("Could not save the configuration for repository group {}: {}", id, e.getMessage(), e);
676 throw new RepositoryException("Could not save the configuration for repository group " + id + ": " + e.getMessage());
680 rwLock.writeLock().unlock();
686 * Adds a new repository group or updates the repository group with the same id. The given configuration object is updated, but
687 * the configuration is not saved.
689 * @param repositoryGroupConfiguration The configuration of the new or changed repository group.
690 * @param configuration The configuration object. If it is <code>null</code>, the configuration is not saved.
691 * @return The new or updated repository group
692 * @throws RepositoryException if the configuration cannot be saved or updated
694 public RepositoryGroup putRepositoryGroup(RepositoryGroupConfiguration repositoryGroupConfiguration, Configuration configuration) throws RepositoryException {
695 rwLock.writeLock().lock();
697 final String id = repositoryGroupConfiguration.getId();
698 final RepositoryType repoType = RepositoryType.valueOf(repositoryGroupConfiguration.getType());
699 RepositoryGroup repo;
700 setRepositoryGroupDefaults(repositoryGroupConfiguration);
701 if (repositoryGroups.containsKey(id)) {
702 repo = repositoryGroups.get(id);
703 if (repo instanceof EditableRepositoryGroup) {
704 getProvider(repoType).updateRepositoryGroupInstance((EditableRepositoryGroup) repo, repositoryGroupConfiguration);
706 throw new RepositoryException("The repository is not editable " + id);
709 repo = getProvider(repoType).createRepositoryGroup(repositoryGroupConfiguration);
710 repositoryGroups.put(id, repo);
712 updateRepositoryReferences(getProvider(repoType), repo, repositoryGroupConfiguration);
713 replaceOrAddRepositoryConfig(repositoryGroupConfiguration, configuration);
716 rwLock.writeLock().unlock();
720 private void setRepositoryGroupDefaults(RepositoryGroupConfiguration repositoryGroupConfiguration) {
721 if (StringUtils.isEmpty(repositoryGroupConfiguration.getMergedIndexPath())) {
722 repositoryGroupConfiguration.setMergedIndexPath(DEFAULT_INDEX_PATH);
724 if (repositoryGroupConfiguration.getMergedIndexTtl() <= 0) {
725 repositoryGroupConfiguration.setMergedIndexTtl(300);
727 if (StringUtils.isEmpty(repositoryGroupConfiguration.getCronExpression())) {
728 repositoryGroupConfiguration.setCronExpression("0 0 03 ? * MON");
732 private void replaceOrAddRepositoryConfig(ManagedRepositoryConfiguration managedRepositoryConfiguration, Configuration configuration) {
733 if (configuration != null) {
734 ManagedRepositoryConfiguration oldCfg = configuration.findManagedRepositoryById(managedRepositoryConfiguration.getId());
735 if (oldCfg != null) {
736 configuration.removeManagedRepository(oldCfg);
738 configuration.addManagedRepository(managedRepositoryConfiguration);
742 private void replaceOrAddRepositoryConfig(RemoteRepositoryConfiguration remoteRepositoryConfiguration, Configuration configuration) {
743 if (configuration != null) {
744 RemoteRepositoryConfiguration oldCfg = configuration.findRemoteRepositoryById(remoteRepositoryConfiguration.getId());
745 if (oldCfg != null) {
746 configuration.removeRemoteRepository(oldCfg);
748 configuration.addRemoteRepository(remoteRepositoryConfiguration);
752 private void replaceOrAddRepositoryConfig(RepositoryGroupConfiguration repositoryGroupConfiguration, Configuration configuration) {
753 RepositoryGroupConfiguration oldCfg = configuration.findRepositoryGroupById(repositoryGroupConfiguration.getId());
754 if (oldCfg != null) {
755 configuration.removeRepositoryGroup(oldCfg);
757 configuration.addRepositoryGroup(repositoryGroupConfiguration);
760 public RemoteRepository putRepository(RemoteRepository remoteRepository, Configuration configuration) throws RepositoryException {
761 rwLock.writeLock().lock();
763 final String id = remoteRepository.getId();
764 if (managedRepositories.containsKey(id)) {
765 throw new RepositoryException("There exists a managed repository with id " + id + ". Could not update with remote repository.");
767 RemoteRepository originRepo = remoteRepositories.put(id, remoteRepository);
768 RemoteRepositoryConfiguration oldCfg = null;
769 RemoteRepositoryConfiguration newCfg;
771 if (originRepo != null && originRepo != remoteRepository) {
774 final RepositoryProvider provider = getProvider(remoteRepository.getType());
775 newCfg = provider.getRemoteConfiguration(remoteRepository);
776 updateRepositoryReferences(provider, remoteRepository, newCfg, configuration);
777 oldCfg = configuration.findRemoteRepositoryById(id);
778 if (oldCfg != null) {
779 configuration.removeRemoteRepository(oldCfg);
781 configuration.addRemoteRepository(newCfg);
782 if (remoteRepository != originRepo) {
783 pushEvent(new LifecycleEvent<>(LifecycleEvent.LifecycleEventType.REGISTERED, this, remoteRepository));
785 pushEvent(new LifecycleEvent<>(LifecycleEvent.LifecycleEventType.UPDATED, this, remoteRepository));
787 return remoteRepository;
788 } catch (Exception e) {
790 if (originRepo != null) {
791 remoteRepositories.put(id, originRepo);
793 remoteRepositories.remove(id);
795 if (oldCfg != null) {
796 RemoteRepositoryConfiguration cfg = configuration.findRemoteRepositoryById(id);
798 configuration.removeRemoteRepository(cfg);
799 configuration.addRemoteRepository(oldCfg);
802 log.error("Error while adding remote repository {}", e.getMessage(), e);
803 throw new RepositoryException("Could not save the configuration" + (e.getMessage() == null ? "" : ": " + e.getMessage()));
806 rwLock.writeLock().unlock();
811 * Adds a remote repository, or overwrites the repository definition with the same id, if it exists already.
812 * The modification is saved to the configuration immediately.
814 * @param remoteRepository the remote repository to add
815 * @throws RepositoryException if an error occurs during configuration save
817 public RemoteRepository putRepository(RemoteRepository remoteRepository) throws RepositoryException {
818 rwLock.writeLock().lock();
820 Configuration configuration = getArchivaConfiguration().getConfiguration();
822 RemoteRepository repo = putRepository(remoteRepository, configuration);
823 saveConfiguration(configuration);
825 } catch (RegistryException | IndeterminateConfigurationException e) {
826 log.error("Error while saving remote repository {}", e.getMessage(), e);
827 throw new RepositoryException("Could not save the configuration" + (e.getMessage() == null ? "" : ": " + e.getMessage()));
830 rwLock.writeLock().unlock();
835 * Adds a new repository or updates the repository with the same id, if it exists already.
836 * The configuration is saved immediately.
838 * @param remoteRepositoryConfiguration the repository configuration
839 * @return the updated or created repository
840 * @throws RepositoryException if an error occurs, or the configuration is not valid.
842 public RemoteRepository putRepository(RemoteRepositoryConfiguration remoteRepositoryConfiguration) throws RepositoryException {
843 rwLock.writeLock().lock();
845 final String id = remoteRepositoryConfiguration.getId();
846 final RepositoryType repositoryType = RepositoryType.valueOf(remoteRepositoryConfiguration.getType());
847 Configuration configuration = getArchivaConfiguration().getConfiguration();
848 RemoteRepository repo = remoteRepositories.get(id);
849 RemoteRepositoryConfiguration oldCfg = repo != null ? getProvider(repositoryType).getRemoteConfiguration(repo) : null;
850 repo = putRepository(remoteRepositoryConfiguration, configuration);
852 saveConfiguration(configuration);
853 } catch (IndeterminateConfigurationException | RegistryException e) {
854 if (oldCfg != null) {
855 getProvider(repositoryType).updateRemoteInstance((EditableRemoteRepository) repo, oldCfg);
857 log.error("Could not save the configuration for repository {}: {}", id, e.getMessage(), e);
858 throw new RepositoryException("Could not save the configuration for repository " + id + ": " + e.getMessage());
862 rwLock.writeLock().unlock();
868 * Adds a new repository or updates the repository with the same id. The given configuration object is updated, but
869 * the configuration is not saved.
871 * @param remoteRepositoryConfiguration the new or changed repository configuration
872 * @param configuration the configuration object
873 * @return the new or updated repository
874 * @throws RepositoryException if the configuration cannot be saved or updated
876 @SuppressWarnings("unchecked")
877 public RemoteRepository putRepository(RemoteRepositoryConfiguration remoteRepositoryConfiguration, Configuration configuration) throws RepositoryException {
878 rwLock.writeLock().lock();
880 final String id = remoteRepositoryConfiguration.getId();
881 final RepositoryType repoType = RepositoryType.valueOf(remoteRepositoryConfiguration.getType());
882 RemoteRepository repo;
883 boolean registeredNew = false;
884 repo = remoteRepositories.get(id);
885 if (repo != null && repo.isOpen()) {
886 if (repo instanceof EditableRemoteRepository) {
887 getProvider(repoType).updateRemoteInstance((EditableRemoteRepository) repo, remoteRepositoryConfiguration);
889 throw new RepositoryException("The repository is not editable " + id);
892 repo = getProvider(repoType).createRemoteInstance(remoteRepositoryConfiguration);
893 remoteRepositories.put(id, repo);
894 registeredNew = true;
896 updateRepositoryReferences(getProvider(repoType), repo, remoteRepositoryConfiguration, configuration);
897 replaceOrAddRepositoryConfig(remoteRepositoryConfiguration, configuration);
899 pushEvent(new LifecycleEvent(LifecycleEvent.LifecycleEventType.REGISTERED, this, repo));
901 pushEvent(new LifecycleEvent(LifecycleEvent.LifecycleEventType.UPDATED, this, repo));
905 rwLock.writeLock().unlock();
911 public void removeRepository(String repoId) throws RepositoryException {
912 Repository repo = getRepository(repoId);
914 removeRepository(repo);
918 public void removeRepository(Repository repo) throws RepositoryException {
920 log.warn("Trying to remove null repository");
923 if (repo instanceof RemoteRepository) {
924 removeRepository((RemoteRepository) repo);
925 } else if (repo instanceof ManagedRepository) {
926 removeRepository((ManagedRepository) repo);
927 } else if (repo instanceof RepositoryGroup) {
928 removeRepositoryGroup((RepositoryGroup) repo);
930 throw new RepositoryException("Repository type not known: " + repo.getClass());
935 * Removes a managed repository from the registry and configuration, if it exists.
936 * The change is saved to the configuration immediately.
938 * @param managedRepository the managed repository to remove
939 * @throws RepositoryException if a error occurs during configuration save
941 public void removeRepository(ManagedRepository managedRepository) throws RepositoryException {
942 if (managedRepository == null) {
945 final String id = managedRepository.getId();
946 ManagedRepository repo = getManagedRepository(id);
948 rwLock.writeLock().lock();
950 repo = managedRepositories.remove(id);
953 removeRepositoryFromGroups(repo);
954 Configuration configuration = getArchivaConfiguration().getConfiguration();
955 ManagedRepositoryConfiguration cfg = configuration.findManagedRepositoryById(id);
957 configuration.removeManagedRepository(cfg);
959 saveConfiguration(configuration);
961 pushEvent(new LifecycleEvent<>(LifecycleEvent.LifecycleEventType.UNREGISTERED, this, repo));
962 } catch (RegistryException | IndeterminateConfigurationException e) {
964 log.error("Could not save config after repository removal: {}", e.getMessage(), e);
965 managedRepositories.put(repo.getId(), repo);
966 throw new RepositoryException("Could not save configuration after repository removal: " + e.getMessage());
968 rwLock.writeLock().unlock();
973 private void removeRepositoryFromGroups(ManagedRepository repo) {
975 repositoryGroups.values().stream().filter(repoGroup -> repoGroup instanceof EditableRepository).
976 map(repoGroup -> (EditableRepositoryGroup) repoGroup).forEach(repoGroup -> repoGroup.removeRepository(repo));
980 public void removeRepository(ManagedRepository managedRepository, Configuration configuration) throws RepositoryException {
981 if (managedRepository == null) {
984 final String id = managedRepository.getId();
985 ManagedRepository repo = getManagedRepository(id);
987 rwLock.writeLock().lock();
989 repo = managedRepositories.remove(id);
992 removeRepositoryFromGroups(repo);
993 ManagedRepositoryConfiguration cfg = configuration.findManagedRepositoryById(id);
995 configuration.removeManagedRepository(cfg);
998 pushEvent(new LifecycleEvent<>(LifecycleEvent.LifecycleEventType.UNREGISTERED, this, repo));
1000 rwLock.writeLock().unlock();
1008 * Removes a repository group from the registry and configuration, if it exists.
1009 * The change is saved to the configuration immediately.
1011 * @param repositoryGroup the repository group to remove
1012 * @throws RepositoryException if a error occurs during configuration save
1014 public void removeRepositoryGroup(RepositoryGroup repositoryGroup) throws RepositoryException {
1015 if (repositoryGroup == null) {
1018 final String id = repositoryGroup.getId();
1019 RepositoryGroup repo = getRepositoryGroup(id);
1021 rwLock.writeLock().lock();
1023 repo = repositoryGroups.remove(id);
1026 Configuration configuration = getArchivaConfiguration().getConfiguration();
1027 RepositoryGroupConfiguration cfg = configuration.findRepositoryGroupById(id);
1029 configuration.removeRepositoryGroup(cfg);
1031 saveConfiguration(configuration);
1034 } catch (RegistryException | IndeterminateConfigurationException e) {
1036 log.error("Could not save config after repository removal: {}", e.getMessage(), e);
1037 repositoryGroups.put(repo.getId(), repo);
1038 throw new RepositoryException("Could not save configuration after repository removal: " + e.getMessage());
1040 rwLock.writeLock().unlock();
1045 public void removeRepositoryGroup(RepositoryGroup repositoryGroup, Configuration configuration) throws RepositoryException {
1046 if (repositoryGroup == null) {
1049 final String id = repositoryGroup.getId();
1050 RepositoryGroup repo = getRepositoryGroup(id);
1052 rwLock.writeLock().lock();
1054 repo = repositoryGroups.remove(id);
1057 RepositoryGroupConfiguration cfg = configuration.findRepositoryGroupById(id);
1059 configuration.removeRepositoryGroup(cfg);
1063 rwLock.writeLock().unlock();
1069 private void doRemoveRepo(RemoteRepository repo, Configuration configuration) {
1071 RemoteRepositoryConfiguration cfg = configuration.findRemoteRepositoryById(repo.getId());
1073 configuration.removeRemoteRepository(cfg);
1075 List<ProxyConnectorConfiguration> proxyConnectors = new ArrayList<>(configuration.getProxyConnectors());
1076 for (ProxyConnectorConfiguration proxyConnector : proxyConnectors) {
1077 if (StringUtils.equals(proxyConnector.getTargetRepoId(), repo.getId())) {
1078 configuration.removeProxyConnector(proxyConnector);
1084 * Removes the remote repository from the registry and configuration.
1085 * The change is saved to the configuration immediately.
1087 * @param remoteRepository the remote repository to remove
1088 * @throws RepositoryException if a error occurs during configuration save
1090 public void removeRepository(RemoteRepository remoteRepository) throws RepositoryException {
1091 if (remoteRepository == null) {
1094 final String id = remoteRepository.getId();
1095 RemoteRepository repo = getRemoteRepository(id);
1097 rwLock.writeLock().lock();
1099 repo = remoteRepositories.remove(id);
1101 Configuration configuration = getArchivaConfiguration().getConfiguration();
1102 doRemoveRepo(repo, configuration);
1103 saveConfiguration(configuration);
1105 pushEvent(new LifecycleEvent<>(LifecycleEvent.LifecycleEventType.UNREGISTERED, this, repo));
1106 } catch (RegistryException | IndeterminateConfigurationException e) {
1108 log.error("Could not save config after repository removal: {}", e.getMessage(), e);
1109 remoteRepositories.put(repo.getId(), repo);
1110 throw new RepositoryException("Could not save configuration after repository removal: " + e.getMessage());
1112 rwLock.writeLock().unlock();
1117 public void removeRepository(RemoteRepository remoteRepository, Configuration configuration) throws RepositoryException {
1118 if (remoteRepository == null) {
1121 final String id = remoteRepository.getId();
1122 RemoteRepository repo = getRemoteRepository(id);
1124 rwLock.writeLock().lock();
1126 repo = remoteRepositories.remove(id);
1128 doRemoveRepo(repo, configuration);
1130 pushEvent(new LifecycleEvent<>(LifecycleEvent.LifecycleEventType.UNREGISTERED, this, repo));
1132 rwLock.writeLock().unlock();
1139 * Reloads the registry from the configuration.
1141 public void reload() {
1146 * Resets the indexing context of a given repository.
1148 * @param repository The repository
1149 * @throws IndexUpdateFailedException If the index could not be resetted.
1151 public void resetIndexingContext(Repository repository) throws IndexUpdateFailedException {
1152 if (repository.hasIndex() && repository instanceof EditableRepository) {
1153 EditableRepository eRepo = (EditableRepository) repository;
1154 ArchivaIndexingContext newCtx = getIndexManager(repository.getType()).reset(repository.getIndexingContext());
1155 eRepo.setIndexingContext(newCtx);
1161 * Creates a new repository instance with the same settings as this one. The cloned repository is not
1162 * registered or saved to the configuration.
1164 * @param repo The origin repository
1165 * @return The cloned repository.
1167 public ManagedRepository clone(ManagedRepository repo, String newId) throws RepositoryException {
1168 if (managedRepositories.containsKey(newId) || remoteRepositories.containsKey(newId)) {
1169 throw new RepositoryException("The given id exists already " + newId);
1171 RepositoryProvider provider = getProvider(repo.getType());
1172 ManagedRepositoryConfiguration cfg = provider.getManagedConfiguration(repo);
1174 ManagedRepository cloned = provider.createManagedInstance(cfg);
1175 cloned.register(this);
1179 public <T extends Repository> Repository clone(T repo, String newId) throws RepositoryException {
1180 if (repo instanceof RemoteRepository) {
1181 return this.clone((RemoteRepository) repo, newId);
1182 } else if (repo instanceof ManagedRepository) {
1183 return this.clone((ManagedRepository) repo, newId);
1185 throw new RepositoryException("This repository class is not supported " + repo.getClass().getName());
1190 * Creates a new repository instance with the same settings as this one. The cloned repository is not
1191 * registered or saved to the configuration.
1193 * @param repo The origin repository
1194 * @return The cloned repository.
1196 public RemoteRepository clone(RemoteRepository repo, String newId) throws RepositoryException {
1197 if (managedRepositories.containsKey(newId) || remoteRepositories.containsKey(newId)) {
1198 throw new RepositoryException("The given id exists already " + newId);
1200 RepositoryProvider provider = getProvider(repo.getType());
1201 RemoteRepositoryConfiguration cfg = provider.getRemoteConfiguration(repo);
1203 RemoteRepository cloned = provider.createRemoteInstance(cfg);
1204 cloned.register(this);
1210 public void configurationEvent(ConfigurationEvent event) {
1211 // Note: the ignoreConfigEvents flag does not work, if the config events are asynchronous.
1212 if (!ignoreConfigEvents) {
1219 public void register(RepositoryEventListener listener) {
1220 if (!this.listeners.contains(listener)) {
1221 this.listeners.add(listener);
1226 public void register(RepositoryEventListener listener, EventType type) {
1227 List<RepositoryEventListener> listeners;
1228 if (typeListenerMap.containsKey(type)) {
1229 listeners = typeListenerMap.get(type);
1231 listeners = new ArrayList<>();
1232 typeListenerMap.put(type, listeners);
1234 if (!listeners.contains(listener)) {
1235 listeners.add(listener);
1240 public void register(RepositoryEventListener listener, Set<? extends EventType> types) {
1241 for (EventType type : types) {
1242 register(listener, type);
1247 public void unregister(RepositoryEventListener listener) {
1248 this.listeners.remove(listener);
1249 for (List<RepositoryEventListener> listeners : typeListenerMap.values()) {
1250 listeners.remove(listener);
1255 public void clearListeners() {
1256 this.listeners.clear();
1257 this.typeListenerMap.clear();
1260 @SuppressWarnings("unchecked")
1262 public void raise(Event event) {
1263 // To avoid event cycles:
1264 if (sameOriginator(event)) {
1267 if (event instanceof IndexCreationEvent) {
1268 handleIndexCreationEvent((IndexCreationEvent) event);
1270 // We propagate all events to our listeners, but with context of repository registry
1271 pushEvent(event.recreate(this));
1274 private void handleIndexCreationEvent(IndexCreationEvent event) {
1275 IndexCreationEvent idxEvent = event;
1276 if (managedRepositories.containsKey(idxEvent.getRepository().getId()) ||
1277 remoteRepositories.containsKey(idxEvent.getRepository().getId())) {
1278 EditableRepository repo = (EditableRepository) idxEvent.getRepository();
1279 if (repo != null && repo.getIndexingContext() != null) {
1281 ArchivaIndexManager idxmgr = getIndexManager(repo.getType());
1282 if (idxmgr != null) {
1283 ArchivaIndexingContext newCtx = idxmgr.move(repo.getIndexingContext(), repo);
1284 repo.setIndexingContext(newCtx);
1285 idxmgr.updateLocalIndexPath(repo);
1288 } catch (IndexCreationFailedException e) {
1289 log.error("Could not move index to new directory {}", e.getMessage(), e);
1295 private boolean sameOriginator(Event event) {
1296 if (event.getOriginator() == this) {
1298 } else if (event.hasPreviousEvent()) {
1299 return sameOriginator(event.getPreviousEvent());
1305 private void pushEvent(Event<RepositoryRegistry> event) {
1306 callListeners(event, listeners);
1307 if (typeListenerMap.containsKey(event.getType())) {
1308 callListeners(event, typeListenerMap.get(event.getType()));
1312 private void callListeners(final Event<RepositoryRegistry> event, final List<RepositoryEventListener> evtListeners) {
1313 for (RepositoryEventListener listener : evtListeners) {
1315 listener.raise(event);
1316 } catch (Throwable e) {
1317 log.error("Could not raise event {} on listener {}: {}", event, listener, e.getMessage());