1 package org.apache.archiva.repository.base;
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.event.Event;
24 import org.apache.archiva.event.EventManager;
25 import org.apache.archiva.event.EventType;
26 import org.apache.archiva.indexer.*;
27 import org.apache.archiva.components.registry.RegistryException;
28 import org.apache.archiva.repository.EditableManagedRepository;
29 import org.apache.archiva.repository.EditableRemoteRepository;
30 import org.apache.archiva.repository.EditableRepository;
31 import org.apache.archiva.repository.EditableRepositoryGroup;
32 import org.apache.archiva.repository.ManagedRepository;
33 import org.apache.archiva.repository.RemoteRepository;
34 import org.apache.archiva.repository.Repository;
35 import org.apache.archiva.repository.RepositoryContentFactory;
36 import org.apache.archiva.repository.RepositoryException;
37 import org.apache.archiva.repository.RepositoryGroup;
38 import org.apache.archiva.repository.RepositoryProvider;
39 import org.apache.archiva.repository.RepositoryRegistry;
40 import org.apache.archiva.repository.RepositoryType;
41 import org.apache.archiva.repository.UnsupportedRepositoryTypeException;
42 import org.apache.archiva.repository.event.*;
43 import org.apache.archiva.event.EventHandler;
44 import org.apache.archiva.repository.features.IndexCreationFeature;
45 import org.apache.archiva.repository.features.StagingRepositoryFeature;
46 import org.apache.archiva.repository.metadata.MetadataReader;
47 import org.apache.archiva.repository.storage.StorageAsset;
48 import org.apache.commons.lang3.StringUtils;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51 import org.springframework.stereotype.Service;
53 import javax.annotation.PostConstruct;
54 import javax.annotation.PreDestroy;
55 import javax.inject.Inject;
56 import javax.inject.Named;
58 import java.util.concurrent.locks.ReentrantReadWriteLock;
59 import java.util.stream.Collectors;
60 import java.util.stream.Stream;
62 import static org.apache.archiva.indexer.ArchivaIndexManager.DEFAULT_INDEX_PATH;
65 * Registry for repositories. This is the central entry point for repositories. It provides methods for
66 * retrieving, adding and removing repositories.
68 * The modification methods addXX and removeXX persist the changes immediately to the configuration. If the
69 * configuration save fails the changes are rolled back.
75 @Service("repositoryRegistry")
76 public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHandler<Event>,
80 private static final Logger log = LoggerFactory.getLogger(RepositoryRegistry.class);
83 * We inject all repository providers
86 List<RepositoryProvider> repositoryProviders;
89 IndexManagerFactory indexManagerFactory;
92 ArchivaConfiguration archivaConfiguration;
95 List<MetadataReader> metadataReaderList;
98 @Named("repositoryContentFactory#default")
99 RepositoryContentFactory repositoryContentFactory;
101 private final EventManager eventManager;
104 private Map<String, ManagedRepository> managedRepositories = new HashMap<>();
105 private Map<String, ManagedRepository> uManagedRepository = Collections.unmodifiableMap(managedRepositories);
107 private Map<String, RemoteRepository> remoteRepositories = new HashMap<>();
108 private Map<String, RemoteRepository> uRemoteRepositories = Collections.unmodifiableMap(remoteRepositories);
110 private Map<String, RepositoryGroup> repositoryGroups = new HashMap<>();
111 private Map<String, RepositoryGroup> uRepositoryGroups = Collections.unmodifiableMap(repositoryGroups);
113 private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
115 private volatile boolean ignoreConfigEvents = false;
117 public ArchivaRepositoryRegistry() {
118 this.eventManager = new EventManager(this);
122 public void setArchivaConfiguration( ArchivaConfiguration archivaConfiguration ) {
123 this.archivaConfiguration = archivaConfiguration;
127 private void initialize() {
128 rwLock.writeLock().lock();
130 log.debug("Initializing repository registry");
131 updateManagedRepositoriesFromConfig();
132 updateRemoteRepositoriesFromConfig();
134 repositoryGroups.clear();
135 Map<String, RepositoryGroup> repositoryGroups = getRepositorGroupsFromConfig();
136 this.repositoryGroups.putAll(repositoryGroups);
138 // archivaConfiguration.addChangeListener(this);
139 archivaConfiguration.addListener(this);
141 rwLock.writeLock().unlock();
143 pushEvent(new RepositoryRegistryEvent(RepositoryRegistryEvent.RELOADED, this));
147 public void destroy() {
148 for (ManagedRepository rep : managedRepositories.values()) {
151 managedRepositories.clear();
152 for (RemoteRepository repo : remoteRepositories.values()) {
155 remoteRepositories.clear();
156 pushEvent(new RepositoryRegistryEvent(RepositoryRegistryEvent.DESTROYED, this));
160 private Map<RepositoryType, RepositoryProvider> createProviderMap() {
161 Map<RepositoryType, RepositoryProvider> map = new HashMap<>();
162 if (repositoryProviders != null) {
163 for (RepositoryProvider provider : repositoryProviders) {
164 for (RepositoryType type : provider.provides()) {
165 map.put(type, provider);
172 private RepositoryProvider getProvider(RepositoryType type) throws RepositoryException
174 return repositoryProviders.stream().filter(repositoryProvider -> repositoryProvider.provides().contains(type)).findFirst().orElseThrow(() -> new RepositoryException("Repository type cannot be handled: " + type));
178 * Updates the repositories
180 private void updateManagedRepositoriesFromConfig() {
183 Set<String> configRepoIds = new HashSet<>();
184 List<ManagedRepositoryConfiguration> managedRepoConfigs =
185 getArchivaConfiguration().getConfiguration().getManagedRepositories();
187 if (managedRepoConfigs == null) {
191 for (ManagedRepositoryConfiguration repoConfig : managedRepoConfigs) {
192 ManagedRepository repo = putRepository(repoConfig, null);
193 configRepoIds.add(repoConfig.getId());
194 if (repo.supportsFeature(StagingRepositoryFeature.class)) {
195 StagingRepositoryFeature stagF = repo.getFeature(StagingRepositoryFeature.class).get();
196 if (stagF.getStagingRepository() != null) {
197 configRepoIds.add(stagF.getStagingRepository().getId());
201 List<String> toRemove = managedRepositories.keySet().stream().filter(id -> !configRepoIds.contains(id)).collect(Collectors.toList());
202 for (String id : toRemove) {
203 ManagedRepository removed = managedRepositories.remove(id);
206 } catch (Throwable e) {
207 log.error("Could not initialize repositories from config: {}", e.getMessage(), e);
212 private ManagedRepository createNewManagedRepository(RepositoryProvider provider, ManagedRepositoryConfiguration cfg) throws RepositoryException {
213 log.debug("Creating repo {}", cfg.getId());
214 ManagedRepository repo = provider.createManagedInstance(cfg);
215 repo.registerEventHandler(RepositoryEvent.ANY, this);
216 updateRepositoryReferences(provider, repo, cfg, null);
221 private String getStagingId(String repoId) {
222 return repoId + StagingRepositoryFeature.STAGING_REPO_POSTFIX;
225 @SuppressWarnings("unchecked")
226 private void updateRepositoryReferences(RepositoryProvider provider, ManagedRepository repo, ManagedRepositoryConfiguration cfg, Configuration configuration) throws RepositoryException {
227 log.debug("Updating references of repo {}", repo.getId());
228 if (repo.supportsFeature(StagingRepositoryFeature.class)) {
229 StagingRepositoryFeature feature = repo.getFeature(StagingRepositoryFeature.class).get();
230 if (feature.isStageRepoNeeded() && feature.getStagingRepository() == null) {
231 ManagedRepository stageRepo = getManagedRepository(getStagingId(repo.getId()));
232 if (stageRepo == null) {
233 stageRepo = getStagingRepository(provider, cfg, configuration);
234 managedRepositories.put(stageRepo.getId(), stageRepo);
235 if (configuration != null) {
236 replaceOrAddRepositoryConfig(provider.getManagedConfiguration(stageRepo), configuration);
238 pushEvent(new LifecycleEvent(LifecycleEvent.REGISTERED, this, stageRepo));
240 feature.setStagingRepository(stageRepo);
243 if (repo instanceof EditableManagedRepository ) {
244 EditableManagedRepository editableRepo = (EditableManagedRepository) repo;
245 if (repo.getContent() == null) {
246 editableRepo.setContent(repositoryContentFactory.getManagedRepositoryContent(repo));
247 editableRepo.getContent().setRepository(editableRepo);
249 log.debug("Index repo: " + repo.hasIndex());
250 if (repo.hasIndex() && ( repo.getIndexingContext() == null || !repo.getIndexingContext().isOpen() )) {
251 log.debug("Creating indexing context for {}", repo.getId());
252 createIndexingContext(editableRepo);
255 repo.registerEventHandler(RepositoryEvent.ANY, this);
259 public ArchivaIndexManager getIndexManager( RepositoryType type ) {
260 return indexManagerFactory.getIndexManager(type);
264 public MetadataReader getMetadataReader( final RepositoryType type ) throws UnsupportedRepositoryTypeException
266 if (metadataReaderList!=null) {
267 return metadataReaderList.stream( ).filter( mr -> mr.isValidForType( type ) ).findFirst( ).orElseThrow( ( ) -> new UnsupportedRepositoryTypeException( type ) );
269 throw new UnsupportedRepositoryTypeException( type );
273 private void createIndexingContext( EditableRepository editableRepo) throws RepositoryException {
274 if (editableRepo.supportsFeature(IndexCreationFeature.class)) {
275 ArchivaIndexManager idxManager = getIndexManager(editableRepo.getType());
277 editableRepo.setIndexingContext(idxManager.createContext(editableRepo));
278 idxManager.updateLocalIndexPath(editableRepo);
279 } catch (IndexCreationFailedException e) {
280 throw new RepositoryException("Could not create index for repository " + editableRepo.getId() + ": " + e.getMessage(), e);
285 private ManagedRepository getStagingRepository(RepositoryProvider provider, ManagedRepositoryConfiguration baseRepoCfg, Configuration configuration) throws RepositoryException {
286 ManagedRepository stageRepo = getManagedRepository(getStagingId(baseRepoCfg.getId()));
287 if (stageRepo == null) {
288 stageRepo = provider.createStagingInstance(baseRepoCfg);
289 if (stageRepo.supportsFeature(StagingRepositoryFeature.class)) {
290 stageRepo.getFeature(StagingRepositoryFeature.class).get().setStageRepoNeeded(false);
292 ManagedRepositoryConfiguration stageCfg = provider.getManagedConfiguration(stageRepo);
293 updateRepositoryReferences(provider, stageRepo, stageCfg, configuration);
299 private void updateRemoteRepositoriesFromConfig() {
301 List<RemoteRepositoryConfiguration> remoteRepoConfigs =
302 getArchivaConfiguration().getConfiguration().getRemoteRepositories();
304 if (remoteRepoConfigs == null) {
307 Set<String> repoIds = new HashSet<>();
308 for (RemoteRepositoryConfiguration repoConfig : remoteRepoConfigs) {
309 putRepository(repoConfig, null);
310 repoIds.add(repoConfig.getId());
313 List<String> toRemove = remoteRepositories.keySet().stream().filter(id -> !repoIds.contains(id)).collect(Collectors.toList());
314 for (String id : toRemove) {
315 RemoteRepository removed = remoteRepositories.remove(id);
319 } catch (Throwable e) {
320 log.error("Could not initialize remote repositories from config: {}", e.getMessage(), e);
325 private RemoteRepository createNewRemoteRepository(RepositoryProvider provider, RemoteRepositoryConfiguration cfg) throws RepositoryException {
326 log.debug("Creating remote repo {}", cfg.getId());
327 RemoteRepository repo = provider.createRemoteInstance(cfg);
328 updateRepositoryReferences(provider, repo, cfg, null);
333 private void updateRepositoryReferences(RepositoryProvider provider, RemoteRepository repo, RemoteRepositoryConfiguration cfg, Configuration configuration) throws RepositoryException {
334 if (repo instanceof EditableRemoteRepository && repo.getContent() == null) {
335 EditableRemoteRepository editableRepo = (EditableRemoteRepository) repo;
336 editableRepo.setContent(repositoryContentFactory.getRemoteRepositoryContent(repo));
337 if (repo.supportsFeature(IndexCreationFeature.class) && repo.getIndexingContext() == null) {
338 createIndexingContext(editableRepo);
341 repo.registerEventHandler(RepositoryEvent.ANY, this);
344 private Map<String, RepositoryGroup> getRepositorGroupsFromConfig() {
346 List<RepositoryGroupConfiguration> repositoryGroupConfigurations =
347 getArchivaConfiguration().getConfiguration().getRepositoryGroups();
349 if (repositoryGroupConfigurations == null) {
350 return Collections.emptyMap();
353 Map<String, RepositoryGroup> repositoryGroupMap = new LinkedHashMap<>(repositoryGroupConfigurations.size());
355 Map<RepositoryType, RepositoryProvider> providerMap = createProviderMap();
356 for (RepositoryGroupConfiguration repoConfig : repositoryGroupConfigurations) {
357 RepositoryType repositoryType = RepositoryType.valueOf(repoConfig.getType());
358 if (providerMap.containsKey(repositoryType)) {
360 RepositoryGroup repo = createNewRepositoryGroup(providerMap.get(repositoryType), repoConfig);
361 repositoryGroupMap.put(repo.getId(), repo);
362 } catch (Exception e) {
363 log.error("Could not create repository group {}: {}", repoConfig.getId(), e.getMessage(), e);
367 return repositoryGroupMap;
368 } catch (Throwable e) {
369 log.error("Could not initialize repositories from config: {}", e.getMessage(), e);
370 return Collections.emptyMap();
374 private RepositoryGroup createNewRepositoryGroup(RepositoryProvider provider, RepositoryGroupConfiguration config) throws RepositoryException {
375 RepositoryGroup repositoryGroup = provider.createRepositoryGroup(config);
376 repositoryGroup.registerEventHandler(RepositoryEvent.ANY, this);
377 updateRepositoryReferences(provider, repositoryGroup, config);
378 return repositoryGroup;
381 private void updateRepositoryReferences(RepositoryProvider provider, RepositoryGroup group, RepositoryGroupConfiguration configuration) {
382 if (group instanceof EditableRepositoryGroup ) {
383 EditableRepositoryGroup eGroup = (EditableRepositoryGroup) group;
384 eGroup.setRepositories(configuration.getRepositories().stream().map(r -> getManagedRepository(r)).collect(Collectors.toList()));
388 private ArchivaConfiguration getArchivaConfiguration() {
389 return this.archivaConfiguration;
393 * Returns all repositories that are registered. There is no defined order of the returned repositories.
395 * @return a list of managed and remote repositories
398 public Collection<Repository> getRepositories( ) {
399 rwLock.readLock().lock();
401 return Stream.concat(managedRepositories.values().stream(), remoteRepositories.values().stream()).collect(Collectors.toList());
403 rwLock.readLock().unlock();
408 * Returns only the managed repositories. There is no defined order of the returned repositories.
410 * @return a list of managed repositories
413 public Collection<ManagedRepository> getManagedRepositories( ) {
414 rwLock.readLock().lock();
416 return uManagedRepository.values();
418 rwLock.readLock().unlock();
423 * Returns only the remote repositories. There is no defined order of the returned repositories.
425 * @return a list of remote repositories
428 public Collection<RemoteRepository> getRemoteRepositories( ) {
429 rwLock.readLock().lock();
431 return uRemoteRepositories.values();
433 rwLock.readLock().unlock();
438 public Collection<RepositoryGroup> getRepositoryGroups( ) {
439 rwLock.readLock().lock();
441 return uRepositoryGroups.values();
443 rwLock.readLock().unlock();
448 * Returns the repository with the given id. The returned repository may be a managed or remote repository.
449 * It returns null, if no repository is registered with the given id.
451 * @param repoId the repository id
452 * @return the repository if found, otherwise null
455 public Repository getRepository( String repoId ) {
456 rwLock.readLock().lock();
458 log.debug("getRepository {}", repoId);
459 if (managedRepositories.containsKey(repoId)) {
460 log.debug("Managed repo");
461 return managedRepositories.get(repoId);
462 } else if (remoteRepositories.containsKey(repoId)) {
463 log.debug("Remote repo");
464 return remoteRepositories.get(repoId);
465 } else if (repositoryGroups.containsKey(repoId)) {
466 return repositoryGroups.get(repoId);
471 rwLock.readLock().unlock();
476 * Convenience method, that returns the managed repository with the given id.
477 * It returns null, if no managed repository is registered with this id.
479 * @param repoId the repository id
480 * @return the managed repository if found, otherwise null
483 public ManagedRepository getManagedRepository( String repoId ) {
484 rwLock.readLock().lock();
486 return managedRepositories.get(repoId);
488 rwLock.readLock().unlock();
493 * Convenience method, that returns the remote repository with the given id.
494 * It returns null, if no remote repository is registered with this id.
496 * @param repoId the repository id
497 * @return the remote repository if found, otherwise null
500 public RemoteRepository getRemoteRepository( String repoId ) {
501 rwLock.readLock().lock();
503 return remoteRepositories.get(repoId);
505 rwLock.readLock().unlock();
510 public RepositoryGroup getRepositoryGroup( String groupId ) {
511 rwLock.readLock().lock();
513 return repositoryGroups.get(groupId);
515 rwLock.readLock().unlock();
520 * The <code>ignoreConfigEvents</code> works only for synchronized configuration events.
521 * If the configuration throws async events, we cannot know, if the event is caused by this instance or another thread.
523 private void saveConfiguration(Configuration configuration) throws IndeterminateConfigurationException, RegistryException {
524 ignoreConfigEvents = true;
526 getArchivaConfiguration().save(configuration);
528 ignoreConfigEvents = false;
533 * Adds a new repository to the current list, or replaces the repository definition with
534 * the same id, if it exists already.
535 * The change is saved to the configuration immediately.
537 * @param managedRepository the new repository.
538 * @throws RepositoryException if the new repository could not be saved to the configuration.
541 public ManagedRepository putRepository( ManagedRepository managedRepository ) throws RepositoryException {
542 rwLock.writeLock().lock();
544 final String id = managedRepository.getId();
545 if (remoteRepositories.containsKey(id)) {
546 throw new RepositoryException("There exists a remote repository with id " + id + ". Could not update with managed repository.");
548 ManagedRepository originRepo = managedRepositories.put(id, managedRepository);
550 if (originRepo != null && originRepo != managedRepository) {
553 RepositoryProvider provider = getProvider(managedRepository.getType());
554 ManagedRepositoryConfiguration newCfg = provider.getManagedConfiguration(managedRepository);
555 Configuration configuration = getArchivaConfiguration().getConfiguration();
556 updateRepositoryReferences(provider, managedRepository, newCfg, configuration);
557 ManagedRepositoryConfiguration oldCfg = configuration.findManagedRepositoryById(id);
558 if (oldCfg != null) {
559 configuration.removeManagedRepository(oldCfg);
561 configuration.addManagedRepository(newCfg);
562 saveConfiguration(configuration);
563 if (originRepo != managedRepository) {
564 pushEvent(new LifecycleEvent(LifecycleEvent.REGISTERED, this, managedRepository));
566 pushEvent(new LifecycleEvent(LifecycleEvent.UPDATED, this, managedRepository));
568 return managedRepository;
569 } catch (Exception e) {
570 // Rollback only partly, because repository is closed already
571 if (originRepo != null) {
572 managedRepositories.put(id, originRepo);
574 managedRepositories.remove(id);
576 log.error("Exception during configuration update {}", e.getMessage(), e);
577 throw new RepositoryException("Could not save the configuration" + (e.getMessage() == null ? "" : ": " + e.getMessage()));
580 rwLock.writeLock().unlock();
585 * Adds a new repository or updates the repository with the same id, if it exists already.
586 * The configuration is saved immediately.
588 * @param managedRepositoryConfiguration the repository configuration
589 * @return the updated or created repository
590 * @throws RepositoryException if an error occurs, or the configuration is not valid.
593 public ManagedRepository putRepository( ManagedRepositoryConfiguration managedRepositoryConfiguration ) throws RepositoryException {
594 rwLock.writeLock().lock();
596 final String id = managedRepositoryConfiguration.getId();
597 final RepositoryType repositoryType = RepositoryType.valueOf(managedRepositoryConfiguration.getType());
598 Configuration configuration = getArchivaConfiguration().getConfiguration();
599 ManagedRepository repo = managedRepositories.get(id);
600 ManagedRepositoryConfiguration oldCfg = repo != null ? getProvider(repositoryType).getManagedConfiguration(repo) : null;
601 repo = putRepository(managedRepositoryConfiguration, configuration);
603 saveConfiguration(configuration);
604 } catch (IndeterminateConfigurationException | RegistryException e) {
605 if (oldCfg != null) {
606 getProvider(repositoryType).updateManagedInstance((EditableManagedRepository) repo, oldCfg);
608 log.error("Could not save the configuration for repository {}: {}", id, e.getMessage(), e);
609 throw new RepositoryException("Could not save the configuration for repository " + id + ": " + e.getMessage());
613 rwLock.writeLock().unlock();
619 * Adds a new repository or updates the repository with the same id. The given configuration object is updated, but
620 * the configuration is not saved.
622 * @param managedRepositoryConfiguration the new or changed managed repository configuration
623 * @param configuration the configuration object (may be <code>null</code>)
624 * @return the new or updated repository
625 * @throws RepositoryException if the configuration cannot be saved or updated
628 public ManagedRepository putRepository( ManagedRepositoryConfiguration managedRepositoryConfiguration, Configuration configuration ) throws RepositoryException {
629 rwLock.writeLock().lock();
631 final String id = managedRepositoryConfiguration.getId();
632 final RepositoryType repoType = RepositoryType.valueOf(managedRepositoryConfiguration.getType());
633 ManagedRepository repo;
634 boolean registeredNew = false;
635 repo = managedRepositories.get(id);
636 if (repo != null && repo.isOpen()) {
637 if (repo instanceof EditableManagedRepository) {
638 getProvider(repoType).updateManagedInstance((EditableManagedRepository) repo, managedRepositoryConfiguration);
640 throw new RepositoryException("The repository is not editable " + id);
643 repo = getProvider(repoType).createManagedInstance(managedRepositoryConfiguration);
644 managedRepositories.put(id, repo);
645 registeredNew = true;
647 updateRepositoryReferences(getProvider(repoType), repo, managedRepositoryConfiguration, configuration);
648 replaceOrAddRepositoryConfig(managedRepositoryConfiguration, configuration);
650 pushEvent(new LifecycleEvent(LifecycleEvent.REGISTERED, this, repo));
652 pushEvent(new LifecycleEvent(LifecycleEvent.UPDATED, this, repo));
656 rwLock.writeLock().unlock();
662 * Adds a new repository group to the current list, or replaces the repository group definition with
663 * the same id, if it exists already.
664 * The change is saved to the configuration immediately.
666 * @param repositoryGroup the new repository group.
667 * @throws RepositoryException if the new repository group could not be saved to the configuration.
670 public RepositoryGroup putRepositoryGroup( RepositoryGroup repositoryGroup ) throws RepositoryException {
671 rwLock.writeLock().lock();
673 final String id = repositoryGroup.getId();
674 RepositoryGroup originRepoGroup = repositoryGroups.put(id, repositoryGroup);
676 if (originRepoGroup != null && originRepoGroup != repositoryGroup) {
677 originRepoGroup.close();
679 RepositoryProvider provider = getProvider(repositoryGroup.getType());
680 RepositoryGroupConfiguration newCfg = provider.getRepositoryGroupConfiguration(repositoryGroup);
681 Configuration configuration = getArchivaConfiguration().getConfiguration();
682 updateRepositoryReferences(provider, repositoryGroup, newCfg);
683 RepositoryGroupConfiguration oldCfg = configuration.findRepositoryGroupById(id);
684 if (oldCfg != null) {
685 configuration.removeRepositoryGroup(oldCfg);
687 configuration.addRepositoryGroup(newCfg);
688 saveConfiguration(configuration);
689 return repositoryGroup;
690 } catch (Exception e) {
692 if (originRepoGroup != null) {
693 repositoryGroups.put(id, originRepoGroup);
695 repositoryGroups.remove(id);
697 log.error("Exception during configuration update {}", e.getMessage(), e);
698 throw new RepositoryException("Could not save the configuration" + (e.getMessage() == null ? "" : ": " + e.getMessage()));
701 rwLock.writeLock().unlock();
706 * Adds a new repository group or updates the repository with the same id, if it exists already.
707 * The configuration is saved immediately.
709 * @param repositoryGroupConfiguration the repository configuration
710 * @return the updated or created repository
711 * @throws RepositoryException if an error occurs, or the configuration is not valid.
714 public RepositoryGroup putRepositoryGroup( RepositoryGroupConfiguration repositoryGroupConfiguration ) throws RepositoryException {
715 rwLock.writeLock().lock();
717 final String id = repositoryGroupConfiguration.getId();
718 final RepositoryType repositoryType = RepositoryType.valueOf(repositoryGroupConfiguration.getType());
719 Configuration configuration = getArchivaConfiguration().getConfiguration();
720 RepositoryGroup repo = repositoryGroups.get(id);
721 RepositoryGroupConfiguration oldCfg = repo != null ? getProvider(repositoryType).getRepositoryGroupConfiguration(repo) : null;
722 repo = putRepositoryGroup(repositoryGroupConfiguration, configuration);
724 saveConfiguration(configuration);
725 } catch (IndeterminateConfigurationException | RegistryException e) {
726 if (oldCfg != null) {
727 getProvider(repositoryType).updateRepositoryGroupInstance((EditableRepositoryGroup) repo, oldCfg);
729 log.error("Could not save the configuration for repository group {}: {}", id, e.getMessage(), e);
730 throw new RepositoryException("Could not save the configuration for repository group " + id + ": " + e.getMessage());
734 rwLock.writeLock().unlock();
740 * Adds a new repository group or updates the repository group with the same id. The given configuration object is updated, but
741 * the configuration is not saved.
743 * @param repositoryGroupConfiguration The configuration of the new or changed repository group.
744 * @param configuration The configuration object. If it is <code>null</code>, the configuration is not saved.
745 * @return The new or updated repository group
746 * @throws RepositoryException if the configuration cannot be saved or updated
749 public RepositoryGroup putRepositoryGroup( RepositoryGroupConfiguration repositoryGroupConfiguration, Configuration configuration ) throws RepositoryException {
750 rwLock.writeLock().lock();
752 final String id = repositoryGroupConfiguration.getId();
753 final RepositoryType repoType = RepositoryType.valueOf(repositoryGroupConfiguration.getType());
754 RepositoryGroup repo;
755 setRepositoryGroupDefaults(repositoryGroupConfiguration);
756 if (repositoryGroups.containsKey(id)) {
757 repo = repositoryGroups.get(id);
758 if (repo instanceof EditableRepositoryGroup) {
759 getProvider(repoType).updateRepositoryGroupInstance((EditableRepositoryGroup) repo, repositoryGroupConfiguration);
761 throw new RepositoryException("The repository is not editable " + id);
764 repo = getProvider(repoType).createRepositoryGroup(repositoryGroupConfiguration);
765 repositoryGroups.put(id, repo);
767 updateRepositoryReferences(getProvider(repoType), repo, repositoryGroupConfiguration);
768 replaceOrAddRepositoryConfig(repositoryGroupConfiguration, configuration);
771 rwLock.writeLock().unlock();
775 private void setRepositoryGroupDefaults(RepositoryGroupConfiguration repositoryGroupConfiguration) {
776 if (StringUtils.isEmpty(repositoryGroupConfiguration.getMergedIndexPath())) {
777 repositoryGroupConfiguration.setMergedIndexPath(DEFAULT_INDEX_PATH);
779 if (repositoryGroupConfiguration.getMergedIndexTtl() <= 0) {
780 repositoryGroupConfiguration.setMergedIndexTtl(300);
782 if (StringUtils.isEmpty(repositoryGroupConfiguration.getCronExpression())) {
783 repositoryGroupConfiguration.setCronExpression("0 0 03 ? * MON");
787 private void replaceOrAddRepositoryConfig(ManagedRepositoryConfiguration managedRepositoryConfiguration, Configuration configuration) {
788 if (configuration != null) {
789 ManagedRepositoryConfiguration oldCfg = configuration.findManagedRepositoryById(managedRepositoryConfiguration.getId());
790 if (oldCfg != null) {
791 configuration.removeManagedRepository(oldCfg);
793 configuration.addManagedRepository(managedRepositoryConfiguration);
797 private void replaceOrAddRepositoryConfig(RemoteRepositoryConfiguration remoteRepositoryConfiguration, Configuration configuration) {
798 if (configuration != null) {
799 RemoteRepositoryConfiguration oldCfg = configuration.findRemoteRepositoryById(remoteRepositoryConfiguration.getId());
800 if (oldCfg != null) {
801 configuration.removeRemoteRepository(oldCfg);
803 configuration.addRemoteRepository(remoteRepositoryConfiguration);
807 private void replaceOrAddRepositoryConfig(RepositoryGroupConfiguration repositoryGroupConfiguration, Configuration configuration) {
808 RepositoryGroupConfiguration oldCfg = configuration.findRepositoryGroupById(repositoryGroupConfiguration.getId());
809 if (oldCfg != null) {
810 configuration.removeRepositoryGroup(oldCfg);
812 configuration.addRepositoryGroup(repositoryGroupConfiguration);
816 public RemoteRepository putRepository( RemoteRepository remoteRepository, Configuration configuration ) throws RepositoryException {
817 rwLock.writeLock().lock();
819 final String id = remoteRepository.getId();
820 if (managedRepositories.containsKey(id)) {
821 throw new RepositoryException("There exists a managed repository with id " + id + ". Could not update with remote repository.");
823 RemoteRepository originRepo = remoteRepositories.put(id, remoteRepository);
824 RemoteRepositoryConfiguration oldCfg = null;
825 RemoteRepositoryConfiguration newCfg;
827 if (originRepo != null && originRepo != remoteRepository) {
830 final RepositoryProvider provider = getProvider(remoteRepository.getType());
831 newCfg = provider.getRemoteConfiguration(remoteRepository);
832 updateRepositoryReferences(provider, remoteRepository, newCfg, configuration);
833 oldCfg = configuration.findRemoteRepositoryById(id);
834 if (oldCfg != null) {
835 configuration.removeRemoteRepository(oldCfg);
837 configuration.addRemoteRepository(newCfg);
838 if (remoteRepository != originRepo) {
839 pushEvent(new LifecycleEvent(LifecycleEvent.REGISTERED, this, remoteRepository));
841 pushEvent(new LifecycleEvent(LifecycleEvent.UPDATED, this, remoteRepository));
843 return remoteRepository;
844 } catch (Exception e) {
846 if (originRepo != null) {
847 remoteRepositories.put(id, originRepo);
849 remoteRepositories.remove(id);
851 if (oldCfg != null) {
852 RemoteRepositoryConfiguration cfg = configuration.findRemoteRepositoryById(id);
854 configuration.removeRemoteRepository(cfg);
855 configuration.addRemoteRepository(oldCfg);
858 log.error("Error while adding remote repository {}", e.getMessage(), e);
859 throw new RepositoryException("Could not save the configuration" + (e.getMessage() == null ? "" : ": " + e.getMessage()));
862 rwLock.writeLock().unlock();
867 * Adds a remote repository, or overwrites the repository definition with the same id, if it exists already.
868 * The modification is saved to the configuration immediately.
870 * @param remoteRepository the remote repository to add
871 * @throws RepositoryException if an error occurs during configuration save
874 public RemoteRepository putRepository( RemoteRepository remoteRepository ) throws RepositoryException {
875 rwLock.writeLock().lock();
877 Configuration configuration = getArchivaConfiguration().getConfiguration();
879 RemoteRepository repo = putRepository(remoteRepository, configuration);
880 saveConfiguration(configuration);
882 } catch (RegistryException | IndeterminateConfigurationException e) {
883 log.error("Error while saving remote repository {}", e.getMessage(), e);
884 throw new RepositoryException("Could not save the configuration" + (e.getMessage() == null ? "" : ": " + e.getMessage()));
887 rwLock.writeLock().unlock();
892 * Adds a new repository or updates the repository with the same id, if it exists already.
893 * The configuration is saved immediately.
895 * @param remoteRepositoryConfiguration the repository configuration
896 * @return the updated or created repository
897 * @throws RepositoryException if an error occurs, or the configuration is not valid.
900 public RemoteRepository putRepository( RemoteRepositoryConfiguration remoteRepositoryConfiguration ) throws RepositoryException {
901 rwLock.writeLock().lock();
903 final String id = remoteRepositoryConfiguration.getId();
904 final RepositoryType repositoryType = RepositoryType.valueOf(remoteRepositoryConfiguration.getType());
905 Configuration configuration = getArchivaConfiguration().getConfiguration();
906 RemoteRepository repo = remoteRepositories.get(id);
907 RemoteRepositoryConfiguration oldCfg = repo != null ? getProvider(repositoryType).getRemoteConfiguration(repo) : null;
908 repo = putRepository(remoteRepositoryConfiguration, configuration);
910 saveConfiguration(configuration);
911 } catch (IndeterminateConfigurationException | RegistryException e) {
912 if (oldCfg != null) {
913 getProvider(repositoryType).updateRemoteInstance((EditableRemoteRepository) repo, oldCfg);
915 log.error("Could not save the configuration for repository {}: {}", id, e.getMessage(), e);
916 throw new RepositoryException("Could not save the configuration for repository " + id + ": " + e.getMessage());
920 rwLock.writeLock().unlock();
926 * Adds a new repository or updates the repository with the same id. The given configuration object is updated, but
927 * the configuration is not saved.
929 * @param remoteRepositoryConfiguration the new or changed repository configuration
930 * @param configuration the configuration object
931 * @return the new or updated repository
932 * @throws RepositoryException if the configuration cannot be saved or updated
935 @SuppressWarnings("unchecked")
936 public RemoteRepository putRepository( RemoteRepositoryConfiguration remoteRepositoryConfiguration, Configuration configuration ) throws RepositoryException {
937 rwLock.writeLock().lock();
939 final String id = remoteRepositoryConfiguration.getId();
940 final RepositoryType repoType = RepositoryType.valueOf(remoteRepositoryConfiguration.getType());
941 RemoteRepository repo;
942 boolean registeredNew = false;
943 repo = remoteRepositories.get(id);
944 if (repo != null && repo.isOpen()) {
945 if (repo instanceof EditableRemoteRepository) {
946 getProvider(repoType).updateRemoteInstance((EditableRemoteRepository) repo, remoteRepositoryConfiguration);
948 throw new RepositoryException("The repository is not editable " + id);
951 repo = getProvider(repoType).createRemoteInstance(remoteRepositoryConfiguration);
952 remoteRepositories.put(id, repo);
953 registeredNew = true;
955 updateRepositoryReferences(getProvider(repoType), repo, remoteRepositoryConfiguration, configuration);
956 replaceOrAddRepositoryConfig(remoteRepositoryConfiguration, configuration);
958 pushEvent(new LifecycleEvent(LifecycleEvent.REGISTERED, this, repo));
960 pushEvent(new LifecycleEvent(LifecycleEvent.UPDATED, this, repo));
964 rwLock.writeLock().unlock();
971 public void removeRepository( String repoId ) throws RepositoryException {
972 Repository repo = getRepository(repoId);
974 removeRepository(repo);
979 public void removeRepository( Repository repo ) throws RepositoryException {
981 log.warn("Trying to remove null repository");
984 if (repo instanceof RemoteRepository) {
985 removeRepository((RemoteRepository) repo);
986 } else if (repo instanceof ManagedRepository) {
987 removeRepository((ManagedRepository) repo);
988 } else if (repo instanceof RepositoryGroup) {
989 removeRepositoryGroup((RepositoryGroup) repo);
991 throw new RepositoryException("Repository type not known: " + repo.getClass());
996 * Removes a managed repository from the registry and configuration, if it exists.
997 * The change is saved to the configuration immediately.
999 * @param managedRepository the managed repository to remove
1000 * @throws RepositoryException if a error occurs during configuration save
1003 public void removeRepository( ManagedRepository managedRepository ) throws RepositoryException {
1004 if (managedRepository == null) {
1007 final String id = managedRepository.getId();
1008 ManagedRepository repo = getManagedRepository(id);
1010 rwLock.writeLock().lock();
1012 repo = managedRepositories.remove(id);
1015 removeRepositoryFromGroups(repo);
1016 Configuration configuration = getArchivaConfiguration().getConfiguration();
1017 ManagedRepositoryConfiguration cfg = configuration.findManagedRepositoryById(id);
1019 configuration.removeManagedRepository(cfg);
1021 saveConfiguration(configuration);
1023 pushEvent(new LifecycleEvent(LifecycleEvent.UNREGISTERED, this, repo));
1024 } catch (RegistryException | IndeterminateConfigurationException e) {
1026 log.error("Could not save config after repository removal: {}", e.getMessage(), e);
1027 managedRepositories.put(repo.getId(), repo);
1028 throw new RepositoryException("Could not save configuration after repository removal: " + e.getMessage());
1030 rwLock.writeLock().unlock();
1035 private void removeRepositoryFromGroups(ManagedRepository repo) {
1037 repositoryGroups.values().stream().filter(repoGroup -> repoGroup instanceof EditableRepository).
1038 map(repoGroup -> (EditableRepositoryGroup) repoGroup).forEach(repoGroup -> repoGroup.removeRepository(repo));
1043 public void removeRepository( ManagedRepository managedRepository, Configuration configuration ) throws RepositoryException {
1044 if (managedRepository == null) {
1047 final String id = managedRepository.getId();
1048 ManagedRepository repo = getManagedRepository(id);
1050 rwLock.writeLock().lock();
1052 repo = managedRepositories.remove(id);
1055 removeRepositoryFromGroups(repo);
1056 ManagedRepositoryConfiguration cfg = configuration.findManagedRepositoryById(id);
1058 configuration.removeManagedRepository(cfg);
1061 pushEvent(new LifecycleEvent(LifecycleEvent.UNREGISTERED, this, repo));
1063 rwLock.writeLock().unlock();
1071 * Removes a repository group from the registry and configuration, if it exists.
1072 * The change is saved to the configuration immediately.
1074 * @param repositoryGroup the repository group to remove
1075 * @throws RepositoryException if a error occurs during configuration save
1078 public void removeRepositoryGroup( RepositoryGroup repositoryGroup ) throws RepositoryException {
1079 if (repositoryGroup == null) {
1082 final String id = repositoryGroup.getId();
1083 RepositoryGroup repo = getRepositoryGroup(id);
1085 rwLock.writeLock().lock();
1087 repo = repositoryGroups.remove(id);
1090 Configuration configuration = getArchivaConfiguration().getConfiguration();
1091 RepositoryGroupConfiguration cfg = configuration.findRepositoryGroupById(id);
1093 configuration.removeRepositoryGroup(cfg);
1095 saveConfiguration(configuration);
1098 } catch (RegistryException | IndeterminateConfigurationException e) {
1100 log.error("Could not save config after repository removal: {}", e.getMessage(), e);
1101 repositoryGroups.put(repo.getId(), repo);
1102 throw new RepositoryException("Could not save configuration after repository removal: " + e.getMessage());
1104 rwLock.writeLock().unlock();
1110 public void removeRepositoryGroup( RepositoryGroup repositoryGroup, Configuration configuration ) throws RepositoryException {
1111 if (repositoryGroup == null) {
1114 final String id = repositoryGroup.getId();
1115 RepositoryGroup repo = getRepositoryGroup(id);
1117 rwLock.writeLock().lock();
1119 repo = repositoryGroups.remove(id);
1122 RepositoryGroupConfiguration cfg = configuration.findRepositoryGroupById(id);
1124 configuration.removeRepositoryGroup(cfg);
1128 rwLock.writeLock().unlock();
1134 private void doRemoveRepo(RemoteRepository repo, Configuration configuration) {
1136 RemoteRepositoryConfiguration cfg = configuration.findRemoteRepositoryById(repo.getId());
1138 configuration.removeRemoteRepository(cfg);
1140 List<ProxyConnectorConfiguration> proxyConnectors = new ArrayList<>(configuration.getProxyConnectors());
1141 for (ProxyConnectorConfiguration proxyConnector : proxyConnectors) {
1142 if (StringUtils.equals(proxyConnector.getTargetRepoId(), repo.getId())) {
1143 configuration.removeProxyConnector(proxyConnector);
1149 * Removes the remote repository from the registry and configuration.
1150 * The change is saved to the configuration immediately.
1152 * @param remoteRepository the remote repository to remove
1153 * @throws RepositoryException if a error occurs during configuration save
1156 public void removeRepository( RemoteRepository remoteRepository ) throws RepositoryException {
1157 if (remoteRepository == null) {
1160 final String id = remoteRepository.getId();
1161 RemoteRepository repo = getRemoteRepository(id);
1163 rwLock.writeLock().lock();
1165 repo = remoteRepositories.remove(id);
1167 Configuration configuration = getArchivaConfiguration().getConfiguration();
1168 doRemoveRepo(repo, configuration);
1169 saveConfiguration(configuration);
1171 pushEvent(new LifecycleEvent(LifecycleEvent.UNREGISTERED, this, repo));
1172 } catch (RegistryException | IndeterminateConfigurationException e) {
1174 log.error("Could not save config after repository removal: {}", e.getMessage(), e);
1175 remoteRepositories.put(repo.getId(), repo);
1176 throw new RepositoryException("Could not save configuration after repository removal: " + e.getMessage());
1178 rwLock.writeLock().unlock();
1184 public void removeRepository( RemoteRepository remoteRepository, Configuration configuration ) throws RepositoryException {
1185 if (remoteRepository == null) {
1188 final String id = remoteRepository.getId();
1189 RemoteRepository repo = getRemoteRepository(id);
1191 rwLock.writeLock().lock();
1193 repo = remoteRepositories.remove(id);
1195 doRemoveRepo(repo, configuration);
1197 pushEvent(new LifecycleEvent(LifecycleEvent.UNREGISTERED, this, repo));
1199 rwLock.writeLock().unlock();
1206 * Reloads the registry from the configuration.
1209 public void reload( ) {
1214 * Resets the indexing context of a given repository.
1216 * @param repository The repository
1217 * @throws IndexUpdateFailedException If the index could not be resetted.
1220 public void resetIndexingContext( Repository repository ) throws IndexUpdateFailedException {
1221 if (repository.hasIndex() && repository instanceof EditableRepository) {
1222 EditableRepository eRepo = (EditableRepository) repository;
1223 ArchivaIndexingContext newCtx = getIndexManager(repository.getType()).reset(repository.getIndexingContext());
1224 eRepo.setIndexingContext(newCtx);
1230 * Creates a new repository instance with the same settings as this one. The cloned repository is not
1231 * registered or saved to the configuration.
1233 * @param repo The origin repository
1234 * @return The cloned repository.
1237 public ManagedRepository clone( ManagedRepository repo, String newId ) throws RepositoryException {
1238 if (managedRepositories.containsKey(newId) || remoteRepositories.containsKey(newId)) {
1239 throw new RepositoryException("The given id exists already " + newId);
1241 RepositoryProvider provider = getProvider(repo.getType());
1242 ManagedRepositoryConfiguration cfg = provider.getManagedConfiguration(repo);
1244 ManagedRepository cloned = provider.createManagedInstance(cfg);
1245 cloned.registerEventHandler(RepositoryEvent.ANY, this);
1250 public <T extends Repository> Repository clone( T repo, String newId ) throws RepositoryException {
1251 if (repo instanceof RemoteRepository) {
1252 return this.clone((RemoteRepository) repo, newId);
1253 } else if (repo instanceof ManagedRepository) {
1254 return this.clone((ManagedRepository) repo, newId);
1256 throw new RepositoryException("This repository class is not supported " + repo.getClass().getName());
1261 * Creates a new repository instance with the same settings as this one. The cloned repository is not
1262 * registered or saved to the configuration.
1264 * @param repo The origin repository
1265 * @return The cloned repository.
1268 public RemoteRepository clone( RemoteRepository repo, String newId ) throws RepositoryException {
1269 if (managedRepositories.containsKey(newId) || remoteRepositories.containsKey(newId)) {
1270 throw new RepositoryException("The given id exists already " + newId);
1272 RepositoryProvider provider = getProvider(repo.getType());
1273 RemoteRepositoryConfiguration cfg = provider.getRemoteConfiguration(repo);
1275 RemoteRepository cloned = provider.createRemoteInstance(cfg);
1276 cloned.registerEventHandler(RepositoryEvent.ANY, this);
1281 public Repository getRepositoryOfAsset( StorageAsset asset )
1283 if (asset instanceof Repository) {
1284 return (Repository)asset;
1287 return getRepositories( ).stream( ).filter( r -> r.getRoot()
1288 .getStorage( ).equals( asset.getStorage( ) ) ).findFirst( ).orElse( null );
1294 public void configurationEvent(ConfigurationEvent event) {
1295 // Note: the ignoreConfigEvents flag does not work, if the config events are asynchronous.
1296 if (!ignoreConfigEvents) {
1303 public <T extends Event> void registerEventHandler( EventType<T> type, EventHandler<? super T> eventHandler) {
1304 eventManager.registerEventHandler(type, eventHandler);
1309 public <T extends Event> void unregisterEventHandler(EventType<T> type, EventHandler<? super T> eventHandler) {
1310 eventManager.unregisterEventHandler(type, eventHandler);
1315 public void handle(Event event) {
1316 // To avoid event cycles:
1317 if (sameOriginator(event)) {
1320 if (event instanceof RepositoryIndexEvent) {
1321 handleIndexCreationEvent((RepositoryIndexEvent) event);
1323 // We propagate all events to our listeners, but with context of repository registry
1327 private void handleIndexCreationEvent(RepositoryIndexEvent event) {
1328 RepositoryIndexEvent idxEvent = event;
1329 if (managedRepositories.containsKey(idxEvent.getRepository().getId()) ||
1330 remoteRepositories.containsKey(idxEvent.getRepository().getId())) {
1331 EditableRepository repo = (EditableRepository) idxEvent.getRepository();
1332 if (repo != null && repo.getIndexingContext() != null) {
1334 ArchivaIndexManager idxmgr = getIndexManager(repo.getType());
1335 if (idxmgr != null) {
1336 ArchivaIndexingContext newCtx = idxmgr.move(repo.getIndexingContext(), repo);
1337 repo.setIndexingContext(newCtx);
1338 idxmgr.updateLocalIndexPath(repo);
1341 } catch (IndexCreationFailedException e) {
1342 log.error("Could not move index to new directory {}", e.getMessage(), e);
1348 private boolean sameOriginator(Event event) {
1349 if (event.getSource() == this) {
1351 } else if (event.hasPreviousEvent()) {
1352 return sameOriginator(event.getPreviousEvent());
1358 private void pushEvent(Event event) {
1359 eventManager.fireEvent(event);