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