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.events.EventHandler;
27 import org.apache.archiva.repository.features.IndexCreationFeature;
28 import org.apache.archiva.repository.features.StagingRepositoryFeature;
29 import org.apache.commons.lang3.StringUtils;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32 import org.springframework.stereotype.Service;
34 import javax.annotation.PostConstruct;
35 import javax.annotation.PreDestroy;
36 import javax.inject.Inject;
37 import javax.inject.Named;
39 import java.util.concurrent.locks.ReentrantReadWriteLock;
40 import java.util.stream.Collectors;
41 import java.util.stream.Stream;
43 import static org.apache.archiva.indexer.ArchivaIndexManager.DEFAULT_INDEX_PATH;
46 * Registry for repositories. This is the central entry point for repositories. It provides methods for
47 * retrieving, adding and removing repositories.
49 * The modification methods addXX and removeXX persist the changes immediately to the configuration. If the
50 * configuration save fails the changes are rolled back.
56 @Service("repositoryRegistry")
57 public class RepositoryRegistry implements ConfigurationListener, EventSource, EventHandler<Event> {
59 private static final Logger log = LoggerFactory.getLogger(RepositoryRegistry.class);
62 * We inject all repository providers
65 List<RepositoryProvider> repositoryProviders;
68 IndexManagerFactory indexManagerFactory;
71 ArchivaConfiguration archivaConfiguration;
74 @Named("repositoryContentFactory#default")
75 RepositoryContentFactory repositoryContentFactory;
77 private final EventManager eventManager;
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 RepositoryRegistry() {
94 this.eventManager = new EventManager(this);
97 public void setArchivaConfiguration(ArchivaConfiguration archivaConfiguration) {
98 this.archivaConfiguration = archivaConfiguration;
102 private void initialize() {
103 rwLock.writeLock().lock();
105 log.debug("Initializing repository registry");
106 updateManagedRepositoriesFromConfig();
107 updateRemoteRepositoriesFromConfig();
109 repositoryGroups.clear();
110 Map<String, RepositoryGroup> repositoryGroups = getRepositorGroupsFromConfig();
111 this.repositoryGroups.putAll(repositoryGroups);
113 // archivaConfiguration.addChangeListener(this);
114 archivaConfiguration.addListener(this);
116 rwLock.writeLock().unlock();
118 pushEvent(new RepositoryRegistryEvent(RepositoryRegistryEvent.RELOADED, this));
122 public void destroy() {
123 for (ManagedRepository rep : managedRepositories.values()) {
126 managedRepositories.clear();
127 for (RemoteRepository repo : remoteRepositories.values()) {
130 remoteRepositories.clear();
131 pushEvent(new RepositoryRegistryEvent(RepositoryRegistryEvent.DESTROYED, this));
135 private Map<RepositoryType, RepositoryProvider> createProviderMap() {
136 Map<RepositoryType, RepositoryProvider> map = new HashMap<>();
137 if (repositoryProviders != null) {
138 for (RepositoryProvider provider : repositoryProviders) {
139 for (RepositoryType type : provider.provides()) {
140 map.put(type, provider);
147 private RepositoryProvider getProvider(RepositoryType type) throws RepositoryException {
148 return repositoryProviders.stream().filter(repositoryProvider -> repositoryProvider.provides().contains(type)).findFirst().orElseThrow(() -> new RepositoryException("Repository type cannot be handled: " + type));
152 * Updates the repositories
154 private void updateManagedRepositoriesFromConfig() {
157 Set<String> configRepoIds = new HashSet<>();
158 List<ManagedRepositoryConfiguration> managedRepoConfigs =
159 getArchivaConfiguration().getConfiguration().getManagedRepositories();
161 if (managedRepoConfigs == null) {
165 for (ManagedRepositoryConfiguration repoConfig : managedRepoConfigs) {
166 ManagedRepository repo = putRepository(repoConfig, null);
167 configRepoIds.add(repoConfig.getId());
168 if (repo.supportsFeature(StagingRepositoryFeature.class)) {
169 StagingRepositoryFeature stagF = repo.getFeature(StagingRepositoryFeature.class).get();
170 if (stagF.getStagingRepository() != null) {
171 configRepoIds.add(stagF.getStagingRepository().getId());
175 List<String> toRemove = managedRepositories.keySet().stream().filter(id -> !configRepoIds.contains(id)).collect(Collectors.toList());
176 for (String id : toRemove) {
177 ManagedRepository removed = managedRepositories.remove(id);
180 } catch (Throwable e) {
181 log.error("Could not initialize repositories from config: {}", e.getMessage(), e);
186 private ManagedRepository createNewManagedRepository(RepositoryProvider provider, ManagedRepositoryConfiguration cfg) throws RepositoryException {
187 log.debug("Creating repo {}", cfg.getId());
188 ManagedRepository repo = provider.createManagedInstance(cfg);
189 repo.registerEventHandler(RepositoryEvent.ANY, this);
190 updateRepositoryReferences(provider, repo, cfg, null);
195 private String getStagingId(String repoId) {
196 return repoId + StagingRepositoryFeature.STAGING_REPO_POSTFIX;
199 @SuppressWarnings("unchecked")
200 private void updateRepositoryReferences(RepositoryProvider provider, ManagedRepository repo, ManagedRepositoryConfiguration cfg, Configuration configuration) throws RepositoryException {
201 log.debug("Updating references of repo {}", repo.getId());
202 if (repo.supportsFeature(StagingRepositoryFeature.class)) {
203 StagingRepositoryFeature feature = repo.getFeature(StagingRepositoryFeature.class).get();
204 if (feature.isStageRepoNeeded() && feature.getStagingRepository() == null) {
205 ManagedRepository stageRepo = getManagedRepository(getStagingId(repo.getId()));
206 if (stageRepo == null) {
207 stageRepo = getStagingRepository(provider, cfg, configuration);
208 managedRepositories.put(stageRepo.getId(), stageRepo);
209 if (configuration != null) {
210 replaceOrAddRepositoryConfig(provider.getManagedConfiguration(stageRepo), configuration);
212 pushEvent(new LifecycleEvent(LifecycleEvent.REGISTERED, this, stageRepo));
214 feature.setStagingRepository(stageRepo);
217 if (repo instanceof EditableManagedRepository) {
218 EditableManagedRepository editableRepo = (EditableManagedRepository) repo;
219 if (repo.getContent() == null) {
220 editableRepo.setContent(repositoryContentFactory.getManagedRepositoryContent(repo));
221 editableRepo.getContent().setRepository(editableRepo);
223 log.debug("Index repo: " + repo.hasIndex());
224 if (repo.hasIndex() && ( repo.getIndexingContext() == null || !repo.getIndexingContext().isOpen() )) {
225 log.debug("Creating indexing context for {}", repo.getId());
226 createIndexingContext(editableRepo);
229 repo.registerEventHandler(RepositoryEvent.ANY, this);
232 public ArchivaIndexManager getIndexManager(RepositoryType type) {
233 return indexManagerFactory.getIndexManager(type);
236 private void createIndexingContext(EditableRepository editableRepo) throws RepositoryException {
237 if (editableRepo.supportsFeature(IndexCreationFeature.class)) {
238 ArchivaIndexManager idxManager = getIndexManager(editableRepo.getType());
240 editableRepo.setIndexingContext(idxManager.createContext(editableRepo));
241 idxManager.updateLocalIndexPath(editableRepo);
242 } catch (IndexCreationFailedException e) {
243 throw new RepositoryException("Could not create index for repository " + editableRepo.getId() + ": " + e.getMessage(), e);
248 private ManagedRepository getStagingRepository(RepositoryProvider provider, ManagedRepositoryConfiguration baseRepoCfg, Configuration configuration) throws RepositoryException {
249 ManagedRepository stageRepo = getManagedRepository(getStagingId(baseRepoCfg.getId()));
250 if (stageRepo == null) {
251 stageRepo = provider.createStagingInstance(baseRepoCfg);
252 if (stageRepo.supportsFeature(StagingRepositoryFeature.class)) {
253 stageRepo.getFeature(StagingRepositoryFeature.class).get().setStageRepoNeeded(false);
255 ManagedRepositoryConfiguration stageCfg = provider.getManagedConfiguration(stageRepo);
256 updateRepositoryReferences(provider, stageRepo, stageCfg, configuration);
262 private void updateRemoteRepositoriesFromConfig() {
264 List<RemoteRepositoryConfiguration> remoteRepoConfigs =
265 getArchivaConfiguration().getConfiguration().getRemoteRepositories();
267 if (remoteRepoConfigs == null) {
270 Set<String> repoIds = new HashSet<>();
271 for (RemoteRepositoryConfiguration repoConfig : remoteRepoConfigs) {
272 putRepository(repoConfig, null);
273 repoIds.add(repoConfig.getId());
276 List<String> toRemove = remoteRepositories.keySet().stream().filter(id -> !repoIds.contains(id)).collect(Collectors.toList());
277 for (String id : toRemove) {
278 RemoteRepository removed = remoteRepositories.remove(id);
282 } catch (Throwable e) {
283 log.error("Could not initialize remote repositories from config: {}", e.getMessage(), e);
288 private RemoteRepository createNewRemoteRepository(RepositoryProvider provider, RemoteRepositoryConfiguration cfg) throws RepositoryException {
289 log.debug("Creating remote repo {}", cfg.getId());
290 RemoteRepository repo = provider.createRemoteInstance(cfg);
291 updateRepositoryReferences(provider, repo, cfg, null);
296 private void updateRepositoryReferences(RepositoryProvider provider, RemoteRepository repo, RemoteRepositoryConfiguration cfg, Configuration configuration) throws RepositoryException {
297 if (repo instanceof EditableRemoteRepository && repo.getContent() == null) {
298 EditableRemoteRepository editableRepo = (EditableRemoteRepository) repo;
299 editableRepo.setContent(repositoryContentFactory.getRemoteRepositoryContent(repo));
300 if (repo.supportsFeature(IndexCreationFeature.class) && repo.getIndexingContext() == null) {
301 createIndexingContext(editableRepo);
304 repo.registerEventHandler(RepositoryEvent.ANY, this);
307 private Map<String, RepositoryGroup> getRepositorGroupsFromConfig() {
309 List<RepositoryGroupConfiguration> repositoryGroupConfigurations =
310 getArchivaConfiguration().getConfiguration().getRepositoryGroups();
312 if (repositoryGroupConfigurations == null) {
313 return Collections.emptyMap();
316 Map<String, RepositoryGroup> repositoryGroupMap = new LinkedHashMap<>(repositoryGroupConfigurations.size());
318 Map<RepositoryType, RepositoryProvider> providerMap = createProviderMap();
319 for (RepositoryGroupConfiguration repoConfig : repositoryGroupConfigurations) {
320 RepositoryType repositoryType = RepositoryType.valueOf(repoConfig.getType());
321 if (providerMap.containsKey(repositoryType)) {
323 RepositoryGroup repo = createNewRepositoryGroup(providerMap.get(repositoryType), repoConfig);
324 repositoryGroupMap.put(repo.getId(), repo);
325 } catch (Exception e) {
326 log.error("Could not create repository group {}: {}", repoConfig.getId(), e.getMessage(), e);
330 return repositoryGroupMap;
331 } catch (Throwable e) {
332 log.error("Could not initialize repositories from config: {}", e.getMessage(), e);
333 return Collections.emptyMap();
337 private RepositoryGroup createNewRepositoryGroup(RepositoryProvider provider, RepositoryGroupConfiguration config) throws RepositoryException {
338 RepositoryGroup repositoryGroup = provider.createRepositoryGroup(config);
339 repositoryGroup.registerEventHandler(RepositoryEvent.ANY, this);
340 updateRepositoryReferences(provider, repositoryGroup, config);
341 return repositoryGroup;
344 private void updateRepositoryReferences(RepositoryProvider provider, RepositoryGroup group, RepositoryGroupConfiguration configuration) {
345 if (group instanceof EditableRepositoryGroup) {
346 EditableRepositoryGroup eGroup = (EditableRepositoryGroup) group;
347 eGroup.setRepositories(configuration.getRepositories().stream().map(r -> getManagedRepository(r)).collect(Collectors.toList()));
351 private ArchivaConfiguration getArchivaConfiguration() {
352 return this.archivaConfiguration;
356 * Returns all repositories that are registered. There is no defined order of the returned repositories.
358 * @return a list of managed and remote repositories
360 public Collection<Repository> getRepositories() {
361 rwLock.readLock().lock();
363 return Stream.concat(managedRepositories.values().stream(), remoteRepositories.values().stream()).collect(Collectors.toList());
365 rwLock.readLock().unlock();
370 * Returns only the managed repositories. There is no defined order of the returned repositories.
372 * @return a list of managed repositories
374 public Collection<ManagedRepository> getManagedRepositories() {
375 rwLock.readLock().lock();
377 return uManagedRepository.values();
379 rwLock.readLock().unlock();
384 * Returns only the remote repositories. There is no defined order of the returned repositories.
386 * @return a list of remote repositories
388 public Collection<RemoteRepository> getRemoteRepositories() {
389 rwLock.readLock().lock();
391 return uRemoteRepositories.values();
393 rwLock.readLock().unlock();
397 public Collection<RepositoryGroup> getRepositoryGroups() {
398 rwLock.readLock().lock();
400 return uRepositoryGroups.values();
402 rwLock.readLock().unlock();
407 * Returns the repository with the given id. The returned repository may be a managed or remote repository.
408 * It returns null, if no repository is registered with the given id.
410 * @param repoId the repository id
411 * @return the repository if found, otherwise null
413 public Repository getRepository(String repoId) {
414 rwLock.readLock().lock();
416 log.debug("getRepository {}", repoId);
417 if (managedRepositories.containsKey(repoId)) {
418 log.debug("Managed repo");
419 return managedRepositories.get(repoId);
420 } else if (remoteRepositories.containsKey(repoId)) {
421 log.debug("Remote repo");
422 return remoteRepositories.get(repoId);
423 } else if (repositoryGroups.containsKey(repoId)) {
424 return repositoryGroups.get(repoId);
429 rwLock.readLock().unlock();
434 * Convenience method, that returns the managed repository with the given id.
435 * It returns null, if no managed repository is registered with this id.
437 * @param repoId the repository id
438 * @return the managed repository if found, otherwise null
440 public ManagedRepository getManagedRepository(String repoId) {
441 rwLock.readLock().lock();
443 return managedRepositories.get(repoId);
445 rwLock.readLock().unlock();
450 * Convenience method, that returns the remote repository with the given id.
451 * It returns null, if no remote repository is registered with this id.
453 * @param repoId the repository id
454 * @return the remote repository if found, otherwise null
456 public RemoteRepository getRemoteRepository(String repoId) {
457 rwLock.readLock().lock();
459 return remoteRepositories.get(repoId);
461 rwLock.readLock().unlock();
465 public RepositoryGroup getRepositoryGroup(String groupId) {
466 rwLock.readLock().lock();
468 return repositoryGroups.get(groupId);
470 rwLock.readLock().unlock();
475 * The <code>ignoreConfigEvents</code> works only for synchronized configuration events.
476 * If the configuration throws async events, we cannot know, if the event is caused by this instance or another thread.
478 private void saveConfiguration(Configuration configuration) throws IndeterminateConfigurationException, RegistryException {
479 ignoreConfigEvents = true;
481 getArchivaConfiguration().save(configuration);
483 ignoreConfigEvents = false;
488 * Adds a new repository to the current list, or replaces the repository definition with
489 * the same id, if it exists already.
490 * The change is saved to the configuration immediately.
492 * @param managedRepository the new repository.
493 * @throws RepositoryException if the new repository could not be saved to the configuration.
495 public ManagedRepository putRepository(ManagedRepository managedRepository) throws RepositoryException {
496 rwLock.writeLock().lock();
498 final String id = managedRepository.getId();
499 if (remoteRepositories.containsKey(id)) {
500 throw new RepositoryException("There exists a remote repository with id " + id + ". Could not update with managed repository.");
502 ManagedRepository originRepo = managedRepositories.put(id, managedRepository);
504 if (originRepo != null && originRepo != managedRepository) {
507 RepositoryProvider provider = getProvider(managedRepository.getType());
508 ManagedRepositoryConfiguration newCfg = provider.getManagedConfiguration(managedRepository);
509 Configuration configuration = getArchivaConfiguration().getConfiguration();
510 updateRepositoryReferences(provider, managedRepository, newCfg, configuration);
511 ManagedRepositoryConfiguration oldCfg = configuration.findManagedRepositoryById(id);
512 if (oldCfg != null) {
513 configuration.removeManagedRepository(oldCfg);
515 configuration.addManagedRepository(newCfg);
516 saveConfiguration(configuration);
517 if (originRepo != managedRepository) {
518 pushEvent(new LifecycleEvent(LifecycleEvent.REGISTERED, this, managedRepository));
520 pushEvent(new LifecycleEvent(LifecycleEvent.UPDATED, this, managedRepository));
522 return managedRepository;
523 } catch (Exception e) {
524 // Rollback only partly, because repository is closed already
525 if (originRepo != null) {
526 managedRepositories.put(id, originRepo);
528 managedRepositories.remove(id);
530 log.error("Exception during configuration update {}", e.getMessage(), e);
531 throw new RepositoryException("Could not save the configuration" + (e.getMessage() == null ? "" : ": " + e.getMessage()));
534 rwLock.writeLock().unlock();
539 * Adds a new repository or updates the repository with the same id, if it exists already.
540 * The configuration is saved immediately.
542 * @param managedRepositoryConfiguration the repository configuration
543 * @return the updated or created repository
544 * @throws RepositoryException if an error occurs, or the configuration is not valid.
546 public ManagedRepository putRepository(ManagedRepositoryConfiguration managedRepositoryConfiguration) throws RepositoryException {
547 rwLock.writeLock().lock();
549 final String id = managedRepositoryConfiguration.getId();
550 final RepositoryType repositoryType = RepositoryType.valueOf(managedRepositoryConfiguration.getType());
551 Configuration configuration = getArchivaConfiguration().getConfiguration();
552 ManagedRepository repo = managedRepositories.get(id);
553 ManagedRepositoryConfiguration oldCfg = repo != null ? getProvider(repositoryType).getManagedConfiguration(repo) : null;
554 repo = putRepository(managedRepositoryConfiguration, configuration);
556 saveConfiguration(configuration);
557 } catch (IndeterminateConfigurationException | RegistryException e) {
558 if (oldCfg != null) {
559 getProvider(repositoryType).updateManagedInstance((EditableManagedRepository) repo, oldCfg);
561 log.error("Could not save the configuration for repository {}: {}", id, e.getMessage(), e);
562 throw new RepositoryException("Could not save the configuration for repository " + id + ": " + e.getMessage());
566 rwLock.writeLock().unlock();
572 * Adds a new repository or updates the repository with the same id. The given configuration object is updated, but
573 * the configuration is not saved.
575 * @param managedRepositoryConfiguration the new or changed managed repository configuration
576 * @param configuration the configuration object (may be <code>null</code>)
577 * @return the new or updated repository
578 * @throws RepositoryException if the configuration cannot be saved or updated
580 public ManagedRepository putRepository(ManagedRepositoryConfiguration managedRepositoryConfiguration, Configuration configuration) throws RepositoryException {
581 rwLock.writeLock().lock();
583 final String id = managedRepositoryConfiguration.getId();
584 final RepositoryType repoType = RepositoryType.valueOf(managedRepositoryConfiguration.getType());
585 ManagedRepository repo;
586 boolean registeredNew = false;
587 repo = managedRepositories.get(id);
588 if (repo != null && repo.isOpen()) {
589 if (repo instanceof EditableManagedRepository) {
590 getProvider(repoType).updateManagedInstance((EditableManagedRepository) repo, managedRepositoryConfiguration);
592 throw new RepositoryException("The repository is not editable " + id);
595 repo = getProvider(repoType).createManagedInstance(managedRepositoryConfiguration);
596 managedRepositories.put(id, repo);
597 registeredNew = true;
599 updateRepositoryReferences(getProvider(repoType), repo, managedRepositoryConfiguration, configuration);
600 replaceOrAddRepositoryConfig(managedRepositoryConfiguration, configuration);
602 pushEvent(new LifecycleEvent(LifecycleEvent.REGISTERED, this, repo));
604 pushEvent(new LifecycleEvent(LifecycleEvent.UPDATED, this, repo));
608 rwLock.writeLock().unlock();
614 * Adds a new repository group to the current list, or replaces the repository group definition with
615 * the same id, if it exists already.
616 * The change is saved to the configuration immediately.
618 * @param repositoryGroup the new repository group.
619 * @throws RepositoryException if the new repository group could not be saved to the configuration.
621 public RepositoryGroup putRepositoryGroup(RepositoryGroup repositoryGroup) throws RepositoryException {
622 rwLock.writeLock().lock();
624 final String id = repositoryGroup.getId();
625 RepositoryGroup originRepoGroup = repositoryGroups.put(id, repositoryGroup);
627 if (originRepoGroup != null && originRepoGroup != repositoryGroup) {
628 originRepoGroup.close();
630 RepositoryProvider provider = getProvider(repositoryGroup.getType());
631 RepositoryGroupConfiguration newCfg = provider.getRepositoryGroupConfiguration(repositoryGroup);
632 Configuration configuration = getArchivaConfiguration().getConfiguration();
633 updateRepositoryReferences(provider, repositoryGroup, newCfg);
634 RepositoryGroupConfiguration oldCfg = configuration.findRepositoryGroupById(id);
635 if (oldCfg != null) {
636 configuration.removeRepositoryGroup(oldCfg);
638 configuration.addRepositoryGroup(newCfg);
639 saveConfiguration(configuration);
640 return repositoryGroup;
641 } catch (Exception e) {
643 if (originRepoGroup != null) {
644 repositoryGroups.put(id, originRepoGroup);
646 repositoryGroups.remove(id);
648 log.error("Exception during configuration update {}", e.getMessage(), e);
649 throw new RepositoryException("Could not save the configuration" + (e.getMessage() == null ? "" : ": " + e.getMessage()));
652 rwLock.writeLock().unlock();
657 * Adds a new repository group or updates the repository with the same id, if it exists already.
658 * The configuration is saved immediately.
660 * @param repositoryGroupConfiguration the repository configuration
661 * @return the updated or created repository
662 * @throws RepositoryException if an error occurs, or the configuration is not valid.
664 public RepositoryGroup putRepositoryGroup(RepositoryGroupConfiguration repositoryGroupConfiguration) throws RepositoryException {
665 rwLock.writeLock().lock();
667 final String id = repositoryGroupConfiguration.getId();
668 final RepositoryType repositoryType = RepositoryType.valueOf(repositoryGroupConfiguration.getType());
669 Configuration configuration = getArchivaConfiguration().getConfiguration();
670 RepositoryGroup repo = repositoryGroups.get(id);
671 RepositoryGroupConfiguration oldCfg = repo != null ? getProvider(repositoryType).getRepositoryGroupConfiguration(repo) : null;
672 repo = putRepositoryGroup(repositoryGroupConfiguration, configuration);
674 saveConfiguration(configuration);
675 } catch (IndeterminateConfigurationException | RegistryException e) {
676 if (oldCfg != null) {
677 getProvider(repositoryType).updateRepositoryGroupInstance((EditableRepositoryGroup) repo, oldCfg);
679 log.error("Could not save the configuration for repository group {}: {}", id, e.getMessage(), e);
680 throw new RepositoryException("Could not save the configuration for repository group " + id + ": " + e.getMessage());
684 rwLock.writeLock().unlock();
690 * Adds a new repository group or updates the repository group with the same id. The given configuration object is updated, but
691 * the configuration is not saved.
693 * @param repositoryGroupConfiguration The configuration of the new or changed repository group.
694 * @param configuration The configuration object. If it is <code>null</code>, the configuration is not saved.
695 * @return The new or updated repository group
696 * @throws RepositoryException if the configuration cannot be saved or updated
698 public RepositoryGroup putRepositoryGroup(RepositoryGroupConfiguration repositoryGroupConfiguration, Configuration configuration) throws RepositoryException {
699 rwLock.writeLock().lock();
701 final String id = repositoryGroupConfiguration.getId();
702 final RepositoryType repoType = RepositoryType.valueOf(repositoryGroupConfiguration.getType());
703 RepositoryGroup repo;
704 setRepositoryGroupDefaults(repositoryGroupConfiguration);
705 if (repositoryGroups.containsKey(id)) {
706 repo = repositoryGroups.get(id);
707 if (repo instanceof EditableRepositoryGroup) {
708 getProvider(repoType).updateRepositoryGroupInstance((EditableRepositoryGroup) repo, repositoryGroupConfiguration);
710 throw new RepositoryException("The repository is not editable " + id);
713 repo = getProvider(repoType).createRepositoryGroup(repositoryGroupConfiguration);
714 repositoryGroups.put(id, repo);
716 updateRepositoryReferences(getProvider(repoType), repo, repositoryGroupConfiguration);
717 replaceOrAddRepositoryConfig(repositoryGroupConfiguration, configuration);
720 rwLock.writeLock().unlock();
724 private void setRepositoryGroupDefaults(RepositoryGroupConfiguration repositoryGroupConfiguration) {
725 if (StringUtils.isEmpty(repositoryGroupConfiguration.getMergedIndexPath())) {
726 repositoryGroupConfiguration.setMergedIndexPath(DEFAULT_INDEX_PATH);
728 if (repositoryGroupConfiguration.getMergedIndexTtl() <= 0) {
729 repositoryGroupConfiguration.setMergedIndexTtl(300);
731 if (StringUtils.isEmpty(repositoryGroupConfiguration.getCronExpression())) {
732 repositoryGroupConfiguration.setCronExpression("0 0 03 ? * MON");
736 private void replaceOrAddRepositoryConfig(ManagedRepositoryConfiguration managedRepositoryConfiguration, Configuration configuration) {
737 if (configuration != null) {
738 ManagedRepositoryConfiguration oldCfg = configuration.findManagedRepositoryById(managedRepositoryConfiguration.getId());
739 if (oldCfg != null) {
740 configuration.removeManagedRepository(oldCfg);
742 configuration.addManagedRepository(managedRepositoryConfiguration);
746 private void replaceOrAddRepositoryConfig(RemoteRepositoryConfiguration remoteRepositoryConfiguration, Configuration configuration) {
747 if (configuration != null) {
748 RemoteRepositoryConfiguration oldCfg = configuration.findRemoteRepositoryById(remoteRepositoryConfiguration.getId());
749 if (oldCfg != null) {
750 configuration.removeRemoteRepository(oldCfg);
752 configuration.addRemoteRepository(remoteRepositoryConfiguration);
756 private void replaceOrAddRepositoryConfig(RepositoryGroupConfiguration repositoryGroupConfiguration, Configuration configuration) {
757 RepositoryGroupConfiguration oldCfg = configuration.findRepositoryGroupById(repositoryGroupConfiguration.getId());
758 if (oldCfg != null) {
759 configuration.removeRepositoryGroup(oldCfg);
761 configuration.addRepositoryGroup(repositoryGroupConfiguration);
764 public RemoteRepository putRepository(RemoteRepository remoteRepository, Configuration configuration) throws RepositoryException {
765 rwLock.writeLock().lock();
767 final String id = remoteRepository.getId();
768 if (managedRepositories.containsKey(id)) {
769 throw new RepositoryException("There exists a managed repository with id " + id + ". Could not update with remote repository.");
771 RemoteRepository originRepo = remoteRepositories.put(id, remoteRepository);
772 RemoteRepositoryConfiguration oldCfg = null;
773 RemoteRepositoryConfiguration newCfg;
775 if (originRepo != null && originRepo != remoteRepository) {
778 final RepositoryProvider provider = getProvider(remoteRepository.getType());
779 newCfg = provider.getRemoteConfiguration(remoteRepository);
780 updateRepositoryReferences(provider, remoteRepository, newCfg, configuration);
781 oldCfg = configuration.findRemoteRepositoryById(id);
782 if (oldCfg != null) {
783 configuration.removeRemoteRepository(oldCfg);
785 configuration.addRemoteRepository(newCfg);
786 if (remoteRepository != originRepo) {
787 pushEvent(new LifecycleEvent(LifecycleEvent.REGISTERED, this, remoteRepository));
789 pushEvent(new LifecycleEvent(LifecycleEvent.UPDATED, this, remoteRepository));
791 return remoteRepository;
792 } catch (Exception e) {
794 if (originRepo != null) {
795 remoteRepositories.put(id, originRepo);
797 remoteRepositories.remove(id);
799 if (oldCfg != null) {
800 RemoteRepositoryConfiguration cfg = configuration.findRemoteRepositoryById(id);
802 configuration.removeRemoteRepository(cfg);
803 configuration.addRemoteRepository(oldCfg);
806 log.error("Error while adding remote repository {}", e.getMessage(), e);
807 throw new RepositoryException("Could not save the configuration" + (e.getMessage() == null ? "" : ": " + e.getMessage()));
810 rwLock.writeLock().unlock();
815 * Adds a remote repository, or overwrites the repository definition with the same id, if it exists already.
816 * The modification is saved to the configuration immediately.
818 * @param remoteRepository the remote repository to add
819 * @throws RepositoryException if an error occurs during configuration save
821 public RemoteRepository putRepository(RemoteRepository remoteRepository) throws RepositoryException {
822 rwLock.writeLock().lock();
824 Configuration configuration = getArchivaConfiguration().getConfiguration();
826 RemoteRepository repo = putRepository(remoteRepository, configuration);
827 saveConfiguration(configuration);
829 } catch (RegistryException | IndeterminateConfigurationException e) {
830 log.error("Error while saving remote repository {}", e.getMessage(), e);
831 throw new RepositoryException("Could not save the configuration" + (e.getMessage() == null ? "" : ": " + e.getMessage()));
834 rwLock.writeLock().unlock();
839 * Adds a new repository or updates the repository with the same id, if it exists already.
840 * The configuration is saved immediately.
842 * @param remoteRepositoryConfiguration the repository configuration
843 * @return the updated or created repository
844 * @throws RepositoryException if an error occurs, or the configuration is not valid.
846 public RemoteRepository putRepository(RemoteRepositoryConfiguration remoteRepositoryConfiguration) throws RepositoryException {
847 rwLock.writeLock().lock();
849 final String id = remoteRepositoryConfiguration.getId();
850 final RepositoryType repositoryType = RepositoryType.valueOf(remoteRepositoryConfiguration.getType());
851 Configuration configuration = getArchivaConfiguration().getConfiguration();
852 RemoteRepository repo = remoteRepositories.get(id);
853 RemoteRepositoryConfiguration oldCfg = repo != null ? getProvider(repositoryType).getRemoteConfiguration(repo) : null;
854 repo = putRepository(remoteRepositoryConfiguration, configuration);
856 saveConfiguration(configuration);
857 } catch (IndeterminateConfigurationException | RegistryException e) {
858 if (oldCfg != null) {
859 getProvider(repositoryType).updateRemoteInstance((EditableRemoteRepository) repo, oldCfg);
861 log.error("Could not save the configuration for repository {}: {}", id, e.getMessage(), e);
862 throw new RepositoryException("Could not save the configuration for repository " + id + ": " + e.getMessage());
866 rwLock.writeLock().unlock();
872 * Adds a new repository or updates the repository with the same id. The given configuration object is updated, but
873 * the configuration is not saved.
875 * @param remoteRepositoryConfiguration the new or changed repository configuration
876 * @param configuration the configuration object
877 * @return the new or updated repository
878 * @throws RepositoryException if the configuration cannot be saved or updated
880 @SuppressWarnings("unchecked")
881 public RemoteRepository putRepository(RemoteRepositoryConfiguration remoteRepositoryConfiguration, Configuration configuration) throws RepositoryException {
882 rwLock.writeLock().lock();
884 final String id = remoteRepositoryConfiguration.getId();
885 final RepositoryType repoType = RepositoryType.valueOf(remoteRepositoryConfiguration.getType());
886 RemoteRepository repo;
887 boolean registeredNew = false;
888 repo = remoteRepositories.get(id);
889 if (repo != null && repo.isOpen()) {
890 if (repo instanceof EditableRemoteRepository) {
891 getProvider(repoType).updateRemoteInstance((EditableRemoteRepository) repo, remoteRepositoryConfiguration);
893 throw new RepositoryException("The repository is not editable " + id);
896 repo = getProvider(repoType).createRemoteInstance(remoteRepositoryConfiguration);
897 remoteRepositories.put(id, repo);
898 registeredNew = true;
900 updateRepositoryReferences(getProvider(repoType), repo, remoteRepositoryConfiguration, configuration);
901 replaceOrAddRepositoryConfig(remoteRepositoryConfiguration, configuration);
903 pushEvent(new LifecycleEvent(LifecycleEvent.REGISTERED, this, repo));
905 pushEvent(new LifecycleEvent(LifecycleEvent.UPDATED, this, repo));
909 rwLock.writeLock().unlock();
915 public void removeRepository(String repoId) throws RepositoryException {
916 Repository repo = getRepository(repoId);
918 removeRepository(repo);
922 public void removeRepository(Repository repo) throws RepositoryException {
924 log.warn("Trying to remove null repository");
927 if (repo instanceof RemoteRepository) {
928 removeRepository((RemoteRepository) repo);
929 } else if (repo instanceof ManagedRepository) {
930 removeRepository((ManagedRepository) repo);
931 } else if (repo instanceof RepositoryGroup) {
932 removeRepositoryGroup((RepositoryGroup) repo);
934 throw new RepositoryException("Repository type not known: " + repo.getClass());
939 * Removes a managed repository from the registry and configuration, if it exists.
940 * The change is saved to the configuration immediately.
942 * @param managedRepository the managed repository to remove
943 * @throws RepositoryException if a error occurs during configuration save
945 public void removeRepository(ManagedRepository managedRepository) throws RepositoryException {
946 if (managedRepository == null) {
949 final String id = managedRepository.getId();
950 ManagedRepository repo = getManagedRepository(id);
952 rwLock.writeLock().lock();
954 repo = managedRepositories.remove(id);
957 removeRepositoryFromGroups(repo);
958 Configuration configuration = getArchivaConfiguration().getConfiguration();
959 ManagedRepositoryConfiguration cfg = configuration.findManagedRepositoryById(id);
961 configuration.removeManagedRepository(cfg);
963 saveConfiguration(configuration);
965 pushEvent(new LifecycleEvent(LifecycleEvent.UNREGISTERED, this, repo));
966 } catch (RegistryException | IndeterminateConfigurationException e) {
968 log.error("Could not save config after repository removal: {}", e.getMessage(), e);
969 managedRepositories.put(repo.getId(), repo);
970 throw new RepositoryException("Could not save configuration after repository removal: " + e.getMessage());
972 rwLock.writeLock().unlock();
977 private void removeRepositoryFromGroups(ManagedRepository repo) {
979 repositoryGroups.values().stream().filter(repoGroup -> repoGroup instanceof EditableRepository).
980 map(repoGroup -> (EditableRepositoryGroup) repoGroup).forEach(repoGroup -> repoGroup.removeRepository(repo));
984 public void removeRepository(ManagedRepository managedRepository, Configuration configuration) throws RepositoryException {
985 if (managedRepository == null) {
988 final String id = managedRepository.getId();
989 ManagedRepository repo = getManagedRepository(id);
991 rwLock.writeLock().lock();
993 repo = managedRepositories.remove(id);
996 removeRepositoryFromGroups(repo);
997 ManagedRepositoryConfiguration cfg = configuration.findManagedRepositoryById(id);
999 configuration.removeManagedRepository(cfg);
1002 pushEvent(new LifecycleEvent(LifecycleEvent.UNREGISTERED, this, repo));
1004 rwLock.writeLock().unlock();
1012 * Removes a repository group from the registry and configuration, if it exists.
1013 * The change is saved to the configuration immediately.
1015 * @param repositoryGroup the repository group to remove
1016 * @throws RepositoryException if a error occurs during configuration save
1018 public void removeRepositoryGroup(RepositoryGroup repositoryGroup) throws RepositoryException {
1019 if (repositoryGroup == null) {
1022 final String id = repositoryGroup.getId();
1023 RepositoryGroup repo = getRepositoryGroup(id);
1025 rwLock.writeLock().lock();
1027 repo = repositoryGroups.remove(id);
1030 Configuration configuration = getArchivaConfiguration().getConfiguration();
1031 RepositoryGroupConfiguration cfg = configuration.findRepositoryGroupById(id);
1033 configuration.removeRepositoryGroup(cfg);
1035 saveConfiguration(configuration);
1038 } catch (RegistryException | IndeterminateConfigurationException e) {
1040 log.error("Could not save config after repository removal: {}", e.getMessage(), e);
1041 repositoryGroups.put(repo.getId(), repo);
1042 throw new RepositoryException("Could not save configuration after repository removal: " + e.getMessage());
1044 rwLock.writeLock().unlock();
1049 public void removeRepositoryGroup(RepositoryGroup repositoryGroup, Configuration configuration) throws RepositoryException {
1050 if (repositoryGroup == null) {
1053 final String id = repositoryGroup.getId();
1054 RepositoryGroup repo = getRepositoryGroup(id);
1056 rwLock.writeLock().lock();
1058 repo = repositoryGroups.remove(id);
1061 RepositoryGroupConfiguration cfg = configuration.findRepositoryGroupById(id);
1063 configuration.removeRepositoryGroup(cfg);
1067 rwLock.writeLock().unlock();
1073 private void doRemoveRepo(RemoteRepository repo, Configuration configuration) {
1075 RemoteRepositoryConfiguration cfg = configuration.findRemoteRepositoryById(repo.getId());
1077 configuration.removeRemoteRepository(cfg);
1079 List<ProxyConnectorConfiguration> proxyConnectors = new ArrayList<>(configuration.getProxyConnectors());
1080 for (ProxyConnectorConfiguration proxyConnector : proxyConnectors) {
1081 if (StringUtils.equals(proxyConnector.getTargetRepoId(), repo.getId())) {
1082 configuration.removeProxyConnector(proxyConnector);
1088 * Removes the remote repository from the registry and configuration.
1089 * The change is saved to the configuration immediately.
1091 * @param remoteRepository the remote repository to remove
1092 * @throws RepositoryException if a error occurs during configuration save
1094 public void removeRepository(RemoteRepository remoteRepository) throws RepositoryException {
1095 if (remoteRepository == null) {
1098 final String id = remoteRepository.getId();
1099 RemoteRepository repo = getRemoteRepository(id);
1101 rwLock.writeLock().lock();
1103 repo = remoteRepositories.remove(id);
1105 Configuration configuration = getArchivaConfiguration().getConfiguration();
1106 doRemoveRepo(repo, configuration);
1107 saveConfiguration(configuration);
1109 pushEvent(new LifecycleEvent(LifecycleEvent.UNREGISTERED, this, repo));
1110 } catch (RegistryException | IndeterminateConfigurationException e) {
1112 log.error("Could not save config after repository removal: {}", e.getMessage(), e);
1113 remoteRepositories.put(repo.getId(), repo);
1114 throw new RepositoryException("Could not save configuration after repository removal: " + e.getMessage());
1116 rwLock.writeLock().unlock();
1121 public void removeRepository(RemoteRepository remoteRepository, Configuration configuration) throws RepositoryException {
1122 if (remoteRepository == null) {
1125 final String id = remoteRepository.getId();
1126 RemoteRepository repo = getRemoteRepository(id);
1128 rwLock.writeLock().lock();
1130 repo = remoteRepositories.remove(id);
1132 doRemoveRepo(repo, configuration);
1134 pushEvent(new LifecycleEvent(LifecycleEvent.UNREGISTERED, this, repo));
1136 rwLock.writeLock().unlock();
1143 * Reloads the registry from the configuration.
1145 public void reload() {
1150 * Resets the indexing context of a given repository.
1152 * @param repository The repository
1153 * @throws IndexUpdateFailedException If the index could not be resetted.
1155 public void resetIndexingContext(Repository repository) throws IndexUpdateFailedException {
1156 if (repository.hasIndex() && repository instanceof EditableRepository) {
1157 EditableRepository eRepo = (EditableRepository) repository;
1158 ArchivaIndexingContext newCtx = getIndexManager(repository.getType()).reset(repository.getIndexingContext());
1159 eRepo.setIndexingContext(newCtx);
1165 * Creates a new repository instance with the same settings as this one. The cloned repository is not
1166 * registered or saved to the configuration.
1168 * @param repo The origin repository
1169 * @return The cloned repository.
1171 public ManagedRepository clone(ManagedRepository repo, String newId) throws RepositoryException {
1172 if (managedRepositories.containsKey(newId) || remoteRepositories.containsKey(newId)) {
1173 throw new RepositoryException("The given id exists already " + newId);
1175 RepositoryProvider provider = getProvider(repo.getType());
1176 ManagedRepositoryConfiguration cfg = provider.getManagedConfiguration(repo);
1178 ManagedRepository cloned = provider.createManagedInstance(cfg);
1179 cloned.registerEventHandler(RepositoryEvent.ANY, this);
1183 public <T extends Repository> Repository clone(T repo, String newId) throws RepositoryException {
1184 if (repo instanceof RemoteRepository) {
1185 return this.clone((RemoteRepository) repo, newId);
1186 } else if (repo instanceof ManagedRepository) {
1187 return this.clone((ManagedRepository) repo, newId);
1189 throw new RepositoryException("This repository class is not supported " + repo.getClass().getName());
1194 * Creates a new repository instance with the same settings as this one. The cloned repository is not
1195 * registered or saved to the configuration.
1197 * @param repo The origin repository
1198 * @return The cloned repository.
1200 public RemoteRepository clone(RemoteRepository repo, String newId) throws RepositoryException {
1201 if (managedRepositories.containsKey(newId) || remoteRepositories.containsKey(newId)) {
1202 throw new RepositoryException("The given id exists already " + newId);
1204 RepositoryProvider provider = getProvider(repo.getType());
1205 RemoteRepositoryConfiguration cfg = provider.getRemoteConfiguration(repo);
1207 RemoteRepository cloned = provider.createRemoteInstance(cfg);
1208 cloned.registerEventHandler(RepositoryEvent.ANY, this);
1214 public void configurationEvent(ConfigurationEvent event) {
1215 // Note: the ignoreConfigEvents flag does not work, if the config events are asynchronous.
1216 if (!ignoreConfigEvents) {
1223 public <T extends Event> void registerEventHandler(EventType<T> type, EventHandler<? super T> eventHandler) {
1224 eventManager.registerEventHandler(type, eventHandler);
1229 public <T extends Event> void unregisterEventHandler(EventType<T> type, EventHandler<? super T> eventHandler) {
1230 eventManager.unregisterEventHandler(type, eventHandler);
1235 public void handle(Event event) {
1236 // To avoid event cycles:
1237 if (sameOriginator(event)) {
1240 if (event instanceof RepositoryIndexEvent) {
1241 handleIndexCreationEvent((RepositoryIndexEvent) event);
1243 // We propagate all events to our listeners, but with context of repository registry
1247 private void handleIndexCreationEvent(RepositoryIndexEvent event) {
1248 RepositoryIndexEvent idxEvent = event;
1249 if (managedRepositories.containsKey(idxEvent.getRepository().getId()) ||
1250 remoteRepositories.containsKey(idxEvent.getRepository().getId())) {
1251 EditableRepository repo = (EditableRepository) idxEvent.getRepository();
1252 if (repo != null && repo.getIndexingContext() != null) {
1254 ArchivaIndexManager idxmgr = getIndexManager(repo.getType());
1255 if (idxmgr != null) {
1256 ArchivaIndexingContext newCtx = idxmgr.move(repo.getIndexingContext(), repo);
1257 repo.setIndexingContext(newCtx);
1258 idxmgr.updateLocalIndexPath(repo);
1261 } catch (IndexCreationFailedException e) {
1262 log.error("Could not move index to new directory {}", e.getMessage(), e);
1268 private boolean sameOriginator(Event event) {
1269 if (event.getSource() == this) {
1271 } else if (event.hasPreviousEvent()) {
1272 return sameOriginator(event.getPreviousEvent());
1278 private void pushEvent(Event event) {
1279 eventManager.fireEvent(event);