package org.apache.archiva.repository.base; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import org.apache.archiva.components.registry.RegistryException; import org.apache.archiva.configuration.AbstractRepositoryConfiguration; import org.apache.archiva.configuration.Configuration; import org.apache.archiva.configuration.IndeterminateConfigurationException; import org.apache.archiva.event.Event; import org.apache.archiva.event.EventManager; import org.apache.archiva.event.EventType; import org.apache.archiva.repository.EditableRepository; import org.apache.archiva.repository.Repository; import org.apache.archiva.repository.RepositoryException; import org.apache.archiva.repository.RepositoryHandler; import org.apache.archiva.repository.RepositoryProvider; import org.apache.archiva.repository.RepositoryState; import org.apache.archiva.repository.RepositoryType; import org.apache.archiva.repository.event.LifecycleEvent; import org.apache.archiva.repository.validation.CheckedResult; import org.apache.archiva.repository.validation.CombinedValidator; import org.apache.archiva.repository.validation.RepositoryChecker; import org.apache.archiva.repository.validation.RepositoryValidator; import org.apache.archiva.repository.validation.ValidationError; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** * Base abstract class for repository handlers. * * @author Martin Stockhammer */ public abstract class AbstractRepositoryHandler implements RepositoryHandler { private static final Logger log = LoggerFactory.getLogger( AbstractRepositoryHandler.class ); protected final Map providerMap = new HashMap<>( ); private CombinedValidator combinedValidator; private final Class repositoryClazz; private final Class configurationClazz; private final EventManager eventManager; private final Map repositoryMap = new HashMap<>( ); private final ConfigurationHandler configurationHandler; public AbstractRepositoryHandler(Class repositoryClazz, Class configurationClazz, ConfigurationHandler configurationHandler) { this.repositoryClazz = repositoryClazz; this.configurationClazz = configurationClazz; this.eventManager = new EventManager( this ); this.configurationHandler = configurationHandler; } protected List> initValidators( Class clazz, List> repositoryGroupValidatorList ) { if ( repositoryGroupValidatorList != null && repositoryGroupValidatorList.size( ) > 0 ) { return repositoryGroupValidatorList.stream( ).filter( v -> v.isFlavour( clazz ) ).map( v -> v.narrowTo( clazz ) ).collect( Collectors.toList( ) ); } else { return Collections.emptyList( ); } } protected CombinedValidator getCombinedValidator( Class clazz, List> repositoryGroupValidatorList ) { return new CombinedValidator<>( clazz, initValidators( clazz, repositoryGroupValidatorList ) ); } protected void setLastState( R repo, RepositoryState state ) { RepositoryState currentState = repo.getLastState( ); if ( repo instanceof EditableRepository ) { if ( state.getOrderNumber( ) > repo.getLastState( ).getOrderNumber( ) ) { ( (EditableRepository) repo ).setLastState( state ); } } else { log.error( "Found a not editable repository instance: {}, {}", repo.getId( ), repo.getClass( ).getName( ) ); } if (state == RepositoryState.REGISTERED && state != currentState ) { pushEvent( LifecycleEvent.REGISTERED, repo ); } else if (state == RepositoryState.UNREGISTERED && state != currentState) { pushEvent( LifecycleEvent.UNREGISTERED, repo ); } } @Override public void setRepositoryProviders( List providers ) { if ( providers != null ) { for ( RepositoryProvider provider : providers ) { for ( RepositoryType type : provider.provides( ) ) { providerMap.put( type, provider ); } } } } protected RepositoryProvider getProvider(RepositoryType type) { return providerMap.get( type ); } @Override public void setRepositoryValidator( List> repositoryValidatorList ) { this.combinedValidator = getCombinedValidator( repositoryClazz, repositoryValidatorList ); } protected CombinedValidator getCombinedValidator() { return this.combinedValidator; } @Override public Class getVariant( ) { return this.repositoryClazz; } @Override public Class getConfigurationVariant( ) { return this.configurationClazz; } @Override public void processOtherVariantRemoval( Repository repository ) { // Default: do nothing } protected void pushEvent( Event event ) { eventManager.fireEvent( event ); } protected void pushEvent(EventType event, R repo) { pushEvent( new LifecycleEvent( event, this, repo ) ); } protected Map getRepositories() { return repositoryMap; } protected ConfigurationHandler getConfigurationHandler() { return configurationHandler; } @Override public void activateRepository( R repository ) { // } @Override public void deactivateRepository( R repository ) { repository.close(); } @Override public abstract R newInstance( C repositoryConfiguration ) throws RepositoryException; @Override public CheckedResult putWithCheck( C repositoryConfiguration, RepositoryChecker checker ) throws RepositoryException { final String id = repositoryConfiguration.getId( ); R currentRepository = getRepositories().get( id ); R managedRepository = newInstance( repositoryConfiguration ); CheckedResult result; if ( currentRepository == null ) { result = checker.apply( managedRepository ); } else { result = checker.applyForUpdate( managedRepository ); } if ( result.isValid( ) ) { put( result.getRepository() ); } return result; } protected abstract C findRepositoryConfiguration(Configuration configuration, String id); protected abstract void removeRepositoryConfiguration(Configuration configuration, C repoConfiguration ); protected abstract void addRepositoryConfiguration( Configuration configuration, C repoConfiguration ); /** * Removes a repository group from the registry and configuration, if it exists. * The change is saved to the configuration immediately. * * @param id the id of the repository group to remove * @throws RepositoryException if an error occurs during configuration save */ @Override public void remove( String id ) throws RepositoryException { R repo = get( id ); if ( repo != null ) { try { repo = getRepositories().remove( id ); if ( repo != null ) { deactivateRepository( repo ); Configuration configuration = this.configurationHandler.getBaseConfiguration( ); C cfg = findRepositoryConfiguration( configuration, id ); if ( cfg != null ) { removeRepositoryConfiguration( configuration, cfg ); } this.configurationHandler.save( configuration, ConfigurationHandler.REGISTRY_EVENT_TAG ); setLastState( repo, RepositoryState.UNREGISTERED ); } } catch ( RegistryException | IndeterminateConfigurationException e ) { // Rollback log.error( "Could not save config after repository removal: {}", e.getMessage( ), e ); getRepositories().put( repo.getId( ), repo ); throw new RepositoryException( "Could not save configuration after repository removal: " + e.getMessage( ) ); } } } @Override public void remove( String id, Configuration configuration ) throws RepositoryException { R repo = getRepositories().get( id ); if ( repo != null ) { repo = getRepositories().remove( id ); if ( repo != null ) { deactivateRepository( repo ); } setLastState( repo, RepositoryState.UNREGISTERED ); } C cfg = findRepositoryConfiguration(configuration, id ); if ( cfg != null ) { removeRepositoryConfiguration(configuration, cfg ); } } @Override public R get( String groupId ) { return getRepositories().get( groupId ); } @Override public Collection getAll( ) { return Collections.unmodifiableCollection( getRepositories( ).values( ) ); } @Override public RepositoryValidator getValidator( ) { return getCombinedValidator(); } @Override public CheckedResult>> validateRepository( R repository ) { return getCombinedValidator( ).apply( repository ); } @Override public CheckedResult>> validateRepositoryForUpdate( R repository ) { return getCombinedValidator().applyForUpdate( repository ); } @Override public boolean hasRepository( String id ) { return getRepositories().containsKey( id ); } @Override public void close( ) { for ( R repository : getRepositories().values( ) ) { try { deactivateRepository( repository ); } catch ( Throwable e ) { log.error( "Could not close repository {}: {}", repository.getId( ), e.getMessage( ) ); } } getRepositories().clear( ); } protected void registerNewRepository( C repositoryGroupConfiguration, R currentRepository, Configuration configuration, boolean updated ) throws IndeterminateConfigurationException, RegistryException, RepositoryException { final String id = repositoryGroupConfiguration.getId( ); getConfigurationHandler().save( configuration, ConfigurationHandler.REGISTRY_EVENT_TAG ); updateReferences( currentRepository, repositoryGroupConfiguration ); if (!updated ) { setLastState( currentRepository, RepositoryState.REFERENCES_SET ); } activateRepository( currentRepository ); getRepositories().put( id, currentRepository ); setLastState( currentRepository, RepositoryState.REGISTERED ); } protected void rollback( Configuration configuration, R oldRepository, Exception e, C oldCfg ) throws RepositoryException { final String id = oldRepository.getId( ); replaceOrAddRepositoryConfig( oldCfg, configuration ); try { getConfigurationHandler().save( configuration, ConfigurationHandler.REGISTRY_EVENT_TAG ); } catch ( IndeterminateConfigurationException | RegistryException indeterminateConfigurationException ) { log.error( "Fatal error, config save during rollback failed: {}", e.getMessage( ), e ); } updateReferences( oldRepository, oldCfg ); setLastState( oldRepository, RepositoryState.REFERENCES_SET ); activateRepository( oldRepository ); getRepositories().put( id, oldRepository ); setLastState( oldRepository, RepositoryState.REGISTERED ); } protected void replaceOrAddRepositoryConfig( C repositoryGroupConfiguration, Configuration configuration ) { C oldCfg = findRepositoryConfiguration( configuration, repositoryGroupConfiguration.getId( ) ); if ( oldCfg != null ) { removeRepositoryConfiguration(configuration, oldCfg ); } addRepositoryConfiguration( configuration, repositoryGroupConfiguration ); } }