From 11d469489e533a0e038b0a44e732595efcd082ed Mon Sep 17 00:00:00 2001 From: Martin Stockhammer Date: Sun, 4 Jul 2021 17:10:10 +0200 Subject: [PATCH] Additional tests and refactoring --- .../archiva/configuration/Configuration.java | 10 +- .../archiva/repository/RepositoryHandler.java | 52 ++-- .../repository/features/AbstractFeature.java | 5 +- .../features/IndexCreationFeature.java | 2 +- .../repository/validation/ErrorKeys.java | 4 +- .../validation/RepositoryValidator.java | 2 + .../repository/base/AbstractRepository.java | 8 - .../base/AbstractRepositoryHandler.java | 49 ++++ .../base/group/BasicRepositoryGroup.java | 181 ++++++++++++++ .../group/BasicRepositoryGroupValidator.java | 26 +- .../base/group/RepositoryGroupHandler.java | 47 ++-- .../BasicManagedRepositoryValidator.java | 7 +- .../managed/ManagedRepositoryHandler.java | 87 ++++++- .../BasicRepositoryGroupValidatorTest.java | 201 +++++++++++++++ ...t.java => RepositoryGroupHandlerTest.java} | 97 +++++++- .../BasicManagedRepositoryValidatorTest.java | 228 ++++++++++++++++++ .../rest/api/model/v2/RepositoryGroup.java | 27 ++- .../v2/DefaultRepositoryGroupService.java | 83 ++++--- .../v2/NativeRepositoryGroupServiceTest.java | 25 +- 19 files changed, 1002 insertions(+), 139 deletions(-) create mode 100644 archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/AbstractRepositoryHandler.java create mode 100644 archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/group/BasicRepositoryGroup.java create mode 100644 archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/base/group/BasicRepositoryGroupValidatorTest.java rename archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/base/group/{BasicManagedRepositoryValidatorTest.java => RepositoryGroupHandlerTest.java} (51%) create mode 100644 archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/base/managed/BasicManagedRepositoryValidatorTest.java diff --git a/archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/Configuration.java b/archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/Configuration.java index 4d62e81ea..1bd3bcef2 100644 --- a/archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/Configuration.java +++ b/archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/Configuration.java @@ -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) repositoryGroups ) - { - if ( group.getId().equals( id ) ) - { - return group; - } - } + return ( (java.util.List) repositoryGroups ).stream( ).filter( g -> g != null && id.equals( g.getId( ) ) ).findFirst( ).orElse( null ); } return null; } diff --git a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryHandler.java b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryHandler.java index 5dbcfe534..5ff5263d8 100644 --- a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryHandler.java +++ b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryHandler.java @@ -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 */ @@ -36,21 +38,32 @@ public interface RepositoryHandler { /** - * 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 newInstancesFromConfig(); + Map 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 * 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 * 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 */ CheckedResult - putWithCheck( C repositoryConfiguration, RepositoryChecker checker) throws RepositoryException; + putWithCheck( C repositoryConfiguration, RepositoryChecker 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 * 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 * @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 configuration instance. @@ -149,7 +162,7 @@ public interface RepositoryHandler * 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 * * @return the list of repositories */ - Collection getAll(); + Collection getAll( ); /** * Returns a validator that can be used to validate repository data + * * @return a validator instance */ RepositoryValidator getValidator( ); @@ -175,7 +189,7 @@ public interface RepositoryHandler * @param repository the repository to validate against * @return the result of the validation. */ - ValidationResponse validateRepository( R repository); + CheckedResult>> 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 * @param repository the repository to validate against * @return the result of the validation. */ - ValidationResponse validateRepositoryForUpdate( R repository); - + CheckedResult>> validateRepositoryForUpdate( R repository ); /** * Returns true, if the repository is registered with the given id, otherwise false + * * @param id the repository identifier * @return true, if it is registered, otherwise false */ - boolean has(String id); + boolean has( String id ); /** * Initializes */ - void init(); + void init( ); /** * Closes the handler */ - void close(); + void close( ); } diff --git a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/features/AbstractFeature.java b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/features/AbstractFeature.java index d74d0eb65..2aeeb3b9f 100644 --- a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/features/AbstractFeature.java +++ b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/features/AbstractFeature.java @@ -34,7 +34,10 @@ public class AbstractFeature { } AbstractFeature(EventHandler listener) { - this.listener.add(listener); + if (listener!=null) + { + this.listener.add( listener ); + } } AbstractFeature(Collection listeners) { diff --git a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/features/IndexCreationFeature.java b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/features/IndexCreationFeature.java index fafd2763f..7f5874edd 100644 --- a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/features/IndexCreationFeature.java +++ b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/features/IndexCreationFeature.java @@ -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 */ diff --git a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/validation/ErrorKeys.java b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/validation/ErrorKeys.java index 315d4dfc4..41808c2ca 100644 --- a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/validation/ErrorKeys.java +++ b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/validation/ErrorKeys.java @@ -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"; } diff --git a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/validation/RepositoryValidator.java b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/validation/RepositoryValidator.java index 25382b31b..c411f64dc 100644 --- a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/validation/RepositoryValidator.java +++ b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/validation/RepositoryValidator.java @@ -34,7 +34,9 @@ public interface RepositoryValidator 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._/~:?!&=\\\\]+$"; diff --git a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/AbstractRepository.java b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/AbstractRepository.java index 843045071..c92e2275a 100644 --- a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/AbstractRepository.java +++ b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/AbstractRepository.java @@ -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; } diff --git a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/AbstractRepositoryHandler.java b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/AbstractRepositoryHandler.java new file mode 100644 index 000000000..4637687a4 --- /dev/null +++ b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/AbstractRepositoryHandler.java @@ -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 + */ +public abstract class AbstractRepositoryHandler implements RepositoryHandler +{ + 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 getCombinedValidatdor(Class clazz, List> repositoryGroupValidatorList) { + return new CombinedValidator<>( clazz, initValidators( clazz, repositoryGroupValidatorList ) ); + } + +} diff --git a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/group/BasicRepositoryGroup.java b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/group/BasicRepositoryGroup.java new file mode 100644 index 000000000..7f3df8554 --- /dev/null +++ b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/group/BasicRepositoryGroup.java @@ -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 + */ +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 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 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 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); + } + +} diff --git a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/group/BasicRepositoryGroupValidator.java b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/group/BasicRepositoryGroupValidator.java index 308dd3aed..209499ffc 100644 --- a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/group/BasicRepositoryGroupValidator.java +++ b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/group/BasicRepositoryGroupValidator.java @@ -45,7 +45,9 @@ public class BasicRepositoryGroupValidator extends AbstractRepositoryValidator apply( RepositoryGroup repositoryGroup, boolean updateMode ) throws IllegalArgumentException { - final String repoGroupId = repositoryGroup.getId( ); Map> 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 */ @Service( "repositoryGroupHandler#default" ) -public class RepositoryGroupHandler implements RepositoryHandler +public class RepositoryGroupHandler + extends AbstractRepositoryHandler + implements RepositoryHandler { private static final Logger log = LoggerFactory.getLogger( RepositoryGroupHandler.class ); @@ -90,28 +93,18 @@ public class RepositoryGroupHandler implements RepositoryHandler> repositoryGroupValidatorList + List> repositoryValidatorList ) { this.configurationHandler = configurationHandler; this.mergedRemoteIndexesScheduler = mergedRemoteIndexesScheduler; this.repositoryRegistry = repositoryRegistry; - List> validatorList = initValidators( repositoryGroupValidatorList ); - this.validator = new CombinedValidator<>( RepositoryGroup.class, validatorList ); - } - - private List> initValidators(List> 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 validateRepository( RepositoryGroup repository ) + public CheckedResult>> validateRepository( RepositoryGroup repository ) { - return null; + return this.validator.apply( repository ); + } @Override - public ValidationResponse validateRepositoryForUpdate( RepositoryGroup repository ) + public CheckedResult>> validateRepositoryForUpdate( RepositoryGroup repository ) { - return null; + return this.validator.applyForUpdate( repository ); } - @Override public boolean has( String id ) { diff --git a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/managed/BasicManagedRepositoryValidator.java b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/managed/BasicManagedRepositoryValidator.java index 5b9e3a739..745ed9d85 100644 --- a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/managed/BasicManagedRepositoryValidator.java +++ b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/managed/BasicManagedRepositoryValidator.java @@ -64,7 +64,8 @@ public class BasicManagedRepositoryValidator extends AbstractRepositoryValidator { Map> 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( ); diff --git a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/managed/ManagedRepositoryHandler.java b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/managed/ManagedRepositoryHandler.java index 3aa65dea2..c7b10c6e5 100644 --- a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/managed/ManagedRepositoryHandler.java +++ b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/managed/ManagedRepositoryHandler.java @@ -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 */ public class ManagedRepositoryHandler + extends AbstractRepositoryHandler implements RepositoryHandler { + private static final Logger log = LoggerFactory.getLogger( ManagedRepositoryHandler.class ); + private final ConfigurationHandler configurationHandler; + private final ArchivaRepositoryRegistry repositoryRegistry; + private final RepositoryValidator validator; + private Map managedRepositories = new HashMap<>( ); + private Map uManagedRepositories = Collections.unmodifiableMap( managedRepositories ); + public ManagedRepositoryHandler( ArchivaRepositoryRegistry repositoryRegistry, ConfigurationHandler configurationHandler, - @Named( "repositoryValidator#common#managed") RepositoryValidator managedRepositoryValidator ) + List> 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 newInstancesFromConfig( ) { - return null; + try + { + Set configRepoIds = new HashSet<>( ); + List 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 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 diff --git a/archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/base/group/BasicRepositoryGroupValidatorTest.java b/archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/base/group/BasicRepositoryGroupValidatorTest.java new file mode 100644 index 000000000..c049b47bd --- /dev/null +++ b/archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/base/group/BasicRepositoryGroupValidatorTest.java @@ -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 + */ +@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 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 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 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 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 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 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 ) ); + } +} \ No newline at end of file diff --git a/archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/base/group/BasicManagedRepositoryValidatorTest.java b/archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/base/group/RepositoryGroupHandlerTest.java similarity index 51% rename from archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/base/group/BasicManagedRepositoryValidatorTest.java rename to archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/base/group/RepositoryGroupHandlerTest.java index 5b950f923..26b6fbf09 100644 --- a/archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/base/group/BasicManagedRepositoryValidatorTest.java +++ b/archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/base/group/RepositoryGroupHandlerTest.java @@ -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 */ -class BasicManagedRepositoryValidatorTest +class RepositoryGroupHandlerTest { @Test - void apply( ) + void init( ) + { + } + + @Test + void initializeFromConfig( ) + { + } + + @Test + void initialize( ) + { + } + + @Test + 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 applyForUpdate( ) + void validateRepositoryForUpdate( ) { } @Test - void getFlavour( ) + void has( ) { } @Test - void isFlavour( ) + void close( ) { } } \ No newline at end of file diff --git a/archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/base/managed/BasicManagedRepositoryValidatorTest.java b/archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/base/managed/BasicManagedRepositoryValidatorTest.java new file mode 100644 index 000000000..2fe4f671e --- /dev/null +++ b/archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/base/managed/BasicManagedRepositoryValidatorTest.java @@ -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 + */ +@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 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 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 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 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 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 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 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 ) ); + } +} \ No newline at end of file diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/RepositoryGroup.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/RepositoryGroup.java index 1f021d0f4..1ca68a0fb 100644 --- a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/RepositoryGroup.java +++ b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/RepositoryGroup.java @@ -55,6 +55,7 @@ public class RepositoryGroup implements Serializable { private static final long serialVersionUID = -7319687481737616081L; private String id; + private String name; private List 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 ); diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/DefaultRepositoryGroupService.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/DefaultRepositoryGroupService.java index 4927b2161..9ecd914ae 100644 --- a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/DefaultRepositoryGroupService.java +++ b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/DefaultRepositoryGroupService.java @@ -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 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>> 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>> validationResult = repositoryRegistry.putRepositoryGroupAndValidate( configuration ); - if ( validationResult.isValid( ) ) - { - httpServletResponse.setStatus( 201 ); - return RepositoryGroup.of( validationResult.getRepository() ); - } else { - throw ValidationException.of( validationResult.getResult() ); - } + CheckedResult>> 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 ); } } diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/test/java/org/apache/archiva/rest/services/v2/NativeRepositoryGroupServiceTest.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/test/java/org/apache/archiva/rest/services/v2/NativeRepositoryGroupServiceTest.java index 3a5601f78..033a4a060 100644 --- a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/test/java/org/apache/archiva/rest/services/v2/NativeRepositoryGroupServiceTest.java +++ b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/test/java/org/apache/archiva/rest/services/v2/NativeRepositoryGroupServiceTest.java @@ -92,11 +92,11 @@ public class NativeRepositoryGroupServiceTest extends AbstractNativeRestServices { Map 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 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 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 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 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 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 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 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" ); } } -- 2.39.5