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.components.registry.RegistryException;
23 import org.apache.archiva.configuration.ArchivaConfiguration;
24 import org.apache.archiva.configuration.Configuration;
25 import org.apache.archiva.configuration.ConfigurationEvent;
26 import org.apache.archiva.configuration.ConfigurationListener;
27 import org.apache.archiva.configuration.IndeterminateConfigurationException;
28 import org.apache.archiva.configuration.ManagedRepositoryConfiguration;
29 import org.apache.archiva.configuration.ProxyConnectorConfiguration;
30 import org.apache.archiva.configuration.RemoteRepositoryConfiguration;
31 import org.apache.archiva.configuration.RepositoryGroupConfiguration;
32 import org.apache.archiva.event.Event;
33 import org.apache.archiva.event.EventHandler;
34 import org.apache.archiva.event.EventManager;
35 import org.apache.archiva.event.EventType;
36 import org.apache.archiva.indexer.ArchivaIndexManager;
37 import org.apache.archiva.indexer.ArchivaIndexingContext;
38 import org.apache.archiva.indexer.IndexCreationFailedException;
39 import org.apache.archiva.indexer.IndexManagerFactory;
40 import org.apache.archiva.indexer.IndexUpdateFailedException;
41 import org.apache.archiva.repository.CheckedResult;
42 import org.apache.archiva.repository.EditableManagedRepository;
43 import org.apache.archiva.repository.EditableRemoteRepository;
44 import org.apache.archiva.repository.EditableRepository;
45 import org.apache.archiva.repository.ManagedRepository;
46 import org.apache.archiva.repository.RemoteRepository;
47 import org.apache.archiva.repository.Repository;
48 import org.apache.archiva.repository.RepositoryContentFactory;
49 import org.apache.archiva.repository.RepositoryException;
50 import org.apache.archiva.repository.RepositoryGroup;
51 import org.apache.archiva.repository.RepositoryProvider;
52 import org.apache.archiva.repository.RepositoryRegistry;
53 import org.apache.archiva.repository.RepositoryType;
54 import org.apache.archiva.repository.UnsupportedRepositoryTypeException;
55 import org.apache.archiva.repository.event.LifecycleEvent;
56 import org.apache.archiva.repository.event.RepositoryEvent;
57 import org.apache.archiva.repository.event.RepositoryIndexEvent;
58 import org.apache.archiva.repository.event.RepositoryRegistryEvent;
59 import org.apache.archiva.repository.features.IndexCreationFeature;
60 import org.apache.archiva.repository.features.StagingRepositoryFeature;
61 import org.apache.archiva.repository.metadata.MetadataReader;
62 import org.apache.archiva.repository.storage.StorageAsset;
63 import org.apache.archiva.repository.validation.RepositoryChecker;
64 import org.apache.archiva.repository.validation.RepositoryValidator;
65 import org.apache.archiva.repository.validation.ValidationError;
66 import org.apache.archiva.repository.validation.ValidationResponse;
67 import org.apache.commons.collections4.ListUtils;
68 import org.apache.commons.lang3.StringUtils;
69 import org.slf4j.Logger;
70 import org.slf4j.LoggerFactory;
71 import org.springframework.stereotype.Service;
73 import javax.annotation.PostConstruct;
74 import javax.annotation.PreDestroy;
75 import javax.inject.Inject;
76 import javax.inject.Named;
77 import java.util.ArrayList;
78 import java.util.Collection;
79 import java.util.Collections;
80 import java.util.HashMap;
81 import java.util.HashSet;
82 import java.util.List;
85 import java.util.TreeSet;
86 import java.util.concurrent.atomic.AtomicBoolean;
87 import java.util.concurrent.locks.ReentrantReadWriteLock;
88 import java.util.stream.Collectors;
89 import java.util.stream.Stream;
92 * Registry for repositories. This is the central entry point for repositories. It provides methods for
93 * retrieving, adding and removing repositories.
95 * The modification methods addXX and removeXX persist the changes immediately to the configuration. If the
96 * configuration save fails the changes are rolled back.
102 @Service( "repositoryRegistry" )
103 public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHandler<Event>,
107 private static final Logger log = LoggerFactory.getLogger( RepositoryRegistry.class );
110 * We inject all repository providers
113 List<RepositoryProvider> repositoryProviders;
116 IndexManagerFactory indexManagerFactory;
119 List<MetadataReader> metadataReaderList;
122 @Named( "repositoryContentFactory#default" )
123 RepositoryContentFactory repositoryContentFactory;
126 private final EventManager eventManager;
129 private Map<String, ManagedRepository> managedRepositories = new HashMap<>( );
130 private Map<String, ManagedRepository> uManagedRepository = Collections.unmodifiableMap( managedRepositories );
132 private Map<String, RemoteRepository> remoteRepositories = new HashMap<>( );
133 private Map<String, RemoteRepository> uRemoteRepositories = Collections.unmodifiableMap( remoteRepositories );
135 private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock( );
137 private RepositoryGroupHandler groupHandler;
138 private final Set<RepositoryValidator<? extends Repository>> validators;
139 private final RepositoryChecker<RepositoryGroup, Map<String, List<ValidationError>>> groupChecker;
140 private final RepositoryChecker<ManagedRepository, Map<String, List<ValidationError>>> managedChecker;
141 private final RepositoryChecker<RemoteRepository, Map<String, List<ValidationError>>> remoteChecker;
142 private final ConfigurationHandler configurationHandler;
145 private AtomicBoolean groups_initalized = new AtomicBoolean( false );
146 private AtomicBoolean managed_initialized = new AtomicBoolean( false );
147 private AtomicBoolean remote_initialized = new AtomicBoolean( false );
150 public ArchivaRepositoryRegistry( ConfigurationHandler configurationHandler, List<RepositoryValidator<? extends Repository>> validatorList )
152 this.eventManager = new EventManager( this );
153 this.configurationHandler = configurationHandler;
154 this.validators = initValidatorList( validatorList );
155 this.groupChecker = initChecker( RepositoryGroup.class );
156 this.managedChecker = initChecker( ManagedRepository.class );
157 this.remoteChecker = initChecker( RemoteRepository.class );
160 private <R extends Repository> RepositoryChecker<R, Map<String, List<ValidationError>>> initChecker(Class<R> clazz) {
161 return new RepositoryChecker<R, Map<String, List<ValidationError>>>( )
164 public CheckedResult<R, Map<String, List<ValidationError>>> apply( R repositoryGroup )
166 return this.apply( repositoryGroup );
170 public CheckedResult<R, Map<String, List<ValidationError>>> applyForUpdate( R repo )
172 return this.applyForUpdate( repo );
177 private Set<RepositoryValidator<? extends Repository>> initValidatorList( List<RepositoryValidator<? extends Repository>> validators )
179 TreeSet<RepositoryValidator<? extends Repository>> val = new TreeSet<>( );
180 for (RepositoryValidator<? extends Repository> validator : validators) {
181 val.add( validator );
187 public void setArchivaConfiguration( ArchivaConfiguration archivaConfiguration )
189 this.configurationHandler.setArchivaConfiguration( archivaConfiguration );
193 private void initialize( )
195 rwLock.writeLock( ).lock( );
198 log.debug( "Initializing repository registry" );
199 updateManagedRepositoriesFromConfig( );
200 pushEvent( new RepositoryRegistryEvent( RepositoryRegistryEvent.MANAGED_REPOS_INITIALIZED, this ) );
201 managed_initialized.set( true );
202 updateRemoteRepositoriesFromConfig( );
203 pushEvent( new RepositoryRegistryEvent( RepositoryRegistryEvent.REMOTE_REPOS_INITIALIZED, this ) );
204 remote_initialized.set( true );
206 initializeRepositoryGroups( );
208 for ( RepositoryProvider provider : repositoryProviders )
210 provider.addRepositoryEventHandler( this );
212 this.configurationHandler.addListener( this );
216 rwLock.writeLock( ).unlock( );
218 pushEvent( new RepositoryRegistryEvent( RepositoryRegistryEvent.RELOADED, this ) );
219 if ( managed_initialized.get( ) && remote_initialized.get( ) && groups_initalized.get( ) )
221 pushEvent( new RepositoryRegistryEvent( RepositoryRegistryEvent.INITIALIZED, this ) );
225 private void initializeRepositoryGroups( )
227 if ( this.groupHandler != null )
229 this.groupHandler.initializeFromConfig( );
230 this.groups_initalized.set( true );
231 pushEvent( new RepositoryRegistryEvent( RepositoryRegistryEvent.GROUPS_INITIALIZED, this ) );
235 public void registerGroupHandler( RepositoryGroupHandler groupHandler )
237 this.groupHandler = groupHandler;
238 initializeRepositoryGroups( );
239 if ( managed_initialized.get( ) && remote_initialized.get( ) && groups_initalized.get( ) )
241 pushEvent( new RepositoryRegistryEvent( RepositoryRegistryEvent.INITIALIZED, this ) );
247 public void destroy( )
249 for ( ManagedRepository rep : managedRepositories.values( ) )
253 managedRepositories.clear( );
254 for ( RemoteRepository repo : remoteRepositories.values( ) )
258 remoteRepositories.clear( );
259 groupHandler.close( );
260 pushEvent( new RepositoryRegistryEvent( RepositoryRegistryEvent.DESTROYED, this ) );
264 protected Map<RepositoryType, RepositoryProvider> getRepositoryProviderMap( )
266 Map<RepositoryType, RepositoryProvider> map = new HashMap<>( );
267 if ( repositoryProviders != null )
269 for ( RepositoryProvider provider : repositoryProviders )
271 for ( RepositoryType type : provider.provides( ) )
273 map.put( type, provider );
280 protected RepositoryProvider getProvider( RepositoryType type ) throws RepositoryException
282 return repositoryProviders.stream( ).filter( repositoryProvider -> repositoryProvider.provides( ).contains( type ) ).findFirst( ).orElseThrow( ( ) -> new RepositoryException( "Repository type cannot be handled: " + type ) );
286 * Updates the repositories
288 private void updateManagedRepositoriesFromConfig( )
293 Set<String> configRepoIds = new HashSet<>( );
294 List<ManagedRepositoryConfiguration> managedRepoConfigs =
295 configurationHandler.getBaseConfiguration( ).getManagedRepositories( );
297 if ( managedRepoConfigs == null )
302 for ( ManagedRepositoryConfiguration repoConfig : managedRepoConfigs )
304 ManagedRepository repo = putRepository( repoConfig, null );
305 configRepoIds.add( repoConfig.getId( ) );
306 if ( repo.supportsFeature( StagingRepositoryFeature.class ) )
308 StagingRepositoryFeature stagF = repo.getFeature( StagingRepositoryFeature.class ).get( );
309 if ( stagF.getStagingRepository( ) != null )
311 configRepoIds.add( stagF.getStagingRepository( ).getId( ) );
315 List<String> toRemove = managedRepositories.keySet( ).stream( ).filter( id -> !configRepoIds.contains( id ) ).collect( Collectors.toList( ) );
316 for ( String id : toRemove )
318 ManagedRepository removed = managedRepositories.remove( id );
322 catch ( Throwable e )
324 log.error( "Could not initialize repositories from config: {}", e.getMessage( ), e );
329 private ManagedRepository createNewManagedRepository( RepositoryProvider provider, ManagedRepositoryConfiguration cfg ) throws RepositoryException
331 log.debug( "Creating repo {}", cfg.getId( ) );
332 ManagedRepository repo = provider.createManagedInstance( cfg );
333 repo.registerEventHandler( RepositoryEvent.ANY, this );
334 updateRepositoryReferences( provider, repo, cfg, null );
339 private String getStagingId( String repoId )
341 return repoId + StagingRepositoryFeature.STAGING_REPO_POSTFIX;
344 @SuppressWarnings( "unchecked" )
345 private void updateRepositoryReferences( RepositoryProvider provider, ManagedRepository repo, ManagedRepositoryConfiguration cfg, Configuration configuration ) throws RepositoryException
347 log.debug( "Updating references of repo {}", repo.getId( ) );
348 if ( repo.supportsFeature( StagingRepositoryFeature.class ) )
350 StagingRepositoryFeature feature = repo.getFeature( StagingRepositoryFeature.class ).get( );
351 if ( feature.isStageRepoNeeded( ) && feature.getStagingRepository( ) == null )
353 ManagedRepository stageRepo = getManagedRepository( getStagingId( repo.getId( ) ) );
354 if ( stageRepo == null )
356 stageRepo = getStagingRepository( provider, cfg, configuration );
357 managedRepositories.put( stageRepo.getId( ), stageRepo );
358 if ( configuration != null )
360 replaceOrAddRepositoryConfig( provider.getManagedConfiguration( stageRepo ), configuration );
362 pushEvent( new LifecycleEvent( LifecycleEvent.REGISTERED, this, stageRepo ) );
364 feature.setStagingRepository( stageRepo );
367 if ( repo instanceof EditableManagedRepository )
369 EditableManagedRepository editableRepo = (EditableManagedRepository) repo;
370 if ( repo.getContent( ) == null )
372 editableRepo.setContent( repositoryContentFactory.getManagedRepositoryContent( repo ) );
373 editableRepo.getContent( ).setRepository( editableRepo );
375 log.debug( "Index repo: " + repo.hasIndex( ) );
376 if ( repo.hasIndex( ) && ( repo.getIndexingContext( ) == null || !repo.getIndexingContext( ).isOpen( ) ) )
378 log.debug( "Creating indexing context for {}", repo.getId( ) );
379 createIndexingContext( editableRepo );
382 repo.registerEventHandler( RepositoryEvent.ANY, this );
386 public ArchivaIndexManager getIndexManager( RepositoryType type )
388 return indexManagerFactory.getIndexManager( type );
392 public MetadataReader getMetadataReader( final RepositoryType type ) throws UnsupportedRepositoryTypeException
394 if ( metadataReaderList != null )
396 return metadataReaderList.stream( ).filter( mr -> mr.isValidForType( type ) ).findFirst( ).orElseThrow( ( ) -> new UnsupportedRepositoryTypeException( type ) );
400 throw new UnsupportedRepositoryTypeException( type );
404 private void createIndexingContext( EditableRepository editableRepo ) throws RepositoryException
406 if ( editableRepo.supportsFeature( IndexCreationFeature.class ) )
408 ArchivaIndexManager idxManager = getIndexManager( editableRepo.getType( ) );
411 editableRepo.setIndexingContext( idxManager.createContext( editableRepo ) );
412 idxManager.updateLocalIndexPath( editableRepo );
414 catch ( IndexCreationFailedException e )
416 throw new RepositoryException( "Could not create index for repository " + editableRepo.getId( ) + ": " + e.getMessage( ), e );
421 private ManagedRepository getStagingRepository( RepositoryProvider provider, ManagedRepositoryConfiguration baseRepoCfg, Configuration configuration ) throws RepositoryException
423 ManagedRepository stageRepo = getManagedRepository( getStagingId( baseRepoCfg.getId( ) ) );
424 if ( stageRepo == null )
426 stageRepo = provider.createStagingInstance( baseRepoCfg );
427 if ( stageRepo.supportsFeature( StagingRepositoryFeature.class ) )
429 stageRepo.getFeature( StagingRepositoryFeature.class ).get( ).setStageRepoNeeded( false );
431 ManagedRepositoryConfiguration stageCfg = provider.getManagedConfiguration( stageRepo );
432 updateRepositoryReferences( provider, stageRepo, stageCfg, configuration );
438 private void updateRemoteRepositoriesFromConfig( )
442 List<RemoteRepositoryConfiguration> remoteRepoConfigs =
443 configurationHandler.getBaseConfiguration( ).getRemoteRepositories( );
445 if ( remoteRepoConfigs == null )
449 Set<String> repoIds = new HashSet<>( );
450 for ( RemoteRepositoryConfiguration repoConfig : remoteRepoConfigs )
452 putRepository( repoConfig, null );
453 repoIds.add( repoConfig.getId( ) );
456 List<String> toRemove = remoteRepositories.keySet( ).stream( ).filter( id -> !repoIds.contains( id ) ).collect( Collectors.toList( ) );
457 for ( String id : toRemove )
459 RemoteRepository removed = remoteRepositories.remove( id );
464 catch ( Throwable e )
466 log.error( "Could not initialize remote repositories from config: {}", e.getMessage( ), e );
471 private RemoteRepository createNewRemoteRepository( RepositoryProvider provider, RemoteRepositoryConfiguration cfg ) throws RepositoryException
473 log.debug( "Creating remote repo {}", cfg.getId( ) );
474 RemoteRepository repo = provider.createRemoteInstance( cfg );
475 updateRepositoryReferences( provider, repo, cfg, null );
480 private void updateRepositoryReferences( RepositoryProvider provider, RemoteRepository repo, RemoteRepositoryConfiguration cfg, Configuration configuration ) throws RepositoryException
482 if ( repo instanceof EditableRemoteRepository && repo.getContent( ) == null )
484 EditableRemoteRepository editableRepo = (EditableRemoteRepository) repo;
485 editableRepo.setContent( repositoryContentFactory.getRemoteRepositoryContent( repo ) );
486 if ( repo.supportsFeature( IndexCreationFeature.class ) && repo.getIndexingContext( ) == null )
488 createIndexingContext( editableRepo );
491 repo.registerEventHandler( RepositoryEvent.ANY, this );
496 * Returns all repositories that are registered. There is no defined order of the returned repositories.
498 * @return a list of managed and remote repositories
501 public Collection<Repository> getRepositories( )
503 rwLock.readLock( ).lock( );
506 return Stream.concat( managedRepositories.values( ).stream( ), remoteRepositories.values( ).stream( ) ).collect( Collectors.toList( ) );
510 rwLock.readLock( ).unlock( );
515 * Returns only the managed repositories. There is no defined order of the returned repositories.
517 * @return a list of managed repositories
520 public Collection<ManagedRepository> getManagedRepositories( )
522 rwLock.readLock( ).lock( );
525 return uManagedRepository.values( );
529 rwLock.readLock( ).unlock( );
534 * Returns only the remote repositories. There is no defined order of the returned repositories.
536 * @return a list of remote repositories
539 public Collection<RemoteRepository> getRemoteRepositories( )
541 rwLock.readLock( ).lock( );
544 return uRemoteRepositories.values( );
548 rwLock.readLock( ).unlock( );
553 public Collection<RepositoryGroup> getRepositoryGroups( )
555 rwLock.readLock( ).lock( );
558 return groupHandler.getAll( );
562 rwLock.readLock( ).unlock( );
567 * Returns the repository with the given id. The returned repository may be a managed or remote repository.
568 * It returns null, if no repository is registered with the given id.
570 * @param repoId the repository id
571 * @return the repository if found, otherwise null
574 public Repository getRepository( String repoId )
576 rwLock.readLock( ).lock( );
579 log.debug( "getRepository {}", repoId );
580 if ( managedRepositories.containsKey( repoId ) )
582 log.debug( "Managed repo" );
583 return managedRepositories.get( repoId );
585 else if ( remoteRepositories.containsKey( repoId ) )
587 log.debug( "Remote repo" );
588 return remoteRepositories.get( repoId );
590 else if ( groupHandler.has( repoId ) )
592 return groupHandler.get( repoId );
601 rwLock.readLock( ).unlock( );
606 * Convenience method, that returns the managed repository with the given id.
607 * It returns null, if no managed repository is registered with this id.
609 * @param repoId the repository id
610 * @return the managed repository if found, otherwise null
613 public ManagedRepository getManagedRepository( String repoId )
615 rwLock.readLock( ).lock( );
618 return managedRepositories.get( repoId );
622 rwLock.readLock( ).unlock( );
627 * Convenience method, that returns the remote repository with the given id.
628 * It returns null, if no remote repository is registered with this id.
630 * @param repoId the repository id
631 * @return the remote repository if found, otherwise null
634 public RemoteRepository getRemoteRepository( String repoId )
636 rwLock.readLock( ).lock( );
639 return remoteRepositories.get( repoId );
643 rwLock.readLock( ).unlock( );
648 public RepositoryGroup getRepositoryGroup( String groupId )
650 rwLock.readLock( ).lock( );
653 return groupHandler.get( groupId );
657 rwLock.readLock( ).unlock( );
662 public boolean hasRepository( String repoId )
664 return this.managedRepositories.containsKey( repoId ) || this.remoteRepositories.containsKey( repoId ) || groupHandler.has( repoId );
668 public boolean hasManagedRepository( String repoId )
670 return this.managedRepositories.containsKey( repoId );
674 public boolean hasRemoteRepository( String repoId )
676 return this.remoteRepositories.containsKey( repoId );
680 public boolean hasRepositoryGroup( String groupId )
682 return groupHandler.has( groupId );
685 protected void saveConfiguration( Configuration configuration ) throws IndeterminateConfigurationException, RegistryException
687 configurationHandler.save( configuration, ConfigurationHandler.REGISTRY_EVENT_TAG );
691 * Adds a new repository to the current list, or replaces the repository definition with
692 * the same id, if it exists already.
693 * The change is saved to the configuration immediately.
695 * @param managedRepository the new repository.
696 * @throws RepositoryException if the new repository could not be saved to the configuration.
699 public ManagedRepository putRepository( ManagedRepository managedRepository ) throws RepositoryException
701 rwLock.writeLock( ).lock( );
704 final String id = managedRepository.getId( );
705 if ( remoteRepositories.containsKey( id ) )
707 throw new RepositoryException( "There exists a remote repository with id " + id + ". Could not update with managed repository." );
709 ManagedRepository originRepo = managedRepositories.put( id, managedRepository );
712 if ( originRepo != null && originRepo != managedRepository )
716 RepositoryProvider provider = getProvider( managedRepository.getType( ) );
717 ManagedRepositoryConfiguration newCfg = provider.getManagedConfiguration( managedRepository );
718 Configuration configuration = configurationHandler.getBaseConfiguration( );
719 updateRepositoryReferences( provider, managedRepository, newCfg, configuration );
720 ManagedRepositoryConfiguration oldCfg = configuration.findManagedRepositoryById( id );
721 if ( oldCfg != null )
723 configuration.removeManagedRepository( oldCfg );
725 configuration.addManagedRepository( newCfg );
726 saveConfiguration( configuration );
727 if ( originRepo != managedRepository )
729 pushEvent( new LifecycleEvent( LifecycleEvent.REGISTERED, this, managedRepository ) );
733 pushEvent( new LifecycleEvent( LifecycleEvent.UPDATED, this, managedRepository ) );
735 return managedRepository;
737 catch ( Exception e )
739 // Rollback only partly, because repository is closed already
740 if ( originRepo != null )
742 managedRepositories.put( id, originRepo );
746 managedRepositories.remove( id );
748 log.error( "Exception during configuration update {}", e.getMessage( ), e );
749 throw new RepositoryException( "Could not save the configuration" + ( e.getMessage( ) == null ? "" : ": " + e.getMessage( ) ) );
754 rwLock.writeLock( ).unlock( );
759 * Adds a new repository or updates the repository with the same id, if it exists already.
760 * The configuration is saved immediately.
762 * @param managedRepositoryConfiguration the repository configuration
763 * @return the updated or created repository
764 * @throws RepositoryException if an error occurs, or the configuration is not valid.
767 public ManagedRepository putRepository( ManagedRepositoryConfiguration managedRepositoryConfiguration ) throws RepositoryException
769 rwLock.writeLock( ).lock( );
772 final String id = managedRepositoryConfiguration.getId( );
773 final RepositoryType repositoryType = RepositoryType.valueOf( managedRepositoryConfiguration.getType( ) );
774 Configuration configuration = configurationHandler.getBaseConfiguration( );
775 ManagedRepository repo = managedRepositories.get( id );
776 ManagedRepositoryConfiguration oldCfg = repo != null ? getProvider( repositoryType ).getManagedConfiguration( repo ) : null;
777 repo = putRepository( managedRepositoryConfiguration, configuration );
780 saveConfiguration( configuration );
782 catch ( IndeterminateConfigurationException | RegistryException e )
784 if ( oldCfg != null )
786 getProvider( repositoryType ).updateManagedInstance( (EditableManagedRepository) repo, oldCfg );
788 log.error( "Could not save the configuration for repository {}: {}", id, e.getMessage( ), e );
789 throw new RepositoryException( "Could not save the configuration for repository " + id + ": " + e.getMessage( ) );
795 rwLock.writeLock( ).unlock( );
801 * Adds a new repository or updates the repository with the same id. The given configuration object is updated, but
802 * the configuration is not saved.
804 * @param managedRepositoryConfiguration the new or changed managed repository configuration
805 * @param configuration the configuration object (may be <code>null</code>)
806 * @return the new or updated repository
807 * @throws RepositoryException if the configuration cannot be saved or updated
810 public ManagedRepository putRepository( ManagedRepositoryConfiguration managedRepositoryConfiguration, Configuration configuration ) throws RepositoryException
812 rwLock.writeLock( ).lock( );
815 final String id = managedRepositoryConfiguration.getId( );
816 final RepositoryType repoType = RepositoryType.valueOf( managedRepositoryConfiguration.getType( ) );
817 ManagedRepository repo;
818 boolean registeredNew = false;
819 repo = managedRepositories.get( id );
820 if ( repo != null && repo.isOpen( ) )
822 if ( repo instanceof EditableManagedRepository )
824 getProvider( repoType ).updateManagedInstance( (EditableManagedRepository) repo, managedRepositoryConfiguration );
828 throw new RepositoryException( "The repository is not editable " + id );
833 repo = getProvider( repoType ).createManagedInstance( managedRepositoryConfiguration );
834 managedRepositories.put( id, repo );
835 registeredNew = true;
837 updateRepositoryReferences( getProvider( repoType ), repo, managedRepositoryConfiguration, configuration );
838 replaceOrAddRepositoryConfig( managedRepositoryConfiguration, configuration );
841 pushEvent( new LifecycleEvent( LifecycleEvent.REGISTERED, this, repo ) );
845 pushEvent( new LifecycleEvent( LifecycleEvent.UPDATED, this, repo ) );
851 rwLock.writeLock( ).unlock( );
857 * Adds a new repository group to the current list, or replaces the repository group definition with
858 * the same id, if it exists already.
859 * The change is saved to the configuration immediately.
861 * @param repositoryGroup the new repository group.
862 * @throws RepositoryException if the new repository group could not be saved to the configuration.
865 public RepositoryGroup putRepositoryGroup( RepositoryGroup repositoryGroup ) throws RepositoryException
867 rwLock.writeLock( ).lock( );
870 if ( this.groupHandler == null )
872 throw new RepositoryException( "Fatal error. RepositoryGroupHandler not registered!" );
874 return this.groupHandler.put( repositoryGroup );
878 rwLock.writeLock( ).unlock( );
883 * Adds a new repository group or updates the repository with the same id, if it exists already.
884 * The configuration is saved immediately.
886 * @param repositoryGroupConfiguration the repository configuration
887 * @return the updated or created repository
888 * @throws RepositoryException if an error occurs, or the configuration is not valid.
891 public RepositoryGroup putRepositoryGroup( RepositoryGroupConfiguration repositoryGroupConfiguration ) throws RepositoryException
893 rwLock.writeLock( ).lock( );
896 return groupHandler.put( repositoryGroupConfiguration );
900 rwLock.writeLock( ).unlock( );
906 public CheckedResult<RepositoryGroup, Map<String, List<ValidationError>>> putRepositoryGroupAndValidate( RepositoryGroupConfiguration repositoryGroupConfiguration )
907 throws RepositoryException
909 rwLock.writeLock( ).lock( );
912 return groupHandler.putWithCheck( repositoryGroupConfiguration, this.groupChecker );
916 rwLock.writeLock( ).unlock( );
921 * Adds a new repository group or updates the repository group with the same id. The given configuration object is updated, but
922 * the configuration is not saved.
924 * @param repositoryGroupConfiguration The configuration of the new or changed repository group.
925 * @param configuration The configuration object. If it is <code>null</code>, the configuration is not saved.
926 * @return The new or updated repository group
927 * @throws RepositoryException if the configuration cannot be saved or updated
930 public RepositoryGroup putRepositoryGroup( RepositoryGroupConfiguration repositoryGroupConfiguration, Configuration configuration ) throws RepositoryException
932 rwLock.writeLock( ).lock( );
935 return groupHandler.put( repositoryGroupConfiguration, configuration );
939 rwLock.writeLock( ).unlock( );
943 private void replaceOrAddRepositoryConfig( ManagedRepositoryConfiguration managedRepositoryConfiguration, Configuration configuration )
945 if ( configuration != null )
947 ManagedRepositoryConfiguration oldCfg = configuration.findManagedRepositoryById( managedRepositoryConfiguration.getId( ) );
948 if ( oldCfg != null )
950 configuration.removeManagedRepository( oldCfg );
952 configuration.addManagedRepository( managedRepositoryConfiguration );
956 private void replaceOrAddRepositoryConfig( RemoteRepositoryConfiguration remoteRepositoryConfiguration, Configuration configuration )
958 if ( configuration != null )
960 RemoteRepositoryConfiguration oldCfg = configuration.findRemoteRepositoryById( remoteRepositoryConfiguration.getId( ) );
961 if ( oldCfg != null )
963 configuration.removeRemoteRepository( oldCfg );
965 configuration.addRemoteRepository( remoteRepositoryConfiguration );
969 private void replaceOrAddRepositoryConfig( RepositoryGroupConfiguration repositoryGroupConfiguration, Configuration configuration )
971 RepositoryGroupConfiguration oldCfg = configuration.findRepositoryGroupById( repositoryGroupConfiguration.getId( ) );
972 if ( oldCfg != null )
974 configuration.removeRepositoryGroup( oldCfg );
976 configuration.addRepositoryGroup( repositoryGroupConfiguration );
980 public RemoteRepository putRepository( RemoteRepository remoteRepository, Configuration configuration ) throws RepositoryException
982 rwLock.writeLock( ).lock( );
985 final String id = remoteRepository.getId( );
986 if ( managedRepositories.containsKey( id ) )
988 throw new RepositoryException( "There exists a managed repository with id " + id + ". Could not update with remote repository." );
990 RemoteRepository originRepo = remoteRepositories.put( id, remoteRepository );
991 RemoteRepositoryConfiguration oldCfg = null;
992 RemoteRepositoryConfiguration newCfg;
995 if ( originRepo != null && originRepo != remoteRepository )
999 final RepositoryProvider provider = getProvider( remoteRepository.getType( ) );
1000 newCfg = provider.getRemoteConfiguration( remoteRepository );
1001 updateRepositoryReferences( provider, remoteRepository, newCfg, configuration );
1002 oldCfg = configuration.findRemoteRepositoryById( id );
1003 if ( oldCfg != null )
1005 configuration.removeRemoteRepository( oldCfg );
1007 configuration.addRemoteRepository( newCfg );
1008 if ( remoteRepository != originRepo )
1010 pushEvent( new LifecycleEvent( LifecycleEvent.REGISTERED, this, remoteRepository ) );
1014 pushEvent( new LifecycleEvent( LifecycleEvent.UPDATED, this, remoteRepository ) );
1016 return remoteRepository;
1018 catch ( Exception e )
1021 if ( originRepo != null )
1023 remoteRepositories.put( id, originRepo );
1027 remoteRepositories.remove( id );
1029 if ( oldCfg != null )
1031 RemoteRepositoryConfiguration cfg = configuration.findRemoteRepositoryById( id );
1034 configuration.removeRemoteRepository( cfg );
1035 configuration.addRemoteRepository( oldCfg );
1038 log.error( "Error while adding remote repository {}", e.getMessage( ), e );
1039 throw new RepositoryException( "Could not save the configuration" + ( e.getMessage( ) == null ? "" : ": " + e.getMessage( ) ) );
1044 rwLock.writeLock( ).unlock( );
1049 * Adds a remote repository, or overwrites the repository definition with the same id, if it exists already.
1050 * The modification is saved to the configuration immediately.
1052 * @param remoteRepository the remote repository to add
1053 * @throws RepositoryException if an error occurs during configuration save
1056 public RemoteRepository putRepository( RemoteRepository remoteRepository ) throws RepositoryException
1058 rwLock.writeLock( ).lock( );
1061 Configuration configuration = configurationHandler.getBaseConfiguration( );
1064 RemoteRepository repo = putRepository( remoteRepository, configuration );
1065 saveConfiguration( configuration );
1068 catch ( RegistryException | IndeterminateConfigurationException e )
1070 log.error( "Error while saving remote repository {}", e.getMessage( ), e );
1071 throw new RepositoryException( "Could not save the configuration" + ( e.getMessage( ) == null ? "" : ": " + e.getMessage( ) ) );
1076 rwLock.writeLock( ).unlock( );
1081 * Adds a new repository or updates the repository with the same id, if it exists already.
1082 * The configuration is saved immediately.
1084 * @param remoteRepositoryConfiguration the repository configuration
1085 * @return the updated or created repository
1086 * @throws RepositoryException if an error occurs, or the configuration is not valid.
1089 public RemoteRepository putRepository( RemoteRepositoryConfiguration remoteRepositoryConfiguration ) throws RepositoryException
1091 rwLock.writeLock( ).lock( );
1094 final String id = remoteRepositoryConfiguration.getId( );
1095 final RepositoryType repositoryType = RepositoryType.valueOf( remoteRepositoryConfiguration.getType( ) );
1096 Configuration configuration = configurationHandler.getBaseConfiguration( );
1097 RemoteRepository repo = remoteRepositories.get( id );
1098 RemoteRepositoryConfiguration oldCfg = repo != null ? getProvider( repositoryType ).getRemoteConfiguration( repo ) : null;
1099 repo = putRepository( remoteRepositoryConfiguration, configuration );
1102 saveConfiguration( configuration );
1104 catch ( IndeterminateConfigurationException | RegistryException e )
1106 if ( oldCfg != null )
1108 getProvider( repositoryType ).updateRemoteInstance( (EditableRemoteRepository) repo, oldCfg );
1110 log.error( "Could not save the configuration for repository {}: {}", id, e.getMessage( ), e );
1111 throw new RepositoryException( "Could not save the configuration for repository " + id + ": " + e.getMessage( ) );
1117 rwLock.writeLock( ).unlock( );
1123 * Adds a new repository or updates the repository with the same id. The given configuration object is updated, but
1124 * the configuration is not saved.
1126 * @param remoteRepositoryConfiguration the new or changed repository configuration
1127 * @param configuration the configuration object
1128 * @return the new or updated repository
1129 * @throws RepositoryException if the configuration cannot be saved or updated
1132 @SuppressWarnings( "unchecked" )
1133 public RemoteRepository putRepository( RemoteRepositoryConfiguration remoteRepositoryConfiguration, Configuration configuration ) throws RepositoryException
1135 rwLock.writeLock( ).lock( );
1138 final String id = remoteRepositoryConfiguration.getId( );
1139 final RepositoryType repoType = RepositoryType.valueOf( remoteRepositoryConfiguration.getType( ) );
1140 RemoteRepository repo;
1141 boolean registeredNew = false;
1142 repo = remoteRepositories.get( id );
1143 if ( repo != null && repo.isOpen( ) )
1145 if ( repo instanceof EditableRemoteRepository )
1147 getProvider( repoType ).updateRemoteInstance( (EditableRemoteRepository) repo, remoteRepositoryConfiguration );
1151 throw new RepositoryException( "The repository is not editable " + id );
1156 repo = getProvider( repoType ).createRemoteInstance( remoteRepositoryConfiguration );
1157 remoteRepositories.put( id, repo );
1158 registeredNew = true;
1160 updateRepositoryReferences( getProvider( repoType ), repo, remoteRepositoryConfiguration, configuration );
1161 replaceOrAddRepositoryConfig( remoteRepositoryConfiguration, configuration );
1162 if ( registeredNew )
1164 pushEvent( new LifecycleEvent( LifecycleEvent.REGISTERED, this, repo ) );
1168 pushEvent( new LifecycleEvent( LifecycleEvent.UPDATED, this, repo ) );
1174 rwLock.writeLock( ).unlock( );
1181 public void removeRepository( String repoId ) throws RepositoryException
1183 Repository repo = getRepository( repoId );
1186 removeRepository( repo );
1191 public void removeRepository( Repository repo ) throws RepositoryException
1195 log.warn( "Trying to remove null repository" );
1198 if ( repo instanceof RemoteRepository )
1200 removeRepository( (RemoteRepository) repo );
1202 else if ( repo instanceof ManagedRepository )
1204 removeRepository( (ManagedRepository) repo );
1206 else if ( repo instanceof RepositoryGroup )
1208 removeRepositoryGroup( (RepositoryGroup) repo );
1212 throw new RepositoryException( "Repository type not known: " + repo.getClass( ) );
1217 * Removes a managed repository from the registry and configuration, if it exists.
1218 * The change is saved to the configuration immediately.
1220 * @param managedRepository the managed repository to remove
1221 * @throws RepositoryException if a error occurs during configuration save
1224 public void removeRepository( ManagedRepository managedRepository ) throws RepositoryException
1226 if ( managedRepository == null )
1230 final String id = managedRepository.getId( );
1231 ManagedRepository repo = getManagedRepository( id );
1234 rwLock.writeLock( ).lock( );
1237 repo = managedRepositories.remove( id );
1241 this.groupHandler.removeRepositoryFromGroups( repo );
1242 Configuration configuration = configurationHandler.getBaseConfiguration( );
1243 ManagedRepositoryConfiguration cfg = configuration.findManagedRepositoryById( id );
1246 configuration.removeManagedRepository( cfg );
1248 saveConfiguration( configuration );
1250 pushEvent( new LifecycleEvent( LifecycleEvent.UNREGISTERED, this, repo ) );
1252 catch ( RegistryException | IndeterminateConfigurationException e )
1255 log.error( "Could not save config after repository removal: {}", e.getMessage( ), e );
1256 managedRepositories.put( repo.getId( ), repo );
1257 throw new RepositoryException( "Could not save configuration after repository removal: " + e.getMessage( ) );
1261 rwLock.writeLock( ).unlock( );
1268 public void removeRepository( ManagedRepository managedRepository, Configuration configuration ) throws RepositoryException
1270 if ( managedRepository == null )
1274 final String id = managedRepository.getId( );
1275 ManagedRepository repo = getManagedRepository( id );
1278 rwLock.writeLock( ).lock( );
1281 repo = managedRepositories.remove( id );
1285 this.groupHandler.removeRepositoryFromGroups( repo );
1286 ManagedRepositoryConfiguration cfg = configuration.findManagedRepositoryById( id );
1289 configuration.removeManagedRepository( cfg );
1292 pushEvent( new LifecycleEvent( LifecycleEvent.UNREGISTERED, this, repo ) );
1296 rwLock.writeLock( ).unlock( );
1304 * Removes a repository group from the registry and configuration, if it exists.
1305 * The change is saved to the configuration immediately.
1307 * @param repositoryGroup the repository group to remove
1308 * @throws RepositoryException if a error occurs during configuration save
1311 public void removeRepositoryGroup( RepositoryGroup repositoryGroup ) throws RepositoryException
1313 if ( repositoryGroup == null )
1317 final String id = repositoryGroup.getId( );
1318 if ( groupHandler.has( id ) )
1320 rwLock.writeLock( ).lock( );
1323 groupHandler.remove( id );
1327 rwLock.writeLock( ).unlock( );
1333 public void removeRepositoryGroup( RepositoryGroup repositoryGroup, Configuration configuration ) throws RepositoryException
1335 if ( repositoryGroup == null )
1339 final String id = repositoryGroup.getId( );
1340 if ( groupHandler.has( id ) )
1342 rwLock.writeLock( ).lock( );
1345 groupHandler.remove( id, configuration );
1349 rwLock.writeLock( ).unlock( );
1354 private void doRemoveRepo( RemoteRepository repo, Configuration configuration )
1357 RemoteRepositoryConfiguration cfg = configuration.findRemoteRepositoryById( repo.getId( ) );
1360 configuration.removeRemoteRepository( cfg );
1362 List<ProxyConnectorConfiguration> proxyConnectors = new ArrayList<>( configuration.getProxyConnectors( ) );
1363 for ( ProxyConnectorConfiguration proxyConnector : proxyConnectors )
1365 if ( StringUtils.equals( proxyConnector.getTargetRepoId( ), repo.getId( ) ) )
1367 configuration.removeProxyConnector( proxyConnector );
1373 * Removes the remote repository from the registry and configuration.
1374 * The change is saved to the configuration immediately.
1376 * @param remoteRepository the remote repository to remove
1377 * @throws RepositoryException if a error occurs during configuration save
1380 public void removeRepository( RemoteRepository remoteRepository ) throws RepositoryException
1382 if ( remoteRepository == null )
1386 final String id = remoteRepository.getId( );
1387 RemoteRepository repo = getRemoteRepository( id );
1390 rwLock.writeLock( ).lock( );
1393 repo = remoteRepositories.remove( id );
1396 Configuration configuration = configurationHandler.getBaseConfiguration( );
1397 doRemoveRepo( repo, configuration );
1398 saveConfiguration( configuration );
1400 pushEvent( new LifecycleEvent( LifecycleEvent.UNREGISTERED, this, repo ) );
1402 catch ( RegistryException | IndeterminateConfigurationException e )
1405 log.error( "Could not save config after repository removal: {}", e.getMessage( ), e );
1406 remoteRepositories.put( repo.getId( ), repo );
1407 throw new RepositoryException( "Could not save configuration after repository removal: " + e.getMessage( ) );
1411 rwLock.writeLock( ).unlock( );
1417 public void removeRepository( RemoteRepository remoteRepository, Configuration configuration ) throws RepositoryException
1419 if ( remoteRepository == null )
1423 final String id = remoteRepository.getId( );
1424 RemoteRepository repo = getRemoteRepository( id );
1427 rwLock.writeLock( ).lock( );
1430 repo = remoteRepositories.remove( id );
1433 doRemoveRepo( repo, configuration );
1435 pushEvent( new LifecycleEvent( LifecycleEvent.UNREGISTERED, this, repo ) );
1439 rwLock.writeLock( ).unlock( );
1446 * Reloads the registry from the configuration.
1449 public void reload( )
1455 * Resets the indexing context of a given repository.
1457 * @param repository The repository
1458 * @throws IndexUpdateFailedException If the index could not be resetted.
1461 public void resetIndexingContext( Repository repository ) throws IndexUpdateFailedException
1463 if ( repository.hasIndex( ) && repository instanceof EditableRepository )
1465 EditableRepository eRepo = (EditableRepository) repository;
1466 ArchivaIndexingContext newCtx = getIndexManager( repository.getType( ) ).reset( repository.getIndexingContext( ) );
1467 eRepo.setIndexingContext( newCtx );
1473 * Creates a new repository instance with the same settings as this one. The cloned repository is not
1474 * registered or saved to the configuration.
1476 * @param repo The origin repository
1477 * @return The cloned repository.
1479 public ManagedRepository clone( ManagedRepository repo, String newId ) throws RepositoryException
1481 if ( managedRepositories.containsKey( newId ) || remoteRepositories.containsKey( newId ) )
1483 throw new RepositoryException( "The given id exists already " + newId );
1485 RepositoryProvider provider = getProvider( repo.getType( ) );
1486 ManagedRepositoryConfiguration cfg = provider.getManagedConfiguration( repo );
1488 ManagedRepository cloned = provider.createManagedInstance( cfg );
1489 cloned.registerEventHandler( RepositoryEvent.ANY, this );
1494 public <T extends Repository> T clone( T repo, String newId ) throws RepositoryException
1496 if ( repo instanceof RemoteRepository )
1498 return (T) this.clone( (RemoteRepository) repo, newId );
1500 else if ( repo instanceof ManagedRepository )
1502 return (T) this.clone( (ManagedRepository) repo, newId );
1506 throw new RepositoryException( "This repository class is not supported " + repo.getClass( ).getName( ) );
1511 * Creates a new repository instance with the same settings as this one. The cloned repository is not
1512 * registered or saved to the configuration.
1514 * @param repo The origin repository
1515 * @return The cloned repository.
1517 public RemoteRepository clone( RemoteRepository repo, String newId ) throws RepositoryException
1519 if ( managedRepositories.containsKey( newId ) || remoteRepositories.containsKey( newId ) )
1521 throw new RepositoryException( "The given id exists already " + newId );
1523 RepositoryProvider provider = getProvider( repo.getType( ) );
1524 RemoteRepositoryConfiguration cfg = provider.getRemoteConfiguration( repo );
1526 RemoteRepository cloned = provider.createRemoteInstance( cfg );
1527 cloned.registerEventHandler( RepositoryEvent.ANY, this );
1532 public Repository getRepositoryOfAsset( StorageAsset asset )
1534 if ( asset instanceof Repository )
1536 return (Repository) asset;
1540 return getRepositories( ).stream( ).filter( r -> r.getRoot( )
1541 .getStorage( ).equals( asset.getStorage( ) ) ).findFirst( ).orElse( null );
1546 public <R extends Repository> ValidationResponse<R> validateRepository( R repository )
1548 Map<String, List<ValidationError>> errorMap = this.validators.stream( )
1549 .filter( ( validator ) -> validator.getType( ).equals( RepositoryType.ALL ) || repository.getType( ).equals( validator.getType( ) ) )
1550 .filter( val -> val.isFlavour( repository.getClass() ))
1551 .flatMap( validator -> ((RepositoryValidator<R>)validator).apply( repository ).getResult().entrySet( ).stream( ) )
1552 .collect( Collectors.toMap(
1553 entry -> entry.getKey( ),
1554 entry -> entry.getValue( ),
1555 ( list1, list2 ) -> ListUtils.union( list1, list2 )
1557 return new ValidationResponse( repository, errorMap );
1561 public <R extends Repository> ValidationResponse<R> validateRepositoryForUpdate( R repository )
1563 Map<String, List<ValidationError>> errorMap = this.validators.stream( )
1564 .filter( ( validator ) -> validator.getType( ).equals( RepositoryType.ALL ) || repository.getType( ).equals( validator.getType( ) ) )
1565 .filter( val -> val.isFlavour( repository.getClass() ))
1566 .flatMap( validator -> ((RepositoryValidator<R>)validator).applyForUpdate( repository ).getResult().entrySet( ).stream( ) )
1567 .collect( Collectors.toMap(
1568 entry -> entry.getKey( ),
1569 entry -> entry.getValue( ),
1570 ( list1, list2 ) -> ListUtils.union( list1, list2 )
1572 return new ValidationResponse( repository, errorMap );
1576 public void configurationEvent( ConfigurationEvent event )
1578 // We ignore the event, if the save was triggered by ourself
1579 if ( !ConfigurationHandler.REGISTRY_EVENT_TAG.equals( event.getTag( ) ) )
1587 public <T extends Event> void registerEventHandler( EventType<T> type, EventHandler<? super T> eventHandler )
1589 eventManager.registerEventHandler( type, eventHandler );
1594 public <T extends Event> void unregisterEventHandler( EventType<T> type, EventHandler<? super T> eventHandler )
1596 eventManager.unregisterEventHandler( type, eventHandler );
1601 public void handle( Event event )
1603 // To avoid event cycles:
1604 if ( sameOriginator( event ) )
1608 if ( event instanceof RepositoryIndexEvent )
1610 handleIndexCreationEvent( (RepositoryIndexEvent) event );
1612 // We propagate all events to our listeners, but with context of repository registry
1616 private void handleIndexCreationEvent( RepositoryIndexEvent event )
1618 RepositoryIndexEvent idxEvent = event;
1619 EditableRepository repo = (EditableRepository) idxEvent.getRepository( );
1622 ArchivaIndexManager idxmgr = getIndexManager( repo.getType( ) );
1623 if ( repo.getIndexingContext( ) != null )
1627 ArchivaIndexingContext newCtx = idxmgr.move( repo.getIndexingContext( ), repo );
1628 repo.setIndexingContext( newCtx );
1629 idxmgr.updateLocalIndexPath( repo );
1632 catch ( IndexCreationFailedException e )
1634 log.error( "Could not move index to new directory: '{}'", e.getMessage( ), e );
1641 ArchivaIndexingContext context = idxmgr.createContext( repo );
1642 repo.setIndexingContext( context );
1643 idxmgr.updateLocalIndexPath( repo );
1645 catch ( IndexCreationFailedException e )
1647 log.error( "Could not create index: '{}'", e.getMessage( ), e );
1653 private boolean sameOriginator( Event event )
1655 if ( event.getSource( ) == this )
1659 else if ( event.hasPreviousEvent( ) )
1661 return sameOriginator( event.getPreviousEvent( ) );
1669 private void pushEvent( Event event )
1671 eventManager.fireEvent( event );