Refactoring group handling

This commit is contained in:
Martin Stockhammer 2021-06-29 21:09:52 +02:00
parent e8a70027d8
commit 478c60608d
9 changed files with 190 additions and 86 deletions

View File

@ -19,6 +19,7 @@ package org.apache.archiva.repository;
import org.apache.archiva.configuration.Configuration;
import org.apache.archiva.repository.validation.RepositoryChecker;
import org.apache.archiva.repository.validation.RepositoryValidator;
import java.util.Collection;
import java.util.Map;
@ -158,6 +159,12 @@ public interface RepositoryHandler<R extends Repository, C>
*/
Collection<R> getAll();
/**
* Returns a validator that can be used to validate repository data
* @return a validator instance
*/
RepositoryValidator<R> getValidator( );
/**
* Returns <code>true</code>, if the repository is registered with the given id, otherwise <code>false</code>
* @param id the repository identifier

View File

@ -52,6 +52,7 @@ import org.apache.archiva.repository.RepositoryProvider;
import org.apache.archiva.repository.RepositoryRegistry;
import org.apache.archiva.repository.RepositoryType;
import org.apache.archiva.repository.UnsupportedRepositoryTypeException;
import org.apache.archiva.repository.base.validation.CommonGroupValidator;
import org.apache.archiva.repository.event.LifecycleEvent;
import org.apache.archiva.repository.event.RepositoryEvent;
import org.apache.archiva.repository.event.RepositoryIndexEvent;
@ -136,9 +137,6 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
private RepositoryGroupHandler groupHandler;
private final Set<RepositoryValidator<? extends Repository>> validators;
private final RepositoryChecker<RepositoryGroup, Map<String, List<ValidationError>>> groupChecker;
private final RepositoryChecker<ManagedRepository, Map<String, List<ValidationError>>> managedChecker;
private final RepositoryChecker<RemoteRepository, Map<String, List<ValidationError>>> remoteChecker;
private final ConfigurationHandler configurationHandler;
@ -152,27 +150,8 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
this.eventManager = new EventManager( this );
this.configurationHandler = configurationHandler;
this.validators = initValidatorList( validatorList );
this.groupChecker = initChecker( RepositoryGroup.class );
this.managedChecker = initChecker( ManagedRepository.class );
this.remoteChecker = initChecker( RemoteRepository.class );
}
private <R extends Repository> RepositoryChecker<R, Map<String, List<ValidationError>>> initChecker(Class<R> clazz) {
return new RepositoryChecker<R, Map<String, List<ValidationError>>>( )
{
@Override
public CheckedResult<R, Map<String, List<ValidationError>>> apply( R repositoryGroup )
{
return this.apply( repositoryGroup );
}
@Override
public CheckedResult<R, Map<String, List<ValidationError>>> applyForUpdate( R repo )
{
return this.applyForUpdate( repo );
}
};
}
private Set<RepositoryValidator<? extends Repository>> initValidatorList( List<RepositoryValidator<? extends Repository>> validators )
{
@ -909,7 +888,7 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
rwLock.writeLock( ).lock( );
try
{
return groupHandler.putWithCheck( repositoryGroupConfiguration, this.groupChecker );
return groupHandler.putWithCheck( repositoryGroupConfiguration, groupHandler.getValidator() );
}
finally
{

View File

@ -36,6 +36,7 @@ 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.RepositoryChecker;
import org.apache.archiva.repository.validation.RepositoryValidator;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -74,9 +75,11 @@ public class RepositoryGroupHandler implements RepositoryHandler<RepositoryGroup
private final MergedRemoteIndexesScheduler mergedRemoteIndexesScheduler;
private final Map<String, RepositoryGroup> repositoryGroups = new HashMap<>( );
private final RepositoryValidator<RepositoryGroup> validator;
private Path groupsDirectory;
/**
* Creates a new instance. All dependencies are injected on the constructor.
*
@ -86,11 +89,14 @@ public class RepositoryGroupHandler implements RepositoryHandler<RepositoryGroup
*/
public RepositoryGroupHandler( ArchivaRepositoryRegistry repositoryRegistry,
ConfigurationHandler configurationHandler,
@Named( "mergedRemoteIndexesScheduler#default" ) MergedRemoteIndexesScheduler mergedRemoteIndexesScheduler )
@Named( "mergedRemoteIndexesScheduler#default" ) MergedRemoteIndexesScheduler mergedRemoteIndexesScheduler,
@Named( "repositoryValidator#common#group") RepositoryValidator<RepositoryGroup> repositoryGroupValidator
)
{
this.configurationHandler = configurationHandler;
this.mergedRemoteIndexesScheduler = mergedRemoteIndexesScheduler;
this.repositoryRegistry = repositoryRegistry;
this.validator = repositoryGroupValidator;
}
@Override
@ -552,6 +558,12 @@ public class RepositoryGroupHandler implements RepositoryHandler<RepositoryGroup
return repositoryGroups.values( );
}
@Override
public RepositoryValidator<RepositoryGroup> getValidator( )
{
return this.validator;
}
@Override
public boolean has( String id )
{

View File

@ -26,9 +26,11 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Exception is thrown
*
* @author Martin Stockhammer <martin_s@apache.org>
*/
public class ValidationException extends ArchivaRestServiceException
@ -39,27 +41,41 @@ public class ValidationException extends ArchivaRestServiceException
private List<ValidationError> validationErrors;
public ValidationException( ) {
public ValidationException( )
{
super( DEFAULT_MESSAGE, DEFAULT_CODE );
}
public ValidationException( int errorCode) {
public ValidationException( int errorCode )
{
super( DEFAULT_MESSAGE, errorCode );
}
public ValidationException( List<ValidationError> errors) {
public ValidationException( List<ValidationError> errors )
{
super( DEFAULT_MESSAGE, DEFAULT_CODE );
this.validationErrors = errors;
}
public static ValidationException of( List<org.apache.archiva.repository.validation.ValidationError> errorList ) {
public static ValidationException of( List<org.apache.archiva.repository.validation.ValidationError> errorList )
{
return new ValidationException( errorList.stream( ).map( ValidationError::of ).collect( Collectors.toList( ) ) );
}
public static <R extends Repository> ValidationException of( ValidationResponse<R> result ) {
if (result.isValid()) {
public static ValidationException of( Map<String, List<org.apache.archiva.repository.validation.ValidationError>> errorMap )
{
return new ValidationException( errorMap.entrySet( ).stream( )
.flatMap( v -> v.getValue( ).stream( ).map( k -> ValidationError.of(v.getKey(), k)))
.collect( Collectors.toList( ) ) );
}
public static <R extends Repository> ValidationException of( ValidationResponse<R> result )
{
if ( result.isValid( ) )
{
return new ValidationException( );
} else
}
else
{
return new ValidationException( result.getResult( ).entrySet( ).stream( ).flatMap(
v -> v.getValue( ).stream( ).map( e -> ValidationError.of( v.getKey( ), e ) ) ).collect( Collectors.toList( ) ) );
@ -68,7 +84,7 @@ public class ValidationException extends ArchivaRestServiceException
public List<ValidationError> getValidationErrors( )
{
return validationErrors==null? Collections.emptyList() : validationErrors;
return validationErrors == null ? Collections.emptyList( ) : validationErrors;
}
public void setValidationErrors( List<ValidationError> validationErrors )
@ -76,8 +92,10 @@ public class ValidationException extends ArchivaRestServiceException
this.validationErrors = validationErrors;
}
public void addValidationError( ValidationError error) {
if (this.validationErrors==null) {
public void addValidationError( ValidationError error )
{
if ( this.validationErrors == null )
{
this.validationErrors = new ArrayList<>( );
}
this.validationErrors.add( error );

View File

@ -54,7 +54,7 @@ public class ArchivaRestServiceExceptionMapper
public Response.Status.Family getFamily()
{
return Response.Status.Family.SERVER_ERROR;
return Response.Status.Family.familyOf( e.getHttpErrorCode( ) );
}
public String getReasonPhrase()

View File

@ -40,11 +40,14 @@ import org.apache.archiva.components.rest.util.QueryHelper;
import org.apache.archiva.configuration.Configuration;
import org.apache.archiva.configuration.IndeterminateConfigurationException;
import org.apache.archiva.configuration.RepositoryGroupConfiguration;
import org.apache.archiva.repository.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.ValidationError;
import org.apache.archiva.repository.validation.ValidationResponse;
import org.apache.archiva.rest.api.model.v2.MergeConfiguration;
import org.apache.archiva.rest.api.model.v2.RepositoryGroup;
import org.apache.archiva.rest.api.services.v2.ArchivaRestServiceException;
import org.apache.archiva.rest.api.services.v2.ErrorKeys;
@ -62,6 +65,7 @@ import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@ -139,9 +143,13 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
result.setId( group.getId( ) );
result.setLocation( group.getLocation( ) );
result.setRepositories( group.getRepositories( ) );
result.setMergedIndexPath( group.getMergeConfiguration( ).getMergedIndexPath( ) );
result.setMergedIndexTtl( group.getMergeConfiguration( ).getMergedIndexTtlMinutes( ) );
result.setCronExpression( group.getMergeConfiguration( ).getIndexMergeSchedule( ) );
MergeConfiguration mergeConfig = group.getMergeConfiguration( );
if (mergeConfig!=null)
{
result.setMergedIndexPath( mergeConfig.getMergedIndexPath( ) );
result.setMergedIndexTtl( mergeConfig.getMergedIndexTtlMinutes( ) );
result.setCronExpression( mergeConfig.getIndexMergeSchedule( ) );
}
return result;
}
@ -158,27 +166,18 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
}
try
{
RepositoryGroupConfiguration configuration = toConfig( repositoryGroup );
Configuration config = configurationHandler.getBaseConfiguration( );
org.apache.archiva.repository.RepositoryGroup repo = repositoryRegistry.putRepositoryGroup( configuration, config);
if ( repo!=null )
{
ValidationResponse<org.apache.archiva.repository.RepositoryGroup> validationResult = repositoryRegistry.validateRepository( repo );
CheckedResult<org.apache.archiva.repository.RepositoryGroup, Map<String, List<ValidationError>>> validationResult = repositoryRegistry.putRepositoryGroupAndValidate( configuration );
if ( validationResult.isValid( ) )
{
httpServletResponse.setStatus( 201 );
configurationHandler.save( config );
return RepositoryGroup.of( repo );
return RepositoryGroup.of( validationResult.getRepository() );
} else {
throw ValidationException.of( validationResult );
throw ValidationException.of( validationResult.getResult() );
}
}
else
{
throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_ADD_FAILED ) );
}
}
catch ( RepositoryException | IndeterminateConfigurationException | RegistryException e )
catch ( RepositoryException e )
{
throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_ADD_FAILED ) );
}
@ -196,32 +195,19 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_NOT_FOUND ), 404 );
}
repositoryGroup.setId( repositoryGroupId );
try
{
RepositoryGroupConfiguration configuration = toConfig( repositoryGroup );
Configuration config = configurationHandler.getBaseConfiguration( );
org.apache.archiva.repository.RepositoryGroup repo = repositoryRegistry.putRepositoryGroup( configuration, config);
if ( repo!=null )
{
ValidationResponse<org.apache.archiva.repository.RepositoryGroup> validationResult = repositoryRegistry.validateRepository( repo );
CheckedResult<org.apache.archiva.repository.RepositoryGroup, Map<String, List<ValidationError>>> validationResult = repositoryRegistry.putRepositoryGroupAndValidate( configuration );
if ( validationResult.isValid( ) )
{
httpServletResponse.setStatus( 201 );
configurationHandler.save( config );
return RepositoryGroup.of( repo );
return RepositoryGroup.of( validationResult.getRepository() );
} else {
throw ValidationException.of( validationResult );
throw ValidationException.of( validationResult.getResult() );
}
}
else
{
log.error( "Returned repository group was null {}", repositoryGroupId );
throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_UPDATE_FAILED ) );
}
}
catch ( RepositoryException | IndeterminateConfigurationException | RegistryException e )
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() ) );

View File

@ -487,9 +487,8 @@ public abstract class AbstractNativeRestServices
Response result = given( ).spec( getAuthRequestSpecBuilder().build() )
.contentType( JSON )
.body( jsonAsMap )
.when( ).post( "/authenticate").prettyPeek().then( ).statusCode( 200 )
.when( ).post( "/authenticate").then( ).statusCode( 200 )
.extract( ).response( );
result.getBody( ).prettyPrint( );
return result.body( ).jsonPath( ).getString( "access_token" );
}
protected String getAdminToken() {

View File

@ -20,10 +20,7 @@ package org.apache.archiva.rest.services.v2;
import io.restassured.response.Response;
import org.apache.archiva.components.rest.model.PagedResult;
import org.apache.archiva.components.rest.model.PropertyEntry;
import org.apache.archiva.rest.api.model.v2.BeanInformation;
import org.apache.archiva.rest.api.model.v2.CacheConfiguration;
import org.apache.archiva.rest.api.model.v2.LdapConfiguration;
import org.apache.archiva.rest.api.model.v2.RepositoryGroup;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
@ -33,14 +30,17 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestMethodOrder;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static io.restassured.RestAssured.given;
import static io.restassured.http.ContentType.JSON;
import static org.junit.jupiter.api.Assertions.*;
import static org.easymock.EasyMock.contains;
import static org.hamcrest.Matchers.endsWith;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
/**
* @author Martin Stockhammer <martin_s@apache.org>
@ -70,16 +70,125 @@ public class NativeRepositoryGroupServiceTest extends AbstractNativeRestServices
}
@Test
void testGetConfiguration() {
void testGetEmptyList( )
{
String token = getAdminToken( );
Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON )
.when( )
.get( "" )
.then( ).statusCode( 200 ).extract( ).response( );
assertNotNull( response );
PagedResult result = response.getBody( ).jsonPath( ).getObject( "", PagedResult.class );
assertEquals( 0, result.getPagination( ).getTotalCount( ) );
}
@Test
void testAddGroup( )
{
String token = getAdminToken( );
try
{
Map<String, Object> jsonAsMap = new HashMap<>( );
jsonAsMap.put( "id", "group_001" );
Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON )
.when( )
.get( "" )
.body( jsonAsMap )
.post( "" )
.prettyPeek()
.then( ).statusCode( 201 ).extract( ).response( );
assertNotNull( response );
RepositoryGroup result = response.getBody( ).jsonPath( ).getObject( "", RepositoryGroup.class );
assertNotNull( result );
response = given( ).spec( getRequestSpec( token ) ).contentType( JSON )
.when( )
.get( "" )
.then( ).statusCode( 200 ).extract( ).response( );
assertNotNull( response );
assertNotNull( response );
PagedResult resultList = response.getBody( ).jsonPath( ).getObject( "", PagedResult.class );
assertEquals( 1, resultList.getPagination( ).getTotalCount( ) );
} finally
{
given( ).spec( getRequestSpec( token ) ).contentType( JSON )
.when( )
.delete( "group_001" )
.then( ).statusCode( 200 );
}
}
@Test
void testAddExistingGroup( )
{
String token = getAdminToken( );
try
{
Map<String, Object> jsonAsMap = new HashMap<>( );
jsonAsMap.put( "id", "group_001" );
Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON )
.when( )
.body( jsonAsMap )
.post( "" )
.then( ).statusCode( 201 ).extract( ).response( );
assertNotNull( response );
response = given( ).spec( getRequestSpec( token ) ).contentType( JSON )
.when( )
.redirects().follow( false )
.body( jsonAsMap )
.post( "" )
.prettyPeek()
.then( ).statusCode( 303 )
.assertThat()
.header( "Location", endsWith("group_001") ).extract( ).response( );
} finally
{
given( ).spec( getRequestSpec( token ) ).contentType( JSON )
.when( )
.delete( "group_001" )
.then( ).statusCode( 200 );
}
}
@Test
void testAddMultipleGroups( )
{
String token = getAdminToken( );
List<String> groups = new ArrayList<>( );
try
{
for ( int i=0; i<10; i++)
{
String groupName = String.format( "group_%03d", i );
groups.add( groupName );
Map<String, Object> jsonAsMap = new HashMap<>( );
jsonAsMap.put( "id", groupName );
Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON )
.when( )
.body( jsonAsMap )
.post( "" )
.then( ).statusCode( 201 ).extract( ).response( );
assertNotNull( response );
RepositoryGroup result = response.getBody( ).jsonPath( ).getObject( "", RepositoryGroup.class );
assertNotNull( result );
}
Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON )
.when( )
.get( "" )
.then( ).statusCode( 200 ).extract( ).response( );
assertNotNull( response );
PagedResult resultList = response.getBody( ).jsonPath( ).getObject( "", PagedResult.class );
assertEquals( 10, resultList.getPagination( ).getTotalCount( ) );
} finally
{
for (String groupName : groups)
{
given( ).spec( getRequestSpec( token ) ).contentType( JSON )
.when( )
.delete( groupName )
.then( ).statusCode( 200 );
}
}
}
}

View File

@ -69,7 +69,6 @@ public class NativeRepositoryServiceTest extends AbstractNativeRestServices
Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON )
.when( )
.get( "" )
.prettyPeek()
.then( ).statusCode( 200 ).extract( ).response( );
assertNotNull( response );
PagedResult<Repository> repositoryPagedResult = response.getBody( ).jsonPath( ).getObject( "", PagedResult.class );
@ -102,7 +101,6 @@ public class NativeRepositoryServiceTest extends AbstractNativeRestServices
.when( )
.queryParam( "q", "central" )
.get( "" )
.prettyPeek()
.then( ).statusCode( 200 ).extract( ).response( );
assertNotNull( response );
PagedResult<Repository> repositoryPagedResult = response.getBody( ).jsonPath( ).getObject( "", PagedResult.class );
@ -118,7 +116,6 @@ public class NativeRepositoryServiceTest extends AbstractNativeRestServices
Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON )
.when( )
.get( "managed/internal/statistics" )
.prettyPeek()
.then( ).statusCode( 200 ).extract( ).response( );
assertNotNull( response );
@ -130,7 +127,6 @@ public class NativeRepositoryServiceTest extends AbstractNativeRestServices
Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON )
.when( )
.post( "managed/internal/scan/schedule" )
.prettyPeek()
.then( ).statusCode( 200 ).extract( ).response( );
assertNotNull( response );
@ -142,7 +138,6 @@ public class NativeRepositoryServiceTest extends AbstractNativeRestServices
Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON )
.when( )
.post( "managed/internal/scan/now" )
.prettyPeek()
.then( ).statusCode( 200 ).extract( ).response( );
assertNotNull( response );
@ -154,7 +149,6 @@ public class NativeRepositoryServiceTest extends AbstractNativeRestServices
Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON )
.when( )
.get( "managed/internal/scan/status" )
.prettyPeek()
.then( ).statusCode( 200 ).extract( ).response( );
assertNotNull( response );