Additional tests and refactoring

This commit is contained in:
Martin Stockhammer 2021-07-04 17:10:10 +02:00
parent bc27b2584b
commit 11d469489e
19 changed files with 1002 additions and 139 deletions

View File

@ -695,15 +695,9 @@ public class Configuration
public RepositoryGroupConfiguration findRepositoryGroupById( String id )
{
if ( repositoryGroups != null )
if ( repositoryGroups != null && id!=null)
{
for ( RepositoryGroupConfiguration group : (java.util.List<RepositoryGroupConfiguration>) repositoryGroups )
{
if ( group.getId().equals( id ) )
{
return group;
}
}
return ( (java.util.List<RepositoryGroupConfiguration>) repositoryGroups ).stream( ).filter( g -> g != null && id.equals( g.getId( ) ) ).findFirst( ).orElse( null );
}
return null;
}

View File

@ -21,14 +21,16 @@ import org.apache.archiva.configuration.Configuration;
import org.apache.archiva.repository.validation.CheckedResult;
import org.apache.archiva.repository.validation.RepositoryChecker;
import org.apache.archiva.repository.validation.RepositoryValidator;
import org.apache.archiva.repository.validation.ValidationError;
import org.apache.archiva.repository.validation.ValidationResponse;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
*
* This is the generic interface that handles different repository flavours.
* This is the generic interface that handles different repository flavours, currently for
* ManagedRepository, RemoteRepository and RepositoryGroup
*
* @author Martin Stockhammer <martin_s@apache.org>
*/
@ -36,21 +38,32 @@ public interface RepositoryHandler<R extends Repository, C>
{
/**
* Creates instances from the archiva configuration. The instances are not registered in the registry.
* Initializes the current state from the configuration
*/
void initializeFromConfig( );
/**
* Initializes the repository. E.g. starts scheduling and activate additional processes.
* @param repository the repository to initialize
*/
void initialize( R repository );
/**
* Creates new instances from the archiva configuration. The instances are not registered in the registry.
*
* @return A map of (repository id, Repository) pairs
*/
Map<String, R> newInstancesFromConfig();
Map<String, R> newInstancesFromConfig( );
/**
* Creates a new instance without registering and without updating the archiva configuration
*
* @param type the repository type
* @param id the repository identifier
* @param id the repository identifier
* @return the repository instance
* @throws RepositoryException if the creation failed
*/
R newInstance(RepositoryType type, String id) throws RepositoryException;
R newInstance( RepositoryType type, String id ) throws RepositoryException;
/**
* Creates a new instance and updates the given configuration object.
@ -90,7 +103,7 @@ public interface RepositoryHandler<R extends Repository, C>
* and not initialized. References are not updated.
*
* @param repositoryConfiguration the repository configuration
* @param configuration the configuration instance
* @param configuration the configuration instance
* @return the repository instance that was created or updated
* @throws RepositoryException if the update or creation failed
*/
@ -102,12 +115,12 @@ public interface RepositoryHandler<R extends Repository, C>
* If the checker returns a valid result, the registry is updated and configuration is saved.
*
* @param repositoryConfiguration the repository configuration
* @param checker the checker that validates the repository data
* @param checker the checker that validates the repository data
* @return the repository and the check result
* @throws RepositoryException if the creation or update failed
*/
<D> CheckedResult<R, D>
putWithCheck( C repositoryConfiguration, RepositoryChecker<R, D> checker) throws RepositoryException;
putWithCheck( C repositoryConfiguration, RepositoryChecker<R, D> checker ) throws RepositoryException;
/**
* Removes the given repository from the registry and updates references and saves the new configuration.
@ -121,7 +134,7 @@ public interface RepositoryHandler<R extends Repository, C>
* Removes the given repository from the registry and updates only the given configuration instance.
* The archiva registry is not updated
*
* @param id the repository identifier
* @param id the repository identifier
* @param configuration the configuration to update
* @throws RepositoryException if the repository could not be removed
*/
@ -141,7 +154,7 @@ public interface RepositoryHandler<R extends Repository, C>
* @param repo the repository that should be cloned
* @return a newly created instance with the same repository data
*/
R clone(R repo) throws RepositoryException;
R clone( R repo ) throws RepositoryException;
/**
* Updates the references and stores updates in the given <code>configuration</code> instance.
@ -149,7 +162,7 @@ public interface RepositoryHandler<R extends Repository, C>
* This method may register/unregister repositories depending on the implementation. That means there is no simple
* way to roll back, if an error occurs.
*
* @param repo the repository for which references are updated
* @param repo the repository for which references are updated
* @param repositoryConfiguration the repository configuration
*/
void updateReferences( R repo, C repositoryConfiguration ) throws RepositoryException;
@ -159,10 +172,11 @@ public interface RepositoryHandler<R extends Repository, C>
*
* @return the list of repositories
*/
Collection<R> getAll();
Collection<R> getAll( );
/**
* Returns a validator that can be used to validate repository data
*
* @return a validator instance
*/
RepositoryValidator<R> getValidator( );
@ -175,7 +189,7 @@ public interface RepositoryHandler<R extends Repository, C>
* @param repository the repository to validate against
* @return the result of the validation.
*/
ValidationResponse<R> validateRepository( R repository);
CheckedResult<R,Map<String, List<ValidationError>>> validateRepository( R repository );
/**
* Validates the set attributes of the given repository instance for a repository update and returns the validation result.
@ -185,25 +199,25 @@ public interface RepositoryHandler<R extends Repository, C>
* @param repository the repository to validate against
* @return the result of the validation.
*/
ValidationResponse<R> validateRepositoryForUpdate( R repository);
CheckedResult<R,Map<String, List<ValidationError>>> validateRepositoryForUpdate( R repository );
/**
* Returns <code>true</code>, if the repository is registered with the given id, otherwise <code>false</code>
*
* @param id the repository identifier
* @return <code>true</code>, if it is registered, otherwise <code>false</code>
*/
boolean has(String id);
boolean has( String id );
/**
* Initializes
*/
void init();
void init( );
/**
* Closes the handler
*/
void close();
void close( );
}

View File

@ -34,7 +34,10 @@ public class AbstractFeature {
}
AbstractFeature(EventHandler listener) {
this.listener.add(listener);
if (listener!=null)
{
this.listener.add( listener );
}
}
AbstractFeature(Collection<EventHandler> listeners) {

View File

@ -173,7 +173,7 @@ public class IndexCreationFeature extends AbstractFeature implements RepositoryF
/**
* Sets the path (relative or absolute) of the packed index.
*
* Throws a {@link RepositoryIndexEvent.Index#PACKED_INDEX_URI_CHANGE}, if the value changes.
* Throws a {@link RepositoryIndexEvent#packedIndexUriChange(Object, Repository, URI, URI)}, if the value changes.
*
* @param packedIndexPath the new path uri for the packed index
*/

View File

@ -33,6 +33,6 @@ public interface ErrorKeys
String MAX_LENGTH_EXCEEDED = "max_length";
String INVALID_CHARS = "invalid_chars";
String BELOW_MIN = "min";
String INVALID_SCHEDULING_EXPRESSION = "scheduling_exp_invalid";
String INVALID_LOCATION = "location_invalid";
String INVALID_SCHEDULING_EXPRESSION = "invalid_scheduling_exp";
String INVALID_LOCATION = "invalid_location";
}

View File

@ -34,7 +34,9 @@ public interface RepositoryValidator<R extends Repository> extends RepositoryChe
{
String REPOSITORY_ID_VALID_EXPRESSION = "^[a-zA-Z0-9._-]+$";
String[] REPOSITORY_ID_ALLOWED = new String[]{"alphanumeric, '.', '-','_'"};
String REPOSITORY_NAME_VALID_EXPRESSION = "^([a-zA-Z0-9.)/_(-]|\\s)+$";
String[] REPOSITORY_NAME_ALLOWED = new String[]{"alphanumeric", "whitespace", "/", "(", ")", "_", ".", "-"};
String REPOSITORY_LOCATION_VALID_EXPRESSION = "^[-a-zA-Z0-9._/~:?!&amp;=\\\\]+$";

View File

@ -287,11 +287,6 @@ public abstract class AbstractRepository implements EditableRepository, EventHan
@Override
public void setSchedulingDefinition(String cronExpression) {
if (StringUtils.isNotEmpty( cronExpression ))
{
CronParser parser = new CronParser( CRON_DEFINITION );
parser.parse( cronExpression ).validate( );
}
this.schedulingDefinition = cronExpression;
}
@ -302,9 +297,6 @@ public abstract class AbstractRepository implements EditableRepository, EventHan
@Override
public void setIndexingContext(ArchivaIndexingContext context) {
if (this.indexingContext!=null) {
}
this.indexingContext = context;
}

View File

@ -0,0 +1,49 @@
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.repository.Repository;
import org.apache.archiva.repository.RepositoryHandler;
import org.apache.archiva.repository.validation.CombinedValidator;
import org.apache.archiva.repository.validation.RepositoryValidator;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
/**
* Base abstract class for repository handlers.
* @author Martin Stockhammer <martin_s@apache.org>
*/
public abstract class AbstractRepositoryHandler<R extends Repository, C> implements RepositoryHandler<R, C>
{
protected List<RepositoryValidator<R>> initValidators( Class<R> clazz, List<RepositoryValidator<? extends Repository>> 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<R> getCombinedValidatdor(Class<R> clazz, List<RepositoryValidator<? extends Repository>> repositoryGroupValidatorList) {
return new CombinedValidator<>( clazz, initValidators( clazz, repositoryGroupValidatorList ) );
}
}

View File

@ -0,0 +1,181 @@
package org.apache.archiva.repository.base.group;
/*
* 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.common.filelock.DefaultFileLockManager;
import org.apache.archiva.common.filelock.FileLockManager;
import org.apache.archiva.repository.EditableRepositoryGroup;
import org.apache.archiva.repository.ManagedRepository;
import org.apache.archiva.repository.ReleaseScheme;
import org.apache.archiva.repository.RepositoryCapabilities;
import org.apache.archiva.repository.RepositoryGroup;
import org.apache.archiva.repository.RepositoryType;
import org.apache.archiva.repository.StandardCapabilities;
import org.apache.archiva.repository.base.AbstractRepository;
import org.apache.archiva.repository.base.managed.BasicManagedRepository;
import org.apache.archiva.repository.features.IndexCreationFeature;
import org.apache.archiva.repository.storage.RepositoryStorage;
import org.apache.archiva.repository.storage.fs.FilesystemStorage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
/**
* @author Martin Stockhammer <martin_s@apache.org>
*/
public class BasicRepositoryGroup extends AbstractRepository implements EditableRepositoryGroup
{
private static final RepositoryCapabilities CAPABILITIES = new StandardCapabilities(
new ReleaseScheme[] { ReleaseScheme.RELEASE, ReleaseScheme.SNAPSHOT },
new String[] {},
new String[] {},
new String[] {IndexCreationFeature.class.getName()},
false,
false,
false,
false,
false
);
private int mergedIndexTtl = 0;
private boolean hasIndex = false;
private final Logger log = LoggerFactory.getLogger(BasicRepositoryGroup.class);
private List<ManagedRepository> repositories = new ArrayList<>( );
public BasicRepositoryGroup( String id, String name, RepositoryStorage repositoryStorage )
{
super( RepositoryType.MAVEN, id, name, repositoryStorage );
IndexCreationFeature feature = new IndexCreationFeature( this, null );
feature.setLocalIndexPath( repositoryStorage.getRoot( ).resolve(".indexer") );
feature.setLocalPackedIndexPath( repositoryStorage.getRoot( ).resolve(".index") );
addFeature( feature );
}
@Override
public List<ManagedRepository> getRepositories( )
{
return repositories;
}
@Override
public boolean contains( ManagedRepository repository )
{
return repositories.contains( repository );
}
@Override
public boolean contains( String id )
{
return repositories.stream( ).anyMatch( v -> id.equals( v.getId( ) ) );
}
@Override
public int getMergedIndexTTL( )
{
return mergedIndexTtl;
}
@Override
public boolean hasIndex( )
{
return hasIndex;
}
@Override
public RepositoryCapabilities getCapabilities( )
{
return CAPABILITIES;
}
@Override
public void clearRepositories( )
{
this.repositories.clear( );
}
@Override
public void setRepositories( List<ManagedRepository> repositories )
{
this.repositories.clear();
this.repositories.addAll( repositories );
}
@Override
public void addRepository( ManagedRepository repository )
{
if ( !this.repositories.contains( repository ) )
{
this.repositories.add( repository );
}
}
@Override
public void addRepository( int index, ManagedRepository repository )
{
if (!this.repositories.contains( repository )) {
this.repositories.add( index, repository );
}
}
@Override
public boolean removeRepository( ManagedRepository repository )
{
return this.repositories.remove( repository );
}
@Override
public ManagedRepository removeRepository( String repoId )
{
for (ManagedRepository repo : this.repositories) {
if (repoId.equals( repo.getId() )) {
this.repositories.remove( repo );
return repo;
}
}
return null;
}
@Override
public void setMergedIndexTTL( int timeInSeconds )
{
this.mergedIndexTtl = timeInSeconds;
}
/**
* Creates a filesystem based repository instance. The path is built by basePath/repository-id
*
* @param id The repository id
* @param name The name of the repository
* @param repositoryPath The path to the repository
* @return The repository instance
* @throws IOException
*/
public static BasicRepositoryGroup newFilesystemInstance( String id, String name, Path repositoryPath) throws IOException {
FileLockManager lockManager = new DefaultFileLockManager();
FilesystemStorage storage = new FilesystemStorage(repositoryPath, lockManager);
return new BasicRepositoryGroup(id, name, storage);
}
}

View File

@ -45,7 +45,9 @@ public class BasicRepositoryGroupValidator extends AbstractRepositoryValidator<R
{
private static final String CATEGORY = "repository_group";
private static final Pattern REPO_GROUP_ID_PATTERN = Pattern.compile( "[A-Za-z0-9._\\-]+" );
private static final Pattern REPOSITORY_ID_VALID_EXPRESSION_PATTERN = Pattern.compile( REPOSITORY_ID_VALID_EXPRESSION );
private static final Pattern REPOSITORY_NAME_VALID_EXPRESSION_PATTERN = Pattern.compile( REPOSITORY_NAME_VALID_EXPRESSION );
private final ConfigurationHandler configurationHandler;
private RepositoryRegistry repositoryRegistry;
@ -60,8 +62,12 @@ public class BasicRepositoryGroupValidator extends AbstractRepositoryValidator<R
@Override
public ValidationResponse<RepositoryGroup> apply( RepositoryGroup repositoryGroup, boolean updateMode ) throws IllegalArgumentException
{
final String repoGroupId = repositoryGroup.getId( );
Map<String, List<ValidationError>> errors = null;
if (repositoryGroup==null) {
errors = appendError( null, "object", ISNULL );
return new ValidationResponse<>( repositoryGroup, errors );
}
final String repoGroupId = repositoryGroup.getId( );
if ( StringUtils.isBlank( repoGroupId ) )
{
errors = appendError( null, "id", ISEMPTY );
@ -73,10 +79,10 @@ public class BasicRepositoryGroupValidator extends AbstractRepositoryValidator<R
}
Matcher matcher = REPO_GROUP_ID_PATTERN.matcher( repoGroupId );
Matcher matcher = REPOSITORY_ID_VALID_EXPRESSION_PATTERN.matcher( repoGroupId );
if ( !matcher.matches( ) )
{
errors = appendError( errors, "id", INVALID_CHARS, repoGroupId, new String[]{"alphanumeric, '.', '-','_'"} );
errors = appendError( errors, "id", INVALID_CHARS, repoGroupId, REPOSITORY_ID_ALLOWED );
}
if ( repositoryGroup.getMergedIndexTTL( ) <= 0 )
@ -84,6 +90,18 @@ public class BasicRepositoryGroupValidator extends AbstractRepositoryValidator<R
errors = appendError( errors, "merged_index_ttl",BELOW_MIN, "0" );
}
if (StringUtils.isBlank( repositoryGroup.getName() )) {
errors = appendError( errors, "name", ISEMPTY );
} else
{
matcher = REPOSITORY_NAME_VALID_EXPRESSION_PATTERN.matcher( repositoryGroup.getName( ) );
if ( !matcher.matches( ) )
{
errors = appendError( errors, "name", INVALID_CHARS, repoGroupId, REPOSITORY_NAME_ALLOWED );
}
}
if ( repositoryRegistry != null && !updateMode )
{

View File

@ -22,6 +22,7 @@ import org.apache.archiva.configuration.Configuration;
import org.apache.archiva.configuration.IndeterminateConfigurationException;
import org.apache.archiva.configuration.RepositoryGroupConfiguration;
import org.apache.archiva.indexer.merger.MergedRemoteIndexesScheduler;
import org.apache.archiva.repository.base.AbstractRepositoryHandler;
import org.apache.archiva.repository.base.ArchivaRepositoryRegistry;
import org.apache.archiva.repository.base.ConfigurationHandler;
import org.apache.archiva.repository.validation.CheckedResult;
@ -37,9 +38,9 @@ import org.apache.archiva.repository.RepositoryType;
import org.apache.archiva.repository.event.RepositoryEvent;
import org.apache.archiva.repository.features.IndexCreationFeature;
import org.apache.archiva.repository.storage.StorageAsset;
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.apache.archiva.repository.validation.ValidationResponse;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
@ -70,7 +71,9 @@ import static org.apache.archiva.indexer.ArchivaIndexManager.DEFAULT_INDEX_PATH;
* @author Martin Stockhammer <martin_s@apache.org>
*/
@Service( "repositoryGroupHandler#default" )
public class RepositoryGroupHandler implements RepositoryHandler<RepositoryGroup, RepositoryGroupConfiguration>
public class RepositoryGroupHandler
extends AbstractRepositoryHandler<RepositoryGroup, RepositoryGroupConfiguration>
implements RepositoryHandler<RepositoryGroup, RepositoryGroupConfiguration>
{
private static final Logger log = LoggerFactory.getLogger( RepositoryGroupHandler.class );
@ -90,28 +93,18 @@ public class RepositoryGroupHandler implements RepositoryHandler<RepositoryGroup
* @param repositoryRegistry the registry. To avoid circular dependencies via DI, this class registers itself on the registry.
* @param configurationHandler the configuration handler is used to retrieve and save configuration.
* @param mergedRemoteIndexesScheduler the index scheduler is used for merging the indexes from all group members
* @param repositoryValidatorList the list of validators that are registered
*/
public RepositoryGroupHandler( ArchivaRepositoryRegistry repositoryRegistry,
ConfigurationHandler configurationHandler,
@Named( "mergedRemoteIndexesScheduler#default" ) MergedRemoteIndexesScheduler mergedRemoteIndexesScheduler,
List<RepositoryValidator<? extends Repository>> repositoryGroupValidatorList
List<RepositoryValidator<? extends Repository>> repositoryValidatorList
)
{
this.configurationHandler = configurationHandler;
this.mergedRemoteIndexesScheduler = mergedRemoteIndexesScheduler;
this.repositoryRegistry = repositoryRegistry;
List<RepositoryValidator<RepositoryGroup>> validatorList = initValidators( repositoryGroupValidatorList );
this.validator = new CombinedValidator<>( RepositoryGroup.class, validatorList );
}
private List<RepositoryValidator<RepositoryGroup>> initValidators(List<RepositoryValidator<? extends Repository>> repositoryGroupValidatorList) {
if (repositoryGroupValidatorList!=null && repositoryGroupValidatorList.size()>0) {
return repositoryGroupValidatorList.stream( ).filter(
v -> v.isFlavour( RepositoryGroup.class )
).map( v -> v.narrowTo( RepositoryGroup.class ) ).collect( Collectors.toList( ) );
} else {
return Collections.emptyList( );
}
this.validator = getCombinedValidatdor( RepositoryGroup.class, repositoryValidatorList );
}
@Override
@ -124,13 +117,14 @@ public class RepositoryGroupHandler implements RepositoryHandler<RepositoryGroup
this.repositoryRegistry.registerGroupHandler( this );
}
@Override
public void initializeFromConfig( )
{
this.repositoryGroups.clear( );
this.repositoryGroups.putAll( newInstancesFromConfig( ) );
for ( RepositoryGroup group : this.repositoryGroups.values( ) )
{
initializeGroup( group );
initialize( group );
}
}
@ -151,7 +145,8 @@ public class RepositoryGroupHandler implements RepositoryHandler<RepositoryGroup
this.groupsDirectory = baseDir;
}
private void initializeGroup( RepositoryGroup repositoryGroup )
@Override
public void initialize( RepositoryGroup repositoryGroup )
{
StorageAsset indexDirectory = getMergedIndexDirectory( repositoryGroup );
if ( !indexDirectory.exists( ) )
@ -295,7 +290,7 @@ public class RepositoryGroupHandler implements RepositoryHandler<RepositoryGroup
}
configuration.addRepositoryGroup( newCfg );
configurationHandler.save( configuration, ConfigurationHandler.REGISTRY_EVENT_TAG );
initializeGroup( repositoryGroup );
initialize( repositoryGroup );
}
finally
{
@ -354,7 +349,7 @@ public class RepositoryGroupHandler implements RepositoryHandler<RepositoryGroup
}
configurationHandler.save( configuration, ConfigurationHandler.REGISTRY_EVENT_TAG );
updateReferences( currentRepository, repositoryGroupConfiguration );
initializeGroup( currentRepository );
initialize( currentRepository );
this.repositoryGroups.put( id, currentRepository );
}
catch ( IndeterminateConfigurationException | RegistryException | RepositoryException e )
@ -374,7 +369,7 @@ public class RepositoryGroupHandler implements RepositoryHandler<RepositoryGroup
log.error( "Fatal error, config save during rollback failed: {}", e.getMessage( ), e );
}
updateReferences( oldRepository, oldCfg );
initializeGroup( oldRepository );
initialize( oldRepository );
}
log.error( "Could not save the configuration for repository group {}: {}", id, e.getMessage( ), e );
if (e instanceof RepositoryException) {
@ -559,7 +554,7 @@ public class RepositoryGroupHandler implements RepositoryHandler<RepositoryGroup
@Override
public void updateReferences( RepositoryGroup repo, RepositoryGroupConfiguration repositoryConfiguration ) throws RepositoryException
{
if ( repo instanceof EditableRepositoryGroup )
if ( repo instanceof EditableRepositoryGroup && repositoryConfiguration!=null)
{
EditableRepositoryGroup eGroup = (EditableRepositoryGroup) repo;
eGroup.setRepositories( repositoryConfiguration.getRepositories( ).stream( )
@ -581,17 +576,17 @@ public class RepositoryGroupHandler implements RepositoryHandler<RepositoryGroup
}
@Override
public ValidationResponse<RepositoryGroup> validateRepository( RepositoryGroup repository )
public CheckedResult<RepositoryGroup, Map<String, List<ValidationError>>> validateRepository( RepositoryGroup repository )
{
return null;
return this.validator.apply( repository );
}
@Override
public ValidationResponse<RepositoryGroup> validateRepositoryForUpdate( RepositoryGroup repository )
public CheckedResult<RepositoryGroup,Map<String, List<ValidationError>>> validateRepositoryForUpdate( RepositoryGroup repository )
{
return null;
return this.validator.applyForUpdate( repository );
}
@Override
public boolean has( String id )
{

View File

@ -64,7 +64,8 @@ public class BasicManagedRepositoryValidator extends AbstractRepositoryValidator
{
Map<String, List<ValidationError>> errors = null;
if (managedRepository==null) {
errors = appendError( errors, "id", ISNULL );
errors = appendError( errors, "object", ISNULL );
return new ValidationResponse<>( managedRepository, errors );
}
final String repoId = managedRepository.getId( );
if ( StringUtils.isBlank( repoId ) ) {
@ -89,7 +90,7 @@ public class BasicManagedRepositoryValidator extends AbstractRepositoryValidator
if ( !REPOSITORY_ID_VALID_EXPRESSION_PATTERN.matcher( repoId ).matches( ) )
{
errors = appendError( errors, "id", INVALID_CHARS, repoId, new String[]{"alphanumeric", "_", ".", "-"} );
errors = appendError( errors, "id", INVALID_CHARS, repoId, REPOSITORY_ID_ALLOWED );
}
if ( StringUtils.isBlank( managedRepository.getName() ) )
{
@ -98,7 +99,7 @@ public class BasicManagedRepositoryValidator extends AbstractRepositoryValidator
if ( !REPOSITORY_NAME_VALID_EXPRESSION_PATTERN.matcher( managedRepository.getName() ).matches( ) )
{
errors = appendError( errors, "name", INVALID_CHARS, managedRepository.getName( ), new String[]{"alphanumeric", "whitespace", "/", "(", ")", "_", ".", "-"} );
errors = appendError( errors, "name", INVALID_CHARS, managedRepository.getName( ), REPOSITORY_NAME_ALLOWED );
}
String cronExpression = managedRepository.getSchedulingDefinition( );

View File

@ -19,20 +19,30 @@ package org.apache.archiva.repository.base.managed;
import org.apache.archiva.configuration.Configuration;
import org.apache.archiva.configuration.ManagedRepositoryConfiguration;
import org.apache.archiva.repository.base.ArchivaRepositoryRegistry;
import org.apache.archiva.repository.base.ConfigurationHandler;
import org.apache.archiva.repository.validation.CheckedResult;
import org.apache.archiva.repository.ManagedRepository;
import org.apache.archiva.repository.Repository;
import org.apache.archiva.repository.RepositoryException;
import org.apache.archiva.repository.RepositoryHandler;
import org.apache.archiva.repository.RepositoryType;
import org.apache.archiva.repository.base.AbstractRepositoryHandler;
import org.apache.archiva.repository.base.ArchivaRepositoryRegistry;
import org.apache.archiva.repository.base.ConfigurationHandler;
import org.apache.archiva.repository.features.StagingRepositoryFeature;
import org.apache.archiva.repository.validation.CheckedResult;
import org.apache.archiva.repository.validation.RepositoryChecker;
import org.apache.archiva.repository.validation.RepositoryValidator;
import org.apache.archiva.repository.validation.ValidationResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Named;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Handler implementation for managed repositories.
@ -40,19 +50,84 @@ import java.util.Map;
* @author Martin Stockhammer <martin_s@apache.org>
*/
public class ManagedRepositoryHandler
extends AbstractRepositoryHandler<ManagedRepository, ManagedRepositoryConfiguration>
implements RepositoryHandler<ManagedRepository, ManagedRepositoryConfiguration>
{
private static final Logger log = LoggerFactory.getLogger( ManagedRepositoryHandler.class );
private final ConfigurationHandler configurationHandler;
private final ArchivaRepositoryRegistry repositoryRegistry;
private final RepositoryValidator<ManagedRepository> validator;
private Map<String, ManagedRepository> managedRepositories = new HashMap<>( );
private Map<String, ManagedRepository> uManagedRepositories = Collections.unmodifiableMap( managedRepositories );
public ManagedRepositoryHandler( ArchivaRepositoryRegistry repositoryRegistry,
ConfigurationHandler configurationHandler,
@Named( "repositoryValidator#common#managed") RepositoryValidator<ManagedRepository> managedRepositoryValidator )
List<RepositoryValidator<? extends Repository>> repositoryValidatorList )
{
this.configurationHandler = configurationHandler;
this.repositoryRegistry = repositoryRegistry;
this.validator = getCombinedValidatdor( ManagedRepository.class, repositoryValidatorList );
}
@Override
public void initializeFromConfig( )
{
this.managedRepositories.clear( );
this.managedRepositories.putAll( newInstancesFromConfig( ) );
for ( ManagedRepository managedRepository : this.managedRepositories.values( ) )
{
initialize( managedRepository );
}
}
@Override
public void initialize( ManagedRepository repository )
{
}
@Override
public Map<String, ManagedRepository> newInstancesFromConfig( )
{
return null;
try
{
Set<String> configRepoIds = new HashSet<>( );
List<ManagedRepositoryConfiguration> managedRepoConfigs =
configurationHandler.getBaseConfiguration( ).getManagedRepositories( );
if ( managedRepoConfigs == null )
{
return managedRepositories;
}
for ( ManagedRepositoryConfiguration repoConfig : managedRepoConfigs )
{
ManagedRepository repo = put( repoConfig, null );
configRepoIds.add( repoConfig.getId( ) );
if ( repo.supportsFeature( StagingRepositoryFeature.class ) )
{
StagingRepositoryFeature stagF = repo.getFeature( StagingRepositoryFeature.class ).get( );
if ( stagF.getStagingRepository( ) != null )
{
configRepoIds.add( stagF.getStagingRepository( ).getId( ) );
}
}
}
List<String> toRemove = managedRepositories.keySet( ).stream( ).filter( id -> !configRepoIds.contains( id ) ).collect( Collectors.toList( ) );
for ( String id : toRemove )
{
ManagedRepository removed = managedRepositories.remove( id );
removed.close( );
}
}
catch ( Throwable e )
{
log.error( "Could not initialize repositories from config: {}", e.getMessage( ), e );
return managedRepositories;
}
return managedRepositories;
}
@Override

View File

@ -0,0 +1,201 @@
package org.apache.archiva.repository.base.group;
/*
* 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.common.filelock.DefaultFileLockManager;
import org.apache.archiva.common.filelock.FileLockManager;
import org.apache.archiva.repository.EditableManagedRepository;
import org.apache.archiva.repository.EditableRepositoryGroup;
import org.apache.archiva.repository.ManagedRepository;
import org.apache.archiva.repository.RepositoryException;
import org.apache.archiva.repository.RepositoryGroup;
import org.apache.archiva.repository.RepositoryRegistry;
import org.apache.archiva.repository.base.ConfigurationHandler;
import org.apache.archiva.repository.base.managed.BasicManagedRepository;
import org.apache.archiva.repository.base.managed.BasicManagedRepositoryValidator;
import org.apache.archiva.repository.mock.ManagedRepositoryContentMock;
import org.apache.archiva.repository.storage.fs.FilesystemStorage;
import org.apache.archiva.repository.validation.ValidationResponse;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import javax.inject.Inject;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.nio.file.Paths;
import static org.junit.jupiter.api.Assertions.*;
/**
* @author Martin Stockhammer <martin_s@apache.org>
*/
@ExtendWith( SpringExtension.class)
@ContextConfiguration(locations = { "classpath*:/META-INF/spring-context.xml", "classpath:/spring-context.xml" })
class BasicRepositoryGroupValidatorTest
{
@Inject
ConfigurationHandler configurationHandler;
@Inject
RepositoryRegistry repositoryRegistry;
@SuppressWarnings( "unused" )
@Inject
RepositoryGroupHandler repositoryGroupHandler;
Path repoBaseDir;
@AfterEach
void cleanup() throws RepositoryException
{
repositoryRegistry.removeRepository("test");
}
protected EditableManagedRepository createRepository( String id, String name, Path location ) throws IOException
{
BasicManagedRepository repo = BasicManagedRepository.newFilesystemInstance(id, name, location);
repo.setLocation( location.toAbsolutePath().toUri());
repo.setContent(new ManagedRepositoryContentMock());
return repo;
}
protected EditableRepositoryGroup createGroup(String id, String name) throws IOException
{
return BasicRepositoryGroup.newFilesystemInstance( id, name, getRepoBaseDir( ).resolve( id ) );
}
private Path getRepoBaseDir() {
if (repoBaseDir==null) {
try
{
repoBaseDir = Paths.get(Thread.currentThread( ).getContextClassLoader( ).getResource( "repositories" ).toURI());
}
catch ( URISyntaxException e )
{
throw new RuntimeException( "Could not retrieve repository base directory" );
}
}
return repoBaseDir;
}
@Test
void apply( ) throws IOException
{
BasicRepositoryGroupValidator validator = new BasicRepositoryGroupValidator( configurationHandler );
EditableRepositoryGroup group = createGroup( "test", "test" );
group.setMergedIndexTTL( 360 );
ValidationResponse<RepositoryGroup> result = validator.apply( group );
assertNotNull( result );
assertTrue( result.isValid( ) );
}
@Test
void applyWithExisting( ) throws IOException, RepositoryException
{
BasicRepositoryGroupValidator validator = new BasicRepositoryGroupValidator( configurationHandler );
validator.setRepositoryRegistry( repositoryRegistry );
EditableRepositoryGroup group = createGroup( "test", "test" );
group.setMergedIndexTTL( 360 );
repositoryRegistry.putRepositoryGroup( group );
EditableRepositoryGroup group2 = createGroup( "test", "test2" );
group2.setMergedIndexTTL( 360 );
ValidationResponse<RepositoryGroup> result = validator.apply( group2 );
assertNotNull( result );
assertFalse( result.isValid( ) );
assertEquals( "group_exists", result.getResult( ).get( "id" ).get( 0 ).getType( ) );
}
@Test
void applyWithBadTTL( ) throws IOException
{
BasicRepositoryGroupValidator validator = new BasicRepositoryGroupValidator( configurationHandler );
EditableRepositoryGroup group = createGroup( "test", "test" );
group.setMergedIndexTTL( 0 );
ValidationResponse<RepositoryGroup> result = validator.apply( group );
assertNotNull( result );
assertFalse( result.isValid( ) );
assertTrue( result.getResult( ).containsKey( "merged_index_ttl" ) );
assertEquals( "repository_group", result.getResult( ).get( "merged_index_ttl" ).get( 0 ).getCategory( ) );
assertEquals( "min", result.getResult( ).get( "merged_index_ttl" ).get( 0 ).getType( ) );
assertEquals( "merged_index_ttl", result.getResult( ).get( "merged_index_ttl" ).get( 0 ).getAttribute() );
}
@Test
void applyWithNullObject( ) throws IOException
{
BasicRepositoryGroupValidator validator = new BasicRepositoryGroupValidator( configurationHandler );
EditableRepositoryGroup group = createGroup( "", "test" );
group.setMergedIndexTTL( 0 );
ValidationResponse<RepositoryGroup> result = validator.apply( null );
assertNotNull( result );
assertFalse( result.isValid( ) );
assertTrue( result.getResult( ).containsKey( "object" ) );
assertEquals( "repository_group", result.getResult( ).get( "object" ).get( 0 ).getCategory( ) );
assertEquals( "isnull", result.getResult( ).get( "object" ).get( 0 ).getType( ) );
assertEquals( "object", result.getResult( ).get( "object" ).get( 0 ).getAttribute() );
}
@Test
void applyWithEmptyId( ) throws IOException
{
BasicRepositoryGroupValidator validator = new BasicRepositoryGroupValidator( configurationHandler );
EditableRepositoryGroup group = createGroup( "", "test" );
group.setMergedIndexTTL( 0 );
ValidationResponse<RepositoryGroup> result = validator.apply( group );
assertNotNull( result );
assertFalse( result.isValid( ) );
assertTrue( result.getResult( ).containsKey( "id" ) );
assertEquals( "repository_group", result.getResult( ).get( "id" ).get( 0 ).getCategory( ) );
assertEquals( "empty", result.getResult( ).get( "id" ).get( 0 ).getType( ) );
assertEquals( "id", result.getResult( ).get( "id" ).get( 0 ).getAttribute() );
}
@Test
void applyWithBadName( ) throws IOException
{
BasicRepositoryGroupValidator validator = new BasicRepositoryGroupValidator( configurationHandler );
validator.setRepositoryRegistry( repositoryRegistry );
EditableRepositoryGroup group = createGroup( "test", "badtest\\name" );
group.setMergedIndexTTL( 360);
ValidationResponse<RepositoryGroup> result = validator.apply( group );
assertFalse( result.isValid( ) );
assertEquals( 1, result.getResult( ).size( ) );
assertEquals( "invalid_chars", result.getResult( ).get( "name" ).get( 0 ).getType( ) );
}
@Test
void getFlavour( )
{
BasicRepositoryGroupValidator validator = new BasicRepositoryGroupValidator( configurationHandler );
assertEquals( RepositoryGroup.class, validator.getFlavour( ) );
}
@Test
void isFlavour() {
BasicRepositoryGroupValidator validator = new BasicRepositoryGroupValidator( configurationHandler );
assertTrue( validator.isFlavour( RepositoryGroup.class ) );
assertFalse( validator.isFlavour( ManagedRepository.class ) );
assertTrue( validator.isFlavour( BasicRepositoryGroup.class ) );
}
}

View File

@ -20,29 +20,116 @@ package org.apache.archiva.repository.base.group;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
/**
* @author Martin Stockhammer <martin_s@apache.org>
*/
class BasicManagedRepositoryValidatorTest
class RepositoryGroupHandlerTest
{
@Test
void apply( )
void init( )
{
}
@Test
void applyForUpdate( )
void initializeFromConfig( )
{
}
@Test
void getFlavour( )
void initialize( )
{
}
@Test
void isFlavour( )
void newInstancesFromConfig( )
{
}
@Test
void newInstance( )
{
}
@Test
void testNewInstance( )
{
}
@Test
void put( )
{
}
@Test
void testPut( )
{
}
@Test
void testPut1( )
{
}
@Test
void putWithCheck( )
{
}
@Test
void remove( )
{
}
@Test
void testRemove( )
{
}
@Test
void get( )
{
}
@Test
void testClone( )
{
}
@Test
void updateReferences( )
{
}
@Test
void getAll( )
{
}
@Test
void getValidator( )
{
}
@Test
void validateRepository( )
{
}
@Test
void validateRepositoryForUpdate( )
{
}
@Test
void has( )
{
}
@Test
void close( )
{
}
}

View File

@ -0,0 +1,228 @@
package org.apache.archiva.repository.base.managed;
/*
* 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.common.filelock.DefaultFileLockManager;
import org.apache.archiva.common.filelock.FileLockManager;
import org.apache.archiva.configuration.ArchivaConfiguration;
import org.apache.archiva.repository.EditableManagedRepository;
import org.apache.archiva.repository.ManagedRepository;
import org.apache.archiva.repository.RepositoryException;
import org.apache.archiva.repository.RepositoryRegistry;
import org.apache.archiva.repository.base.ConfigurationHandler;
import org.apache.archiva.repository.base.group.RepositoryGroupHandler;
import org.apache.archiva.repository.mock.ManagedRepositoryContentMock;
import org.apache.archiva.repository.storage.fs.FilesystemStorage;
import org.apache.archiva.repository.validation.ValidationResponse;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import javax.inject.Inject;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.nio.file.Paths;
import static org.junit.jupiter.api.Assertions.*;
/**
* @author Martin Stockhammer <martin_s@apache.org>
*/
@ExtendWith( SpringExtension.class)
@ContextConfiguration(locations = { "classpath*:/META-INF/spring-context.xml", "classpath:/spring-context.xml" })
class BasicManagedRepositoryValidatorTest
{
@Inject
ConfigurationHandler configurationHandler;
@Inject
RepositoryRegistry repositoryRegistry;
@SuppressWarnings( "unused" )
@Inject
RepositoryGroupHandler repositoryGroupHandler;
Path repoBaseDir;
@AfterEach
void cleanup() {
try
{
repositoryRegistry.removeRepository( "test" );
}
catch ( RepositoryException e )
{
// Ignore this
}
}
protected EditableManagedRepository createRepository( String id, String name, Path location ) throws IOException
{
FileLockManager lockManager = new DefaultFileLockManager();
FilesystemStorage storage = new FilesystemStorage(location.toAbsolutePath(), lockManager);
BasicManagedRepository repo = new BasicManagedRepository(id, name, storage);
repo.setLocation( location.toAbsolutePath().toUri());
repo.setContent(new ManagedRepositoryContentMock());
return repo;
}
private Path getRepoBaseDir() {
if (repoBaseDir==null) {
try
{
repoBaseDir = Paths.get(Thread.currentThread( ).getContextClassLoader( ).getResource( "repositories" ).toURI());
}
catch ( URISyntaxException e )
{
throw new RuntimeException( "Could not retrieve repository base directory" );
}
}
return repoBaseDir;
}
@Test
void apply( ) throws IOException
{
BasicManagedRepositoryValidator validator = new BasicManagedRepositoryValidator( configurationHandler );
validator.setRepositoryRegistry( repositoryRegistry );
Path repoDir = getRepoBaseDir().resolve("test" );
EditableManagedRepository repo = createRepository( "test", "test", repoDir );
ValidationResponse<ManagedRepository> result = validator.apply( repo );
assertTrue( result.isValid( ) );
}
@Test
void applyWithExistingRepo( ) throws IOException, RepositoryException
{
BasicManagedRepositoryValidator validator = new BasicManagedRepositoryValidator( configurationHandler );
validator.setRepositoryRegistry( repositoryRegistry );
Path repoDir = getRepoBaseDir().resolve("test" );
EditableManagedRepository repo = createRepository( "test", "test", repoDir );
Path repoDir2 = getRepoBaseDir().resolve("test2" );
EditableManagedRepository repo2 = createRepository( "test", "test", repoDir2 );
repositoryRegistry.putRepository( repo );
ValidationResponse<ManagedRepository> result = validator.apply( repo );
assertFalse( result.isValid( ) );
assertEquals( 1, result.getResult( ).size( ) );
assertTrue( result.getResult( ).containsKey( "id" ) );
assertEquals( "managed_repository", result.getResult( ).get( "id" ).get( 0 ).getCategory( ) );
assertEquals( "managed_repo_exists", result.getResult( ).get( "id" ).get( 0 ).getType( ) );
assertEquals( "id", result.getResult( ).get( "id" ).get( 0 ).getAttribute() );
}
@Test
void applyUpdateWithExistingRepo( ) throws IOException, RepositoryException
{
BasicManagedRepositoryValidator validator = new BasicManagedRepositoryValidator( configurationHandler );
validator.setRepositoryRegistry( repositoryRegistry );
Path repoDir = getRepoBaseDir().resolve("test" );
EditableManagedRepository repo = createRepository( "test", "test", repoDir );
Path repoDir2 = getRepoBaseDir().resolve("test2" );
EditableManagedRepository repo2 = createRepository( "test", "test", repoDir2 );
repositoryRegistry.putRepository( repo );
ValidationResponse<ManagedRepository> result = validator.applyForUpdate( repo );
assertTrue( result.isValid( ) );
assertEquals( 0, result.getResult( ).size( ) );
}
@Test
void applyWithNullObject( ) throws IOException
{
BasicManagedRepositoryValidator validator = new BasicManagedRepositoryValidator( configurationHandler );
validator.setRepositoryRegistry( repositoryRegistry );
ValidationResponse<ManagedRepository> result = validator.apply( null );
assertFalse( result.isValid( ) );
assertEquals( 1, result.getResult( ).size( ) );
assertTrue( result.getResult( ).containsKey( "object" ) );
assertEquals( "managed_repository", result.getResult( ).get( "object" ).get( 0 ).getCategory( ) );
assertEquals( "isnull", result.getResult( ).get( "object" ).get( 0 ).getType( ) );
assertEquals( "object", result.getResult( ).get( "object" ).get( 0 ).getAttribute() );
}
@Test
void applyWithEmptyId( ) throws IOException
{
BasicManagedRepositoryValidator validator = new BasicManagedRepositoryValidator( configurationHandler );
validator.setRepositoryRegistry( repositoryRegistry );
Path repoDir = getRepoBaseDir().resolve("test" );
EditableManagedRepository repo = createRepository( "", "test", repoDir );
ValidationResponse<ManagedRepository> result = validator.apply( repo );
assertFalse( result.isValid( ) );
assertEquals( 1, result.getResult( ).size( ) );
assertTrue( result.getResult( ).containsKey( "id" ) );
assertEquals( "managed_repository", result.getResult( ).get( "id" ).get( 0 ).getCategory( ) );
assertEquals( "empty", result.getResult( ).get( "id" ).get( 0 ).getType( ) );
assertEquals( "id", result.getResult( ).get( "id" ).get( 0 ).getAttribute() );
}
@Test
void applyWithBadName( ) throws IOException
{
BasicManagedRepositoryValidator validator = new BasicManagedRepositoryValidator( configurationHandler );
validator.setRepositoryRegistry( repositoryRegistry );
Path repoDir = getRepoBaseDir().resolve("test" );
EditableManagedRepository repo = createRepository( "test", "badtest\\name", repoDir );
ValidationResponse<ManagedRepository> result = validator.apply( repo );
assertFalse( result.isValid( ) );
assertEquals( 1, result.getResult( ).size( ) );
assertEquals( "invalid_chars", result.getResult( ).get( "name" ).get( 0 ).getType( ) );
}
@Test
void applyWithBadSchedulingExpression( ) throws IOException
{
BasicManagedRepositoryValidator validator = new BasicManagedRepositoryValidator( configurationHandler );
validator.setRepositoryRegistry( repositoryRegistry );
Path repoDir = getRepoBaseDir().resolve("test" );
EditableManagedRepository repo = createRepository( "test", "test", repoDir );
repo.setSchedulingDefinition( "xxxxx" );
ValidationResponse<ManagedRepository> result = validator.apply( repo );
assertFalse( result.isValid( ) );
assertEquals( 1, result.getResult( ).size( ) );
assertEquals( "invalid_scheduling_exp", result.getResult( ).get( "scheduling_definition" ).get( 0 ).getType( ) );
}
@Test
void applyForUpdate( )
{
}
@Test
void getFlavour( )
{
BasicManagedRepositoryValidator validator = new BasicManagedRepositoryValidator( configurationHandler );
validator.setRepositoryRegistry( repositoryRegistry );
assertEquals( ManagedRepository.class, validator.getFlavour( ) );
}
@Test
void isFlavour( )
{
BasicManagedRepositoryValidator validator = new BasicManagedRepositoryValidator( configurationHandler );
validator.setRepositoryRegistry( repositoryRegistry );
assertTrue( validator.isFlavour( ManagedRepository.class ) );
assertTrue( validator.isFlavour( BasicManagedRepository.class ) );
}
}

View File

@ -55,6 +55,7 @@ public class RepositoryGroup implements Serializable
{
private static final long serialVersionUID = -7319687481737616081L;
private String id;
private String name;
private List<String> repositories = new ArrayList<>( );
private String location;
MergeConfiguration mergeConfiguration;
@ -72,6 +73,7 @@ public class RepositoryGroup implements Serializable
MergeConfiguration mergeConfig = new MergeConfiguration( );
result.setMergeConfiguration( mergeConfig );
result.setId( modelObj.getId() );
result.setName( modelObj.getName() );
result.setLocation( modelObj.getLocation().toString() );
result.setRepositories( modelObj.getRepositories().stream().map( Repository::getId ).collect( Collectors.toList()) );
if (modelObj.supportsFeature( IndexCreationFeature.class )) {
@ -133,6 +135,17 @@ public class RepositoryGroup implements Serializable
this.location = location;
}
@Schema(description = "The name of the repository group")
public String getName( )
{
return name;
}
public void setName( String name )
{
this.name = name;
}
@Override
public boolean equals( Object o )
{
@ -141,29 +154,21 @@ public class RepositoryGroup implements Serializable
RepositoryGroup that = (RepositoryGroup) o;
if ( !Objects.equals( id, that.id ) ) return false;
if ( !repositories.equals( that.repositories ) )
return false;
if ( !Objects.equals( location, that.location ) ) return false;
return Objects.equals( mergeConfiguration, that.mergeConfiguration );
return id.equals( that.id );
}
@Override
public int hashCode( )
{
int result = id != null ? id.hashCode( ) : 0;
result = 31 * result + repositories.hashCode( );
result = 31 * result + ( location != null ? location.hashCode( ) : 0 );
result = 31 * result + ( mergeConfiguration != null ? mergeConfiguration.hashCode( ) : 0 );
return result;
return id.hashCode( );
}
@SuppressWarnings( "StringBufferReplaceableByString" )
@Override
public String toString( )
{
final StringBuilder sb = new StringBuilder( "RepositoryGroup{" );
sb.append( "id='" ).append( id ).append( '\'' );
sb.append( ", name='" ).append( name ).append( '\'' );
sb.append( ", repositories=" ).append( repositories );
sb.append( ", location='" ).append( location ).append( '\'' );
sb.append( ", mergeConfiguration=" ).append( mergeConfiguration );

View File

@ -37,11 +37,11 @@ package org.apache.archiva.rest.services.v2;/*
import org.apache.archiva.components.rest.model.PagedResult;
import org.apache.archiva.components.rest.util.QueryHelper;
import org.apache.archiva.configuration.RepositoryGroupConfiguration;
import org.apache.archiva.repository.validation.CheckedResult;
import org.apache.archiva.repository.EditableRepositoryGroup;
import org.apache.archiva.repository.RepositoryException;
import org.apache.archiva.repository.RepositoryRegistry;
import org.apache.archiva.repository.base.ConfigurationHandler;
import org.apache.archiva.repository.validation.CheckedResult;
import org.apache.archiva.repository.validation.ValidationError;
import org.apache.archiva.rest.api.model.v2.MergeConfiguration;
import org.apache.archiva.rest.api.model.v2.RepositoryGroup;
@ -72,7 +72,7 @@ import java.util.stream.Collectors;
* @see RepositoryGroupService
* @since 3.0
*/
@Service("v2.repositoryGroupService#rest")
@Service( "v2.repositoryGroupService#rest" )
public class DefaultRepositoryGroupService implements RepositoryGroupService
{
private final ConfigurationHandler configurationHandler;
@ -86,9 +86,9 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
final private RepositoryRegistry repositoryRegistry;
private static final Logger log = LoggerFactory.getLogger( DefaultRepositoryGroupService.class );
private static final QueryHelper<org.apache.archiva.repository.RepositoryGroup> QUERY_HELPER = new QueryHelper<>( new String[]{"id"} );
static
{
QUERY_HELPER.addStringFilter( "id", org.apache.archiva.repository.RepositoryGroup::getId );
@ -96,7 +96,8 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
}
public DefaultRepositoryGroupService( RepositoryRegistry repositoryRegistry, ConfigurationHandler configurationHandler ) {
public DefaultRepositoryGroupService( RepositoryRegistry repositoryRegistry, ConfigurationHandler configurationHandler )
{
this.repositoryRegistry = repositoryRegistry;
this.configurationHandler = configurationHandler;
}
@ -137,10 +138,11 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
{
RepositoryGroupConfiguration result = new RepositoryGroupConfiguration( );
result.setId( group.getId( ) );
result.setName( group.getName() );
result.setLocation( group.getLocation( ) );
result.setRepositories( group.getRepositories( ) );
MergeConfiguration mergeConfig = group.getMergeConfiguration( );
if (mergeConfig!=null)
if ( mergeConfig != null )
{
result.setMergedIndexPath( mergeConfig.getMergedIndexPath( ) );
result.setMergedIndexTtl( mergeConfig.getMergedIndexTtlMinutes( ) );
@ -153,10 +155,12 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
public RepositoryGroup addRepositoryGroup( RepositoryGroup repositoryGroup ) throws ArchivaRestServiceException
{
final String groupId = repositoryGroup.getId( );
if ( StringUtils.isEmpty( groupId ) ) {
if ( StringUtils.isEmpty( groupId ) )
{
throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_INVALID_ID, groupId ), 422 );
}
if (repositoryRegistry.hasRepositoryGroup( groupId )) {
if ( repositoryRegistry.hasRepositoryGroup( groupId ) )
{
httpServletResponse.setHeader( "Location", uriInfo.getAbsolutePathBuilder( ).path( groupId ).build( ).toString( ) );
throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_ID_EXISTS, groupId ), 303 );
}
@ -165,13 +169,15 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
RepositoryGroupConfiguration configuration = toConfig( repositoryGroup );
CheckedResult<org.apache.archiva.repository.RepositoryGroup, Map<String, List<ValidationError>>> validationResult = repositoryRegistry.putRepositoryGroupAndValidate( configuration );
if ( validationResult.isValid( ) )
{
httpServletResponse.setStatus( 201 );
return RepositoryGroup.of( validationResult.getRepository() );
} else {
throw ValidationException.of( validationResult.getResult() );
}
if ( validationResult.isValid( ) )
{
httpServletResponse.setStatus( 201 );
return RepositoryGroup.of( validationResult.getRepository( ) );
}
else
{
throw ValidationException.of( validationResult.getResult( ) );
}
}
catch ( RepositoryException e )
{
@ -194,19 +200,21 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
try
{
RepositoryGroupConfiguration configuration = toConfig( repositoryGroup );
CheckedResult<org.apache.archiva.repository.RepositoryGroup, Map<String, List<ValidationError>>> validationResult = repositoryRegistry.putRepositoryGroupAndValidate( configuration );
if ( validationResult.isValid( ) )
{
httpServletResponse.setStatus( 201 );
return RepositoryGroup.of( validationResult.getRepository() );
} else {
throw ValidationException.of( validationResult.getResult() );
}
CheckedResult<org.apache.archiva.repository.RepositoryGroup, Map<String, List<ValidationError>>> validationResult = repositoryRegistry.putRepositoryGroupAndValidate( configuration );
if ( validationResult.isValid( ) )
{
httpServletResponse.setStatus( 201 );
return RepositoryGroup.of( validationResult.getRepository( ) );
}
else
{
throw ValidationException.of( validationResult.getResult( ) );
}
}
catch ( RepositoryException e )
{
log.error( "Exception during repository group update: {}", e.getMessage( ), e );
throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_UPDATE_FAILED, e.getMessage() ) );
throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_UPDATE_FAILED, e.getMessage( ) ) );
}
}
@ -221,7 +229,8 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
try
{
org.apache.archiva.repository.RepositoryGroup group = repositoryRegistry.getRepositoryGroup( repositoryGroupId );
if (group==null) {
if ( group == null )
{
throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_NOT_FOUND, "" ), 404 );
}
repositoryRegistry.removeRepositoryGroup( group );
@ -247,21 +256,24 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
try
{
org.apache.archiva.repository.RepositoryGroup repositoryGroup = repositoryRegistry.getRepositoryGroup( repositoryGroupId );
if (repositoryGroup==null) {
if ( repositoryGroup == null )
{
throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_NOT_FOUND, "" ), 404 );
}
if (!(repositoryGroup instanceof EditableRepositoryGroup )) {
if ( !( repositoryGroup instanceof EditableRepositoryGroup ) )
{
log.error( "This group instance is not editable: {}", repositoryGroupId );
throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_UPDATE_FAILED, "" ), 500 );
}
EditableRepositoryGroup editableRepositoryGroup = (EditableRepositoryGroup) repositoryGroup;
if ( editableRepositoryGroup.getRepositories().stream().anyMatch( repo -> repositoryId.equals(repo.getId())) )
if ( editableRepositoryGroup.getRepositories( ).stream( ).anyMatch( repo -> repositoryId.equals( repo.getId( ) ) ) )
{
log.info( "Repository {} is already member of group {}", repositoryId, repositoryGroupId );
return RepositoryGroup.of( editableRepositoryGroup );
}
org.apache.archiva.repository.ManagedRepository managedRepo = repositoryRegistry.getManagedRepository(repositoryId);
if (managedRepo==null) {
org.apache.archiva.repository.ManagedRepository managedRepo = repositoryRegistry.getManagedRepository( repositoryId );
if ( managedRepo == null )
{
throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_NOT_FOUND, "" ), 404 );
}
editableRepositoryGroup.addRepository( managedRepo );
@ -270,7 +282,7 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
}
catch ( RepositoryException e )
{
throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_UPDATE_FAILED, e.getMessage() ), 500 );
throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_UPDATE_FAILED, e.getMessage( ) ), 500 );
}
}
@ -288,13 +300,16 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
try
{
org.apache.archiva.repository.RepositoryGroup repositoryGroup = repositoryRegistry.getRepositoryGroup( repositoryGroupId );
if (repositoryGroup==null) {
if ( repositoryGroup == null )
{
throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_NOT_FOUND, "" ), 404 );
}
if (repositoryGroup.getRepositories().stream().noneMatch( r -> repositoryId.equals( r.getId() ) )) {
if ( repositoryGroup.getRepositories( ).stream( ).noneMatch( r -> repositoryId.equals( r.getId( ) ) ) )
{
throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_NOT_FOUND, repositoryId ), 404 );
}
if (!(repositoryGroup instanceof EditableRepositoryGroup)) {
if ( !( repositoryGroup instanceof EditableRepositoryGroup ) )
{
log.error( "This group instance is not editable: {}", repositoryGroupId );
throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_UPDATE_FAILED, "" ), 500 );
}
@ -305,7 +320,7 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
}
catch ( RepositoryException e )
{
throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_UPDATE_FAILED, e.getMessage() ), 500 );
throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_UPDATE_FAILED, e.getMessage( ) ), 500 );
}
}

View File

@ -92,11 +92,11 @@ public class NativeRepositoryGroupServiceTest extends AbstractNativeRestServices
{
Map<String, Object> jsonAsMap = new HashMap<>( );
jsonAsMap.put( "id", "group_001" );
jsonAsMap.put( "name", "group_001" );
Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON )
.when( )
.body( jsonAsMap )
.post( "" )
.prettyPeek()
.then( ).statusCode( 201 ).extract( ).response( );
assertNotNull( response );
RepositoryGroup result = response.getBody( ).jsonPath( ).getObject( "", RepositoryGroup.class );
@ -126,10 +126,12 @@ public class NativeRepositoryGroupServiceTest extends AbstractNativeRestServices
{
Map<String, Object> jsonAsMap = new HashMap<>( );
jsonAsMap.put( "id", "group_001" );
jsonAsMap.put( "name", "group_001" );
Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON )
.when( )
.body( jsonAsMap )
.post( "" )
.prettyPeek()
.then( ).statusCode( 201 ).extract( ).response( );
assertNotNull( response );
response = given( ).spec( getRequestSpec( token ) ).contentType( JSON )
@ -145,8 +147,7 @@ public class NativeRepositoryGroupServiceTest extends AbstractNativeRestServices
{
given( ).spec( getRequestSpec( token ) ).contentType( JSON )
.when( )
.delete( "group_001" )
.then( ).statusCode( 200 );
.delete( "group_001" );
}
}
@ -164,6 +165,7 @@ public class NativeRepositoryGroupServiceTest extends AbstractNativeRestServices
groups.add( groupName );
Map<String, Object> jsonAsMap = new HashMap<>( );
jsonAsMap.put( "id", groupName );
jsonAsMap.put( "name", groupName );
Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON )
.when( )
.body( jsonAsMap )
@ -186,8 +188,7 @@ public class NativeRepositoryGroupServiceTest extends AbstractNativeRestServices
{
given( ).spec( getRequestSpec( token ) ).contentType( JSON )
.when( )
.delete( groupName )
.then( ).statusCode( 200 );
.delete( groupName );
}
}
}
@ -205,6 +206,7 @@ public class NativeRepositoryGroupServiceTest extends AbstractNativeRestServices
groups.add( groupName );
Map<String, Object> jsonAsMap = new HashMap<>( );
jsonAsMap.put( "id", groupName );
jsonAsMap.put( "name", groupName );
Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON )
.when( )
.body( jsonAsMap )
@ -251,8 +253,7 @@ public class NativeRepositoryGroupServiceTest extends AbstractNativeRestServices
{
given( ).spec( getRequestSpec( token ) ).contentType( JSON )
.when( )
.delete( groupName )
.then( ).statusCode( 200 );
.delete( groupName );
}
}
}
@ -267,6 +268,7 @@ public class NativeRepositoryGroupServiceTest extends AbstractNativeRestServices
{
Map<String, Object> jsonAsMap = new HashMap<>( );
jsonAsMap.put( "id", "group_001" );
jsonAsMap.put( "name", "group_001" );
Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON )
.when( )
.body( jsonAsMap )
@ -302,8 +304,7 @@ public class NativeRepositoryGroupServiceTest extends AbstractNativeRestServices
{
given( ).spec( getRequestSpec( token ) ).contentType( JSON )
.when( )
.delete( "group_001" )
.then( ).statusCode( 200 );
.delete( "group_001" );
}
}
@ -315,6 +316,7 @@ public class NativeRepositoryGroupServiceTest extends AbstractNativeRestServices
{
Map<String, Object> jsonAsMap = new HashMap<>( );
jsonAsMap.put( "id", "group_001" );
jsonAsMap.put( "name", "group_001" );
Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON )
.when( )
.body( jsonAsMap )
@ -371,6 +373,7 @@ public class NativeRepositoryGroupServiceTest extends AbstractNativeRestServices
{
Map<String, Object> jsonAsMap = new HashMap<>( );
jsonAsMap.put( "id", "group_001" );
jsonAsMap.put( "name", "group_001" );
jsonAsMap.put( "repositories", Arrays.asList( "internal" ) );
Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON )
.when( )
@ -423,6 +426,7 @@ public class NativeRepositoryGroupServiceTest extends AbstractNativeRestServices
{
Map<String, Object> jsonAsMap = new HashMap<>( );
jsonAsMap.put( "id", "group_001" );
jsonAsMap.put( "name", "group_001" );
jsonAsMap.put( "repositories", Arrays.asList( "internal" ) );
Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON )
.when( )
@ -460,8 +464,7 @@ public class NativeRepositoryGroupServiceTest extends AbstractNativeRestServices
{
given( ).spec( getRequestSpec( token ) ).contentType( JSON )
.when( )
.delete( "group_001" )
.then( ).statusCode( 200 );
.delete( "group_001" );
}
}