1 package org.apache.archiva.repository.base.remote;
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
20 import org.apache.archiva.components.registry.RegistryException;
21 import org.apache.archiva.configuration.Configuration;
22 import org.apache.archiva.configuration.IndeterminateConfigurationException;
23 import org.apache.archiva.configuration.ProxyConnectorConfiguration;
24 import org.apache.archiva.configuration.RemoteRepositoryConfiguration;
25 import org.apache.archiva.indexer.ArchivaIndexManager;
26 import org.apache.archiva.indexer.IndexCreationFailedException;
27 import org.apache.archiva.indexer.IndexManagerFactory;
28 import org.apache.archiva.repository.EditableRemoteRepository;
29 import org.apache.archiva.repository.EditableRepository;
30 import org.apache.archiva.repository.RemoteRepository;
31 import org.apache.archiva.repository.RepositoryContentFactory;
32 import org.apache.archiva.repository.RepositoryException;
33 import org.apache.archiva.repository.RepositoryHandler;
34 import org.apache.archiva.repository.RepositoryHandlerManager;
35 import org.apache.archiva.repository.RepositoryProvider;
36 import org.apache.archiva.repository.RepositoryState;
37 import org.apache.archiva.repository.RepositoryType;
38 import org.apache.archiva.repository.base.AbstractRepositoryHandler;
39 import org.apache.archiva.repository.base.ConfigurationHandler;
40 import org.apache.archiva.repository.event.LifecycleEvent;
41 import org.apache.archiva.repository.event.RepositoryEvent;
42 import org.apache.archiva.repository.features.IndexCreationFeature;
43 import org.apache.commons.lang3.StringUtils;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46 import org.springframework.stereotype.Service;
48 import javax.annotation.PostConstruct;
49 import javax.inject.Named;
50 import java.util.ArrayList;
51 import java.util.Collections;
52 import java.util.HashMap;
53 import java.util.List;
55 import java.util.concurrent.locks.ReentrantReadWriteLock;
58 * @author Martin Stockhammer <martin_s@apache.org>
60 @Service( "remoteRepositoryHandler#default" )
61 public class RemoteRepositoryHandler extends AbstractRepositoryHandler<RemoteRepository, RemoteRepositoryConfiguration> implements RepositoryHandler<RemoteRepository, RemoteRepositoryConfiguration>
63 private static final Logger log = LoggerFactory.getLogger( RemoteRepositoryHandler.class );
64 private final RepositoryHandlerManager repositoryHandlerManager;
65 private final RepositoryContentFactory repositoryContentFactory;
66 private final IndexManagerFactory indexManagerFactory;
69 public RemoteRepositoryHandler( RepositoryHandlerManager repositoryHandlerManager, ConfigurationHandler configurationHandler,
70 IndexManagerFactory indexManagerFactory,
71 @Named( "repositoryContentFactory#default" ) RepositoryContentFactory repositoryContentFactory )
73 super( RemoteRepository.class, RemoteRepositoryConfiguration.class, configurationHandler );
74 this.repositoryHandlerManager = repositoryHandlerManager;
75 this.repositoryContentFactory = repositoryContentFactory;
76 this.indexManagerFactory = indexManagerFactory;
83 log.debug( "Initializing repository handler " + RemoteRepositoryHandler.class );
85 // We are registering this class on the registry. This is necessary to avoid circular dependencies via injection.
86 this.repositoryHandlerManager.registerHandler( this );
89 private void initializeStorage( )
95 public void initializeFromConfig( )
97 Map<String, RemoteRepository> currentInstances = new HashMap<>( getRepositories( ) );
98 getRepositories().clear();
99 Map<String, RemoteRepository> newAndUpdated = newOrUpdateInstancesFromConfig( currentInstances );
100 getRepositories( ).putAll( newAndUpdated );
101 currentInstances.entrySet( ).stream( ).filter( entry -> !newAndUpdated.containsKey( entry.getKey( ) ) ).forEach(
103 deactivateRepository( r.getValue() )
105 for ( RemoteRepository remoteRepository : getRepositories( ).values( ) )
107 activateRepository( remoteRepository );
113 public Map<String, RemoteRepository> newOrUpdateInstancesFromConfig( Map<String, RemoteRepository> currentInstances)
117 List<RemoteRepositoryConfiguration> remoteRepoConfigs =
119 getConfigurationHandler( ).getBaseConfiguration( ).getRemoteRepositories( ) );
121 if ( remoteRepoConfigs == null )
123 return Collections.emptyMap( );
126 Map<String, RemoteRepository> result = new HashMap<>( );
127 for ( RemoteRepositoryConfiguration repoConfig : remoteRepoConfigs )
129 String id = repoConfig.getId( );
130 if (result.containsKey( id )) {
131 log.error( "There are repositories with the same id in the configuration: {}", id );
134 RemoteRepository repo;
135 if ( currentInstances.containsKey( id ) )
137 repo = currentInstances.remove( id );
138 getProvider( repo.getType( ) ).updateRemoteInstance( (EditableRemoteRepository) repo, repoConfig );
139 updateReferences( repo, repoConfig );
143 repo = newInstance( repoConfig );
145 result.put( id, repo );
149 catch ( Throwable e )
151 log.error( "Could not initialize repositories from config: {}", e.getMessage( ), e );
152 return new HashMap<>( );
158 public Map<String, RemoteRepository> newInstancesFromConfig( )
162 List<RemoteRepositoryConfiguration> remoteRepoConfigs =
164 getConfigurationHandler( ).getBaseConfiguration( ).getRemoteRepositories( ) );
166 if ( remoteRepoConfigs == null )
168 return Collections.emptyMap( );
171 Map<String, RemoteRepository> result = new HashMap<>( );
172 for ( RemoteRepositoryConfiguration repoConfig : remoteRepoConfigs )
174 RemoteRepository repo = newInstance( repoConfig );
175 result.put( repo.getId( ), repo );
179 catch ( Throwable e )
181 log.error( "Could not initialize repositories from config: {}", e.getMessage( ), e );
182 return new HashMap<>( );
187 public RemoteRepository newInstance( RepositoryType type, String id ) throws RepositoryException
189 log.debug( "Creating repo {}", id );
190 RepositoryProvider provider = getProvider( type );
191 EditableRemoteRepository repo;
192 repo = provider.createRemoteInstance( id, id );
193 repo.registerEventHandler( RepositoryEvent.ANY, repositoryHandlerManager );
194 updateReferences( repo, null );
195 repo.setLastState( RepositoryState.REFERENCES_SET );
202 public RemoteRepository newInstance( RemoteRepositoryConfiguration repositoryConfiguration ) throws RepositoryException
204 RepositoryType type = RepositoryType.valueOf( repositoryConfiguration.getType( ) );
205 RepositoryProvider provider = getProvider( type );
206 if ( provider == null )
208 throw new RepositoryException( "Provider not found for repository type: " + repositoryConfiguration.getType( ) );
210 final RemoteRepository repo = provider.createRemoteInstance( repositoryConfiguration );
211 repo.registerEventHandler( RepositoryEvent.ANY, repositoryHandlerManager );
212 updateReferences( repo, null );
213 if ( repo instanceof EditableRepository )
215 ( (EditableRepository) repo ).setLastState( RepositoryState.REFERENCES_SET );
221 protected RemoteRepositoryConfiguration findRepositoryConfiguration( Configuration configuration, String id )
223 return configuration.findRemoteRepositoryById( id );
227 protected void removeRepositoryConfiguration( Configuration configuration, RemoteRepositoryConfiguration repoConfiguration )
229 configuration.removeRemoteRepository( repoConfiguration );
230 List<ProxyConnectorConfiguration> proxyConnectors = new ArrayList<>( configuration.getProxyConnectors( ) );
231 for ( ProxyConnectorConfiguration proxyConnector : proxyConnectors )
233 if ( StringUtils.equals( proxyConnector.getTargetRepoId( ), repoConfiguration.getId( ) ) )
235 configuration.removeProxyConnector( proxyConnector );
241 protected void addRepositoryConfiguration( Configuration configuration, RemoteRepositoryConfiguration repoConfiguration )
243 configuration.addRemoteRepository( repoConfiguration );
250 public RemoteRepository put( RemoteRepository repository ) throws RepositoryException
252 final String id = repository.getId( );
253 RemoteRepository originRepo = getRepositories( ).remove( id );
254 if ( originRepo == null && repositoryHandlerManager.isRegisteredId( id ) )
256 throw new RepositoryException( "There exists a repository with id " + id + ". Could not update with managed repository." );
260 if ( originRepo != null && repository != originRepo )
262 deactivateRepository( originRepo );
263 pushEvent( LifecycleEvent.UNREGISTERED, originRepo );
265 RepositoryProvider provider = getProvider( repository.getType( ) );
266 RemoteRepositoryConfiguration newCfg = provider.getRemoteConfiguration( repository );
267 getConfigurationHandler( ).getLock( ).writeLock( ).lock( );
270 Configuration configuration = getConfigurationHandler( ).getBaseConfiguration( );
271 updateReferences( repository, newCfg );
272 RemoteRepositoryConfiguration oldCfg = configuration.findRemoteRepositoryById( id );
273 if ( oldCfg != null )
275 configuration.removeRemoteRepository( oldCfg );
277 configuration.addRemoteRepository( newCfg );
278 getConfigurationHandler( ).save( configuration, ConfigurationHandler.REGISTRY_EVENT_TAG );
279 setLastState( repository, RepositoryState.SAVED );
280 activateRepository( repository );
284 getConfigurationHandler( ).getLock( ).writeLock( ).unlock( );
286 getRepositories( ).put( id, repository );
287 setLastState( repository, RepositoryState.REGISTERED );
290 catch ( Exception e )
292 // Rollback only partly, because repository is closed already
293 if ( originRepo != null )
295 getRepositories( ).put( id, originRepo );
299 getRepositories( ).remove( id );
301 log.error( "Exception during configuration update {}", e.getMessage( ), e );
302 throw new RepositoryException( "Could not save the configuration" + ( e.getMessage( ) == null ? "" : ": " + e.getMessage( ) ) );
308 public RemoteRepository put( RemoteRepositoryConfiguration repositoryConfiguration ) throws RepositoryException
310 final String id = repositoryConfiguration.getId( );
311 final RepositoryType repositoryType = RepositoryType.valueOf( repositoryConfiguration.getType( ) );
312 final RepositoryProvider provider = getProvider( repositoryType );
313 ReentrantReadWriteLock.WriteLock configLock = this.getConfigurationHandler( ).getLock( ).writeLock( );
315 RemoteRepository repo = null;
316 RemoteRepository oldRepository = null;
317 Configuration configuration = null;
320 boolean updated = false;
321 configuration = getConfigurationHandler( ).getBaseConfiguration( );
322 repo = getRepositories( ).get( id );
323 oldRepository = repo == null ? null : clone( repo, id );
326 repo = put( repositoryConfiguration, configuration );
330 setRepositoryDefaults( repositoryConfiguration );
331 provider.updateRemoteInstance( (EditableRemoteRepository) repo, repositoryConfiguration );
333 pushEvent( LifecycleEvent.UPDATED, repo );
335 registerNewRepository( repositoryConfiguration, repo, configuration, updated );
337 catch ( IndeterminateConfigurationException | RegistryException e )
339 if ( oldRepository != null )
341 RemoteRepositoryConfiguration oldCfg = provider.getRemoteConfiguration( oldRepository );
342 provider.updateRemoteInstance( (EditableRemoteRepository) repo, oldCfg );
343 rollback( configuration, oldRepository, e, oldCfg );
347 getRepositories( ).remove( id );
349 log.error( "Could not save the configuration for repository {}: {}", id, e.getMessage( ), e );
350 throw new RepositoryException( "Could not save the configuration for repository " + id + ": " + e.getMessage( ) );
354 configLock.unlock( );
360 @SuppressWarnings( "unused" )
361 private void setRepositoryDefaults( RemoteRepositoryConfiguration repositoryConfiguration )
363 // We do nothing here
368 public RemoteRepository put( RemoteRepositoryConfiguration repositoryConfiguration, Configuration configuration ) throws RepositoryException
370 final String id = repositoryConfiguration.getId( );
371 final RepositoryType repoType = RepositoryType.valueOf( repositoryConfiguration.getType( ) );
372 RemoteRepository repo;
373 setRepositoryDefaults( repositoryConfiguration );
374 if ( getRepositories( ).containsKey( id ) )
376 repo = clone( getRepositories( ).get( id ), id );
377 if ( repo instanceof EditableRemoteRepository )
379 getProvider( repoType ).updateRemoteInstance( (EditableRemoteRepository) repo, repositoryConfiguration );
383 throw new RepositoryException( "The repository is not editable " + id );
388 repo = getProvider( repoType ).createRemoteInstance( repositoryConfiguration );
389 setLastState( repo, RepositoryState.CREATED );
391 if ( configuration != null )
393 replaceOrAddRepositoryConfig( repositoryConfiguration, configuration );
395 updateReferences( repo, repositoryConfiguration );
396 setLastState( repo, RepositoryState.REFERENCES_SET );
402 public RemoteRepository clone( RemoteRepository repo, String newId ) throws RepositoryException
404 RepositoryProvider provider = getProvider( repo.getType( ) );
405 RemoteRepositoryConfiguration cfg = provider.getRemoteConfiguration( repo );
407 RemoteRepository cloned = provider.createRemoteInstance( cfg );
408 cloned.registerEventHandler( RepositoryEvent.ANY, repositoryHandlerManager );
409 setLastState( cloned, RepositoryState.CREATED );
415 public void updateReferences( RemoteRepository repo, RemoteRepositoryConfiguration repositoryConfiguration ) throws RepositoryException
417 if ( repo instanceof EditableRemoteRepository && repo.getContent( ) == null )
419 EditableRemoteRepository editableRepo = (EditableRemoteRepository) repo;
420 editableRepo.setContent( repositoryContentFactory.getRemoteRepositoryContent( repo ) );
421 if ( repo.supportsFeature( IndexCreationFeature.class ) && repo.getIndexingContext( ) == null )
423 createIndexingContext( editableRepo );
426 repo.registerEventHandler( RepositoryEvent.ANY, repositoryHandlerManager );
430 private void createIndexingContext( EditableRepository editableRepo ) throws RepositoryException
432 if ( editableRepo.supportsFeature( IndexCreationFeature.class ) )
434 ArchivaIndexManager idxManager = getIndexManager( editableRepo.getType( ) );
437 editableRepo.setIndexingContext( idxManager.createContext( editableRepo ) );
438 idxManager.updateLocalIndexPath( editableRepo );
440 catch ( IndexCreationFailedException e )
442 throw new RepositoryException( "Could not create index for repository " + editableRepo.getId( ) + ": " + e.getMessage( ), e );
447 public ArchivaIndexManager getIndexManager( RepositoryType type )
449 return indexManagerFactory.getIndexManager( type );