aboutsummaryrefslogtreecommitdiffstats
path: root/archiva-modules
diff options
context:
space:
mode:
authorMartin Stockhammer <martin_s@apache.org>2021-06-27 11:35:23 +0200
committerMartin Stockhammer <martin_s@apache.org>2021-06-27 11:35:23 +0200
commite8a70027d8342f78272b471aa0ac963c0a6f89be (patch)
tree26ff0e859616e117d65103ebbea11ddf50b43c87 /archiva-modules
parenta1b92c562fae957e601875e50f87a3ff93fecfd6 (diff)
downloadarchiva-e8a70027d8342f78272b471aa0ac963c0a6f89be.tar.gz
archiva-e8a70027d8342f78272b471aa0ac963c0a6f89be.zip
Changing repository group handling
Diffstat (limited to 'archiva-modules')
-rw-r--r--archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/RepositoryGroupConfiguration.java26
-rw-r--r--archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/io/registry/ConfigurationRegistryReader.java2
-rw-r--r--archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/io/registry/ConfigurationRegistryWriter.java3
-rw-r--r--archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/CheckedResult.java31
-rw-r--r--archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryHandler.java178
-rw-r--r--archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryRegistry.java287
-rw-r--r--archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryType.java2
-rw-r--r--archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/validation/AbstractRepositoryValidator.java50
-rw-r--r--archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/validation/RepositoryChecker.java36
-rw-r--r--archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/validation/RepositoryValidator.java85
-rw-r--r--archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/validation/ValidationError.java186
-rw-r--r--archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/validation/ValidationResponse.java110
-rw-r--r--archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/ArchivaRepositoryRegistry.java157
-rw-r--r--archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/ConfigurationHandler.java7
-rw-r--r--archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/RepositoryGroupHandler.java538
-rw-r--r--archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/validation/CommonGroupValidator.java144
-rw-r--r--archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/base/ArchivaRepositoryRegistryTest.java64
-rw-r--r--archiva-modules/archiva-maven/archiva-maven-repository/src/main/java/org/apache/archiva/repository/maven/MavenRepositoryProvider.java52
-rw-r--r--archiva-modules/archiva-maven/archiva-maven-repository/src/test/java/org/apache/archiva/repository/maven/mock/RepositoryRegistryMock.java6
-rw-r--r--archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/RepositoryGroup.java19
-rw-r--r--archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/ValidationError.java139
-rw-r--r--archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/ArchivaRestError.java29
-rw-r--r--archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/ErrorKeys.java4
-rw-r--r--archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/RepositoryGroupService.java22
-rw-r--r--archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/ValidationException.java85
-rw-r--r--archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/DefaultRepositoryGroupService.java272
26 files changed, 2095 insertions, 439 deletions
diff --git a/archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/RepositoryGroupConfiguration.java b/archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/RepositoryGroupConfiguration.java
index cf518951c..d0dc381e4 100644
--- a/archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/RepositoryGroupConfiguration.java
+++ b/archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/RepositoryGroupConfiguration.java
@@ -78,11 +78,37 @@ public class RepositoryGroupConfiguration
*/
private List<String> repositories;
+ /**
+ * The path for local data
+ */
+ private String location;
+
//-----------/
//- Methods -/
//-----------/
+
+ /**
+ * Return the local path for group data. If the merged index property is set to a non absolute path,
+ * it is relative to this location.
+ *
+ * @return the path for group data storage
+ */
+ public String getLocation( )
+ {
+ return location;
+ }
+
+ /**
+ * Set the local path for group data
+ * @param location
+ */
+ public void setLocation( String location )
+ {
+ this.location = location;
+ }
+
/**
* Method addRepository.
*
diff --git a/archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/io/registry/ConfigurationRegistryReader.java b/archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/io/registry/ConfigurationRegistryReader.java
index f3f0f2ea7..27146f5e6 100644
--- a/archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/io/registry/ConfigurationRegistryReader.java
+++ b/archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/io/registry/ConfigurationRegistryReader.java
@@ -753,6 +753,8 @@ public class ConfigurationRegistryReader {
value.setMergedIndexTtl(mergedIndexTtl);
//String cronExpression = registry.getString( prefix + "cronExpression", value.getCronExpression() );
+ value.setLocation( registry.getString( prefix + "location" ) );
+
List<String> cronExpressionList = registry.getList(prefix + "cronExpression");
String cronExpression = value.getCronExpression();
if (cronExpressionList != null && !cronExpressionList.isEmpty()) {
diff --git a/archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/io/registry/ConfigurationRegistryWriter.java b/archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/io/registry/ConfigurationRegistryWriter.java
index 2cbd387b6..83202f531 100644
--- a/archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/io/registry/ConfigurationRegistryWriter.java
+++ b/archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/io/registry/ConfigurationRegistryWriter.java
@@ -425,6 +425,9 @@ public class ConfigurationRegistryWriter {
if (value.getType() != null) {
registry.setString(prefix + "type", value.getType());
}
+ if (value.getLocation()!=null) {
+ registry.setString( prefix+"location", value.getType( ) );
+ }
if (value.getMergedIndexPath() != null && !value.getMergedIndexPath().equals(".indexer")
) {
String mergedIndexPath = "mergedIndexPath";
diff --git a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/CheckedResult.java b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/CheckedResult.java
new file mode 100644
index 000000000..41961a5e7
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/CheckedResult.java
@@ -0,0 +1,31 @@
+package org.apache.archiva.repository;
+/*
+ * 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.
+ */
+
+/**
+ * @author Martin Stockhammer <martin_s@apache.org>
+ */
+public interface CheckedResult<R extends Repository, D>
+{
+ R getRepository();
+
+ boolean isValid();
+
+ D getResult();
+
+}
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
new file mode 100644
index 000000000..49fc4de12
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryHandler.java
@@ -0,0 +1,178 @@
+package org.apache.archiva.repository;
+/*
+ * 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.configuration.Configuration;
+import org.apache.archiva.repository.validation.RepositoryChecker;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ *
+ * This is the generic interface that handles different repository flavours.
+ *
+ * @author Martin Stockhammer <martin_s@apache.org>
+ */
+public interface RepositoryHandler<R extends Repository, C>
+{
+
+ /**
+ * Creates 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();
+
+ /**
+ * Creates a new instance without registering and without updating the archiva configuration
+ *
+ * @param type the repository type
+ * @param id the repository identifier
+ * @return the repository instance
+ * @throws RepositoryException if the creation failed
+ */
+ R newInstance(RepositoryType type, String id) throws RepositoryException;
+
+ /**
+ * Creates a new instance and updates the given configuration object.
+ *
+ * @param repositoryConfiguration the configuration instance
+ * @return a newly created instance
+ * @throws RepositoryException if the creation failed
+ */
+ R newInstance( C repositoryConfiguration ) throws RepositoryException;
+
+ /**
+ * Adds the given repository to the registry or replaces a already existing repository in the registry.
+ * If an error occurred during the update, it will revert to the old repository status.
+ *
+ * @param repository the repository
+ * @return the created or updated repository instance
+ * @throws RepositoryException if the update or creation failed
+ */
+ R put( R repository ) throws RepositoryException;
+
+ /**
+ * Adds the repository to the registry, based on the given configuration.
+ * If there is a repository registered with the given id, it is updated.
+ * The archiva configuration is updated. The status is not defined, if an error occurs during update. The
+ * The repository instance is registered and initialized if no error occurs
+ *
+ * @param repositoryConfiguration the repository configuration
+ * @return the updated or created repository instance
+ * @throws RepositoryException if the update or creation failed
+ */
+ R put( C repositoryConfiguration ) throws RepositoryException;
+
+ /**
+ * Adds a repository from the given repository configuration. The changes are stored in
+ * the configuration object. The archiva registry is not updated.
+ * The returned repository instance is a clone of the registered repository instance. It is not registered
+ * and not initialized. References are not updated.
+ *
+ * @param repositoryConfiguration the repository configuration
+ * @param configuration the configuration instance
+ * @return the repository instance that was created or updated
+ * @throws RepositoryException if the update or creation failed
+ */
+ R put( C repositoryConfiguration, Configuration configuration ) throws RepositoryException;
+
+ /**
+ * Adds or updates a repository from the given configuration data. The resulting repository is
+ * checked by the repository checker and the result is returned.
+ * 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
+ * @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;
+
+ /**
+ * Removes the given repository from the registry and updates references and saves the new configuration.
+ *
+ * @param id The repository identifier
+ * @throws RepositoryException if the repository could not be removed
+ */
+ void remove( final String id ) throws RepositoryException;
+
+ /**
+ * 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 configuration the configuration to update
+ * @throws RepositoryException if the repository could not be removed
+ */
+ void remove( String id, Configuration configuration ) throws RepositoryException;
+
+ /**
+ * Returns the repository with the given identifier or <code>null</code>, if it is not registered.
+ *
+ * @param id the repository id
+ * @return if the retrieval failed
+ */
+ R get( String id );
+
+ /**
+ * Clones a given repository without registering.
+ *
+ * @param repo the repository that should be cloned
+ * @return a newly created instance with the same repository data
+ */
+ R clone(R repo) throws RepositoryException;
+
+ /**
+ * Updates the references and stores updates in the given <code>configuration</code> instance.
+ * The references that are updated depend on the concrete repository subclass <code>R</code>.
+ * 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 repositoryConfiguration the repository configuration
+ */
+ void updateReferences( R repo, C repositoryConfiguration ) throws RepositoryException;
+
+ /**
+ * Returns all registered repositories.
+ *
+ * @return the list of repositories
+ */
+ Collection<R> getAll();
+
+ /**
+ * 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);
+
+ /**
+ * Initializes
+ */
+ void init();
+
+ /**
+ * Closes the handler
+ */
+ void close();
+
+}
diff --git a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryRegistry.java b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryRegistry.java
index bb6bbc98b..2a5210666 100644
--- a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryRegistry.java
+++ b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryRegistry.java
@@ -29,23 +29,31 @@ import org.apache.archiva.indexer.ArchivaIndexManager;
import org.apache.archiva.indexer.IndexUpdateFailedException;
import org.apache.archiva.repository.metadata.MetadataReader;
import org.apache.archiva.repository.storage.StorageAsset;
+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;
/**
* Registry for repositories. This is the central entry point for repositories. It provides methods for
* retrieving, adding and removing repositories.
* <p>
- * The modification methods addXX and removeXX persist the changes immediately to the configuration. If the
+ * The modification methods putXX and removeXX without configuration object persist the changes immediately to the archiva configuration. If the
* configuration save fails the changes are rolled back.
+ * </p>
* <p>
+ * The modification methods with configuration object do only update the given configuration. The configuration is not saved.
+ * </p>
* @author Martin Stockhammer <martin_s@apache.org>
*/
+@SuppressWarnings( "UnusedReturnValue" )
public interface RepositoryRegistry extends EventSource
{
/**
* Set the configuration for the registry
- * @param archivaConfiguration
+ * @param archivaConfiguration the archiva configuration instance
*/
void setArchivaConfiguration( ArchivaConfiguration archivaConfiguration );
@@ -57,7 +65,7 @@ public interface RepositoryRegistry extends EventSource
ArchivaIndexManager getIndexManager( RepositoryType type );
/**
- * Returns the metadatareader for the given repository type
+ * Returns the metadata reader for the given repository type
* @param type the repository type
* @return the metadata reader instance
*/
@@ -75,63 +83,305 @@ public interface RepositoryRegistry extends EventSource
*/
Collection<ManagedRepository> getManagedRepositories( );
+ /**
+ * Returns a collection of all registered remote repositories
+ * @return the collection of remote repositories
+ */
Collection<RemoteRepository> getRemoteRepositories( );
+ /**
+ * Returns a collection of all registered repository groups.
+ *
+ * @return the collection of repository groups
+ */
Collection<RepositoryGroup> getRepositoryGroups( );
+ /**
+ * Returns the repository (managed, remote, group) with the given id
+ * @param repoId the id of the repository
+ * @return the repository or <code>null</code> if no repository with this ID is registered.
+ */
Repository getRepository( String repoId );
+ /**
+ * Returns the managed repository with the given id
+ * @param repoId the id of the repository
+ * @return the managed repository instance or <code>null</code>, if no managed repository with this ID is registered.
+ */
ManagedRepository getManagedRepository( String repoId );
+ /**
+ * Returns the remote repository with the given id
+ * @param repoId the id of the repository
+ * @return the remote repository instance or <code>null</code>, if no remote repository with this ID is registered.
+ */
RemoteRepository getRemoteRepository( String repoId );
+ /**
+ * Returns the repository group with the given id
+ * @param groupId the id of the repository group
+ * @return the repository group instance or <code>null</code>, if no repository group with this ID is registered.
+ */
RepositoryGroup getRepositoryGroup( String groupId );
+ /**
+ * Returns <code>true</code>, if a repository with the given ID is registered, otherwise <code>false</code>
+ * @param repoId the ID of the repository
+ * @return <code>true</code>, if a repository with the given ID is registered, otherwise <code>false</code>
+ */
+ boolean hasRepository(String repoId);
+
+ /**
+ * Returns <code>true</code>, if a managed repository with the given ID is registered, otherwise <code>false</code>
+ * @param repoId the id of the managed repository
+ * @return <code>true</code>, if a managed repository with the given ID is registered, otherwise <code>false</code>
+ */
+ boolean hasManagedRepository(String repoId);
+
+ /**
+ * Returns <code>true</code>, if a remote repository with the given ID is registered, otherwise <code>false</code>
+ * @param repoId the id of the remote repository
+ * @return <code>true</code>, if a remote repository with the given ID is registered, otherwise <code>false</code>
+ */
+ boolean hasRemoteRepository(String repoId);
+
+ /**
+ * Returns <code>true</code>, if a repository group with the given ID is registered, otherwise <code>false</code>
+ * @param groupId the id of the repository group
+ * @return <code>true</code>, if a repository group with the given ID is registered, otherwise <code>false</code>
+ */
+ boolean hasRepositoryGroup( String groupId );
+
+ /**
+ * Adds or updates the given managed repository. If a managed repository with the given id exists already, it is updated
+ * from the data of the given instance. Otherwise a new repository is created and updated by the data of the given instance.
+ *
+ * The archiva configuration is updated and saved after updating the registered repository instance.
+ *
+ * @param managedRepository the managed repository
+ * @return the repository instance, that was created or updated
+ * @throws RepositoryException if an error occurred while creating or updating the instance
+ */
ManagedRepository putRepository( ManagedRepository managedRepository ) throws RepositoryException;
+ /**
+ * Adds or updates the given managed repository. If a managed repository with the given id exists already, it is updated
+ * from the data of the given configuration. Otherwise a new repository is created and updated by the data of the given configuration.
+ *
+ * The archiva configuration is updated and saved after updating the registered repository instance.
+ *
+ * @param managedRepositoryConfiguration the managed repository configuration
+ * @return the repository instance, that was created or updated
+ * @throws RepositoryException if an error occurred while creating or updating the instance
+ */
ManagedRepository putRepository( ManagedRepositoryConfiguration managedRepositoryConfiguration ) throws RepositoryException;
+ /**
+ * Adds or updates the given managed repository. If a managed repository with the given id exists already, it is updated
+ * from the data of the given configuration. Otherwise a new repository is created and updated by the data of the given configuration.
+ *
+ * This method can be used, if the archiva configuration should not be saved. It will only update the given configuration object.
+ *
+ * @param managedRepositoryConfiguration the managed repository configuration
+ * @param configuration the archiva configuration that is updated
+ * @return the repository instance, that was created or updated
+ * @throws RepositoryException if an error occurred while creating or updating the instance
+ */
ManagedRepository putRepository( ManagedRepositoryConfiguration managedRepositoryConfiguration, Configuration configuration ) throws RepositoryException;
+ /**
+ * Adds or updates the given repository group. If a repository group with the given id exists already, it is updated
+ * from the data of the given instance. Otherwise a new repository is created and updated by the data of the given instance.
+ *
+ * The archiva configuration is updated and saved after updating the registered repository instance.
+ *
+ * @param repositoryGroup the repository group
+ * @return the repository instance, that was created or updated
+ * @throws RepositoryException if an error occurred while creating or updating the instance
+ */
RepositoryGroup putRepositoryGroup( RepositoryGroup repositoryGroup ) throws RepositoryException;
+ /**
+ * Adds or updates the given repository group. If a repository group with the given id exists already, it is updated
+ * from the data of the given configuration. Otherwise a new repository is created and updated by the data of the given configuration.
+ *
+ * The archiva configuration is updated and saved after updating the registered repository instance.
+ *
+ * @param repositoryGroupConfiguration the repository group configuration
+ * @return the repository instance, that was created or updated
+ * @throws RepositoryException if an error occurred while creating or updating the instance
+ */
RepositoryGroup putRepositoryGroup( RepositoryGroupConfiguration repositoryGroupConfiguration ) throws RepositoryException;
+
+ /**
+ * This method creates or updates a repository by the given configuration. It uses the <code>validator</code> to check the
+ * result. If the validation is not successful, the repository will not be saved.
+ *
+ * @param configuration the repository configuration
+ * @return the result
+ */
+ CheckedResult<RepositoryGroup, Map<String, List<ValidationError>>> putRepositoryGroupAndValidate( RepositoryGroupConfiguration configuration) throws RepositoryException;
+
+ /**
+ * Adds or updates the given repository group. If a repository group with the given id exists already, it is updated
+ * from the data of the given configuration. Otherwise a new repository is created and updated by the data of the given configuration.
+ *
+ * This method can be used, if the archiva configuration should not be saved. It will only update the given configuration object.
+ *
+ * @param repositoryGroupConfiguration the repository group configuration
+ * @param configuration the archiva configuration that is updated
+ * @return the repository instance, that was created or updated
+ * @throws RepositoryException if an error occurred while creating or updating the instance
+ */
RepositoryGroup putRepositoryGroup( RepositoryGroupConfiguration repositoryGroupConfiguration, Configuration configuration ) throws RepositoryException;
+ /**
+ * Adds or updates the given remote repository. If a remote repository with the given id exists already, it is updated
+ * from the data of the given instance. Otherwise a new repository is created and updated by the data of the given instance.
+ *
+ * This method can be used, if the archiva configuration should not be saved. It will only update the given configuration object.
+ *
+ * @param remoteRepository the remote repository
+ * @param configuration the configuration that is updated
+ * @return the repository instance, that was created or updated
+ * @throws RepositoryException if an error occurred while creating or updating the instance
+ */
RemoteRepository putRepository( RemoteRepository remoteRepository, Configuration configuration ) throws RepositoryException;
+ /**
+ * Adds or updates the given remote repository. If a remote repository with the given id exists already, it is updated
+ * from the data of the given instance. Otherwise a new repository is created and updated by the data of the given instance.
+ *
+ * The archiva configuration is updated and saved after updating the registered repository instance.
+ *
+ * @param remoteRepository the remote repository
+ * @return the repository instance, that was created or updated
+ * @throws RepositoryException if an error occurred while creating or updating the instance
+ */
RemoteRepository putRepository( RemoteRepository remoteRepository ) throws RepositoryException;
+ /**
+ * Adds or updates the given remote repository. If a remote repository with the given id exists already, it is updated
+ * from the data of the given configuration. Otherwise a new repository is created and updated by the data of the given configuration.
+ *
+ * The archiva configuration is updated and saved after updating the registered repository instance.
+ *
+ * @param remoteRepositoryConfiguration the remote repository configuration
+ * @return the repository instance, that was created or updated
+ * @throws RepositoryException if an error occurred while creating or updating the instance
+ */
RemoteRepository putRepository( RemoteRepositoryConfiguration remoteRepositoryConfiguration ) throws RepositoryException;
+ /**
+ * Adds or updates the given remote repository. If a remote repository with the given id exists already, it is updated
+ * from the data of the given configuration. Otherwise a new repository is created and updated by the data of the given configuration.
+ *
+ * This method can be used, if the archiva configuration should not be saved. It will only update the given configuration object.
+ *
+ * @param remoteRepositoryConfiguration the remote repository configuration
+ * @param configuration the archiva configuration where the updated data is stored into
+ * @return the repository instance, that was created or updated
+ * @throws RepositoryException if an error occurred while creating or updating the instance
+ */
RemoteRepository putRepository( RemoteRepositoryConfiguration remoteRepositoryConfiguration, Configuration configuration ) throws RepositoryException;
+ /**
+ * Removes the repository or repository group with the given id, if it exists. Otherwise, it will do nothing.
+ *
+ * The configuration is updated and saved, if the deletion was successful
+ *
+ * @param repoId the id of the repository or repository group to delete
+ * @throws RepositoryException if the repository deletion failed
+ */
void removeRepository( String repoId ) throws RepositoryException;
+ /**
+ * Removes the given repository.
+ *
+ * The configuration is updated and saved, if the deletion was successful
+ *
+ * @param repo the repository instance that should be deleted
+ * @throws RepositoryException if the repository deletion failed
+ */
void removeRepository( Repository repo ) throws RepositoryException;
+ /**
+ * Removes the given managed repository.
+ *
+ * The configuration is updated and saved, if the deletion was successful
+ *
+ * @param managedRepository the managed repository to remove
+ * @throws RepositoryException if the repository deletion failed
+ */
void removeRepository( ManagedRepository managedRepository ) throws RepositoryException;
+ /**
+ * Removes the given managed repository. The given configuration instance is updated, but the
+ * archiva configuration is not saved.
+ *
+ * @param managedRepository the managed repository to remove
+ * @param configuration the configuration instance to update
+ * @throws RepositoryException if the repository deletion failed
+ */
void removeRepository( ManagedRepository managedRepository, Configuration configuration ) throws RepositoryException;
+ /**
+ * Removes the given repository group.
+ *
+ * The configuration is updated and saved, if the deletion was successful
+ *
+ * @param repositoryGroup the repository group to remove
+ * @throws RepositoryException if the repository deletion failed
+ */
void removeRepositoryGroup( RepositoryGroup repositoryGroup ) throws RepositoryException;
+ /**
+ * Removes the given repository group. The given configuration instance is updated, but the
+ * archiva configuration is not saved.
+ *
+ * @param repositoryGroup the repository group to remove
+ * @param configuration the configuration instance to update
+ * @throws RepositoryException if the repository deletion failed
+ */
void removeRepositoryGroup( RepositoryGroup repositoryGroup, Configuration configuration ) throws RepositoryException;
+ /**
+ * Removes the given remote repository.
+ *
+ * The configuration is updated and saved, if the deletion was successful
+ *
+ * @param remoteRepository the remote repository to remove
+ * @throws RepositoryException if the repository deletion failed
+ */
void removeRepository( RemoteRepository remoteRepository ) throws RepositoryException;
+ /**
+ * Removes the given remote repository. The given configuration instance is updated, but the
+ * archiva configuration is not saved.
+ *
+ * @param remoteRepository the remote repository to remove
+ * @param configuration the configuration instance to update
+ * @throws RepositoryException if the repository deletion failed
+ */
void removeRepository( RemoteRepository remoteRepository, Configuration configuration ) throws RepositoryException;
+ /**
+ * Reloads all repositories and groups from the configuration
+ */
void reload( );
void resetIndexingContext( Repository repository ) throws IndexUpdateFailedException;
- ManagedRepository clone( ManagedRepository repo, String newId ) throws RepositoryException;
-
- <T extends Repository> Repository clone( T repo, String newId ) throws RepositoryException;
-
- RemoteRepository clone( RemoteRepository repo, String newId ) throws RepositoryException;
+ /**
+ * Creates a new repository based on the given repository and with the given new id.
+ * @param repo the repository to copy from
+ * @param newId the new repository id
+ * @param <T> the type of the repository (Manage, Remote or RepositoryGroup)
+ * @return the newly created repository
+ * @throws RepositoryException if the repository could not be created
+ */
+ <T extends Repository> T clone( T repo, String newId ) throws RepositoryException;
/**
* Return the repository that stores the given asset.
@@ -139,4 +389,25 @@ public interface RepositoryRegistry extends EventSource
* @return the repository or <code>null</code> if no matching repository is found
*/
Repository getRepositoryOfAsset( StorageAsset asset );
+
+ /**
+ * Validates the set attributes of the given repository instance and returns the validation result.
+ * The repository registry uses all available validators and applies their validateRepository method to the given
+ * repository. Validation results will be merged per field.
+ *
+ * @param repository the repository to validate against
+ * @return the result of the validation.
+ */
+ <R extends Repository> ValidationResponse<R> validateRepository( R repository);
+
+ /**
+ * Validates the set attributes of the given repository instance for a repository update and returns the validation result.
+ * The repository registry uses all available validators and applies their validateRepositoryForUpdate method to the given
+ * repository. Validation results will be merged per field.
+ *
+ * @param repository the repository to validate against
+ * @return the result of the validation.
+ */
+ <R extends Repository> ValidationResponse<R> validateRepositoryForUpdate( R repository);
+
}
diff --git a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryType.java b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryType.java
index f60c65787..b5e8385c1 100644
--- a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryType.java
+++ b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryType.java
@@ -25,5 +25,5 @@ package org.apache.archiva.repository;
*/
public enum RepositoryType {
- MAVEN, NPM
+ ALL, MAVEN, NPM
}
diff --git a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/validation/AbstractRepositoryValidator.java b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/validation/AbstractRepositoryValidator.java
new file mode 100644
index 000000000..319fc50db
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/validation/AbstractRepositoryValidator.java
@@ -0,0 +1,50 @@
+package org.apache.archiva.repository.validation;
+/*
+ * 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.CheckedResult;
+import org.apache.archiva.repository.Repository;
+import org.apache.archiva.repository.RepositoryRegistry;
+
+/**
+ * @author Martin Stockhammer <martin_s@apache.org>
+ */
+public abstract class AbstractRepositoryValidator<R extends Repository> implements RepositoryValidator<R>
+{
+ protected RepositoryRegistry repositoryRegistry;
+
+ @Override
+ public void setRepositoryRegistry( RepositoryRegistry repositoryRegistry )
+ {
+ this.repositoryRegistry = repositoryRegistry;
+ }
+
+ protected abstract ValidationResponse<R> apply( R repo, boolean update );
+
+ @Override
+ public ValidationResponse<R> apply( R r )
+ {
+ return apply( r, false );
+ }
+
+ @Override
+ public ValidationResponse<R> applyForUpdate( R repo )
+ {
+ return apply( repo, true );
+ }
+}
diff --git a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/validation/RepositoryChecker.java b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/validation/RepositoryChecker.java
new file mode 100644
index 000000000..f208d10fe
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/validation/RepositoryChecker.java
@@ -0,0 +1,36 @@
+package org.apache.archiva.repository.validation;
+/*
+ * 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.CheckedResult;
+import org.apache.archiva.repository.Repository;
+
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+/**
+ * @author Martin Stockhammer <martin_s@apache.org>
+ */
+public interface RepositoryChecker<R extends Repository, D> extends Function<R, CheckedResult<R,D>>
+{
+
+ @Override
+ CheckedResult<R,D> apply( R r );
+
+ CheckedResult<R,D> applyForUpdate( R repo );
+}
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
new file mode 100644
index 000000000..041fe8a48
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/validation/RepositoryValidator.java
@@ -0,0 +1,85 @@
+package org.apache.archiva.repository.validation;
+/*
+ * 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.RepositoryRegistry;
+import org.apache.archiva.repository.RepositoryType;
+
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+
+/**
+ * A repository validator validates given repository data against certain rules.
+ *
+ * @author Martin Stockhammer <martin_s@apache.org>
+ */
+public interface RepositoryValidator<R extends Repository> extends RepositoryChecker<R, Map<String, List<ValidationError>>>, Comparable<RepositoryValidator<R>>
+{
+
+ int DEFAULT_PRIORITY=1000;
+
+ /**
+ * Returns the repository type for which this validator can be used. If the validator is applicable
+ * to all types, it should return {@link RepositoryType#ALL}
+ *
+ * @return the repository type for which this validator is applicable
+ */
+ default RepositoryType getType() {
+ return RepositoryType.ALL;
+ }
+
+ /**
+ * Returns the priority of this validator. Smaller values mean higher priority.
+ * All common validators have priority {@link #DEFAULT_PRIORITY}
+ *
+ * Validators are called in numerical order of their priority.
+ *
+ * @return
+ */
+ default int getPriority() {
+ return DEFAULT_PRIORITY;
+ }
+
+
+ /**
+ * Orders by priority
+ *
+ * @see Comparable#compareTo(Object)
+ */
+ @Override
+ default int compareTo( RepositoryValidator o ) {
+ if (o==null) {
+ return 1;
+ } else
+ {
+ return this.getPriority( ) - o.getPriority( );
+ }
+ }
+
+ /**
+ * Sets the repository registry to the given instance.
+ * @param repositoryRegistry the repository registry
+ */
+ void setRepositoryRegistry( RepositoryRegistry repositoryRegistry );
+
+ Class<R> getFlavour();
+
+ boolean isFlavour(Class<?> clazz);
+}
diff --git a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/validation/ValidationError.java b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/validation/ValidationError.java
new file mode 100644
index 000000000..22594fbfa
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/validation/ValidationError.java
@@ -0,0 +1,186 @@
+package org.apache.archiva.repository.validation;
+/*
+ * 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.commons.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Represents a single validation error. A error is defined by a global unique key and has a optional number
+ * of arguments.
+ * <p>
+ * The unique key should represent a category, the attribute and a generic type, separated by '.'
+ * E.g. repository_group.id.empty
+ * </p>
+ * <p>
+ * Categories normally separate errors for different domain types, like managed repository, repository group, maven repository.
+ * <p>
+ * Types define a certain type of error that can be handled similar independent of the attribute or category
+ *
+ * @author Martin Stockhammer <martin_s@apache.org>
+ */
+public class ValidationError
+{
+ public static final String UNSPECIFIED = "unspecified";
+
+ final String errorKey;
+ final String attribute;
+ final String category;
+ final String type;
+ final List<Object> arguments = new ArrayList<>();
+
+
+ public static ValidationError ofKey( final String errorKey, Object... arguments )
+ {
+ return new ValidationError( errorKey, getCategoryFromKey( errorKey ), getTypeFromKey( errorKey ), getAttributeFromKey( errorKey ),
+ Arrays.asList( arguments ) );
+ }
+
+ public static ValidationError ofKey( String errorKey, List<Object> arguments )
+ {
+ return new ValidationError( errorKey, getCategoryFromKey( errorKey ), getTypeFromKey( errorKey ), getAttributeFromKey( errorKey ),
+ arguments );
+ }
+
+ public ValidationError( String errorKey, String category, String type, String attribute, List<Object> arguments )
+ {
+ if ( StringUtils.isEmpty( errorKey ) )
+ {
+ throw new IllegalArgumentException( "The key of a validation error cannot be empty" );
+ }
+ this.errorKey = errorKey;
+ if ( arguments != null )
+ {
+ this.arguments.addAll( arguments );
+ }
+ this.type = type;
+ this.category = category;
+ this.attribute = attribute;
+ }
+
+ private static String getTypeFromKey( final String errorKey )
+ {
+ return errorKey.contains( "." ) ?
+ StringUtils.substringAfterLast( errorKey, "." ) :
+ UNSPECIFIED;
+ }
+
+ private static String getCategoryFromKey( final String errorKey )
+ {
+ return errorKey.contains( "." ) ?
+ StringUtils.substringBefore( errorKey, "." ) :
+ UNSPECIFIED;
+ }
+
+ private static String getAttributeFromKey( final String errorKey )
+ {
+ return StringUtils.countMatches( errorKey, "." ) >= 2 ?
+ StringUtils.substringBetween( errorKey, "." ) : UNSPECIFIED;
+ }
+
+ /**
+ * Returns the unique key of this validation error. It is best practice for keys to contain the
+ * validation source, the attribute and a unique error definition.
+ * E.g. repository_group.id.empty
+ *
+ * @return
+ */
+ public String getErrorKey( )
+ {
+ return errorKey;
+ }
+
+ /**
+ * Returns the list of arguments stored for this error
+ * @return the list of arguments
+ */
+ public List<Object> getArguments( )
+ {
+ return arguments;
+ }
+
+ /**
+ * Adds the given argument to the list
+ * @param argument the argument to add
+ */
+ public void addArgument( Object argument )
+ {
+ this.arguments.add( argument );
+ }
+
+ /**
+ * Returns the generic error type, this error represents.
+ *
+ * @return the error type or {@link #UNSPECIFIED} if not explicitly set.
+ */
+ public String getType( )
+ {
+ return type;
+ }
+
+ /**
+ * Returns the category of the error.
+ *
+ * @return the category or {@link #UNSPECIFIED} if not explicitly set
+ */
+ public String getCategory( )
+ {
+ return category;
+ }
+
+ /**
+ * Returns the attribute name
+ * @return the attribute name or {@link #UNSPECIFIED} if not explicitly set
+ */
+ public String getAttribute( )
+ {
+ return attribute;
+ }
+
+ @Override
+ public String toString( )
+ {
+ final StringBuilder sb = new StringBuilder( "ValidationError{" );
+ sb.append( "errorKey='" ).append( errorKey ).append( '\'' );
+ sb.append( '}' );
+ return sb.toString( );
+ }
+
+ @Override
+ public boolean equals( Object o )
+ {
+ if ( this == o ) return true;
+ if ( o == null || getClass( ) != o.getClass( ) ) return false;
+
+ ValidationError that = (ValidationError) o;
+
+ if ( !errorKey.equals( that.errorKey ) ) return false;
+ return arguments.equals( that.arguments );
+ }
+
+ @Override
+ public int hashCode( )
+ {
+ int result = errorKey.hashCode( );
+ result = 31 * result + arguments.hashCode( );
+ return result;
+ }
+}
diff --git a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/validation/ValidationResponse.java b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/validation/ValidationResponse.java
new file mode 100644
index 000000000..377a3ccb2
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/validation/ValidationResponse.java
@@ -0,0 +1,110 @@
+package org.apache.archiva.repository.validation;
+/*
+ * 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.CheckedResult;
+import org.apache.archiva.repository.Repository;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+
+/**
+ * A validation response gives information about the validation status for certain attributes.
+ *
+ *
+ * @author Martin Stockhammer <martin_s@apache.org>
+ */
+public class ValidationResponse<R extends Repository> implements CheckedResult<R, Map<String, List<ValidationError>>>
+{
+ final boolean valid;
+ final R repository;
+ final Map<String, List<ValidationError>> validationErrors = new HashMap<>( );
+
+
+ public ValidationResponse( R repo, Map<String, List<ValidationError>> errors)
+ {
+ if( errors==null || errors.size()==0 ) {
+ this.valid = true;
+ } else {
+ this.valid = false;
+ validationErrors.putAll( errors );
+ }
+ this.repository = repo;
+ }
+
+ public static <S extends Repository> ValidationResponse<S> getValid( S repository )
+ {
+ return new ValidationResponse<>( repository, null );
+ }
+
+ @Override
+ public R getRepository( )
+ {
+ return repository;
+ }
+
+ /**
+ * Returns true, if the validation was successful and there are not validation errors.
+ * @return <code>true</code>, if the validation was successful, otherwise <code>false</code>
+ */
+ @Override
+ public boolean isValid( )
+ {
+ return valid;
+ }
+
+ @Override
+ public Map<String, List<ValidationError>> getResult( )
+ {
+ return validationErrors;
+ }
+
+
+ /**
+ * Add the given validation error to the list for the given attribute.
+ *
+ * @param attribute the name of the attribute
+ * @param error the error that is added to the list
+ */
+ public void addValidationError(String attribute, ValidationError error) {
+ if (!validationErrors.containsKey( attribute )) {
+ validationErrors.put( attribute, new ArrayList<>( ) );
+ }
+ validationErrors.get( attribute ).add( error );
+ }
+
+ /**
+ * Returns a list of validation errors that are stored for the given attribute. If there are no
+ * errors stored for this attribute, a empty list is returned.
+ *
+ * @param attribute the name of the attribute
+ * @return the list of validation errors
+ */
+ public List<ValidationError> getValidationErrors(String attribute) {
+ if (validationErrors.containsKey( attribute )) {
+ return validationErrors.get( attribute );
+ } else {
+ return Collections.emptyList( );
+ }
+ }
+
+}
diff --git a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/ArchivaRepositoryRegistry.java b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/ArchivaRepositoryRegistry.java
index 249436092..db1d626a2 100644
--- a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/ArchivaRepositoryRegistry.java
+++ b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/ArchivaRepositoryRegistry.java
@@ -38,6 +38,7 @@ import org.apache.archiva.indexer.ArchivaIndexingContext;
import org.apache.archiva.indexer.IndexCreationFailedException;
import org.apache.archiva.indexer.IndexManagerFactory;
import org.apache.archiva.indexer.IndexUpdateFailedException;
+import org.apache.archiva.repository.CheckedResult;
import org.apache.archiva.repository.EditableManagedRepository;
import org.apache.archiva.repository.EditableRemoteRepository;
import org.apache.archiva.repository.EditableRepository;
@@ -59,6 +60,11 @@ import org.apache.archiva.repository.features.IndexCreationFeature;
import org.apache.archiva.repository.features.StagingRepositoryFeature;
import org.apache.archiva.repository.metadata.MetadataReader;
import org.apache.archiva.repository.storage.StorageAsset;
+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.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -76,6 +82,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.stream.Collectors;
@@ -98,7 +105,6 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
{
private static final Logger log = LoggerFactory.getLogger( RepositoryRegistry.class );
- private final ConfigurationHandler configurationHandler;
/**
* We inject all repository providers
@@ -129,16 +135,52 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock( );
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;
+
private AtomicBoolean groups_initalized = new AtomicBoolean( false );
private AtomicBoolean managed_initialized = new AtomicBoolean( false );
private AtomicBoolean remote_initialized = new AtomicBoolean( false );
- public ArchivaRepositoryRegistry( ConfigurationHandler configurationHandler )
+ public ArchivaRepositoryRegistry( ConfigurationHandler configurationHandler, List<RepositoryValidator<? extends Repository>> validatorList )
{
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 )
+ {
+ TreeSet<RepositoryValidator<? extends Repository>> val = new TreeSet<>( );
+ for (RepositoryValidator<? extends Repository> validator : validators) {
+ val.add( validator );
+ }
+ return val;
}
@Override
@@ -513,7 +555,7 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
rwLock.readLock( ).lock( );
try
{
- return groupHandler.getRepositoryGroups( );
+ return groupHandler.getAll( );
}
finally
{
@@ -545,9 +587,9 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
log.debug( "Remote repo" );
return remoteRepositories.get( repoId );
}
- else if ( groupHandler.hasRepositoryGroup( repoId ) )
+ else if ( groupHandler.has( repoId ) )
{
- return groupHandler.getRepositoryGroup( repoId );
+ return groupHandler.get( repoId );
}
else
{
@@ -608,7 +650,7 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
rwLock.readLock( ).lock( );
try
{
- return groupHandler.getRepositoryGroup( groupId );
+ return groupHandler.get( groupId );
}
finally
{
@@ -616,6 +658,30 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
}
}
+ @Override
+ public boolean hasRepository( String repoId )
+ {
+ return this.managedRepositories.containsKey( repoId ) || this.remoteRepositories.containsKey( repoId ) || groupHandler.has( repoId );
+ }
+
+ @Override
+ public boolean hasManagedRepository( String repoId )
+ {
+ return this.managedRepositories.containsKey( repoId );
+ }
+
+ @Override
+ public boolean hasRemoteRepository( String repoId )
+ {
+ return this.remoteRepositories.containsKey( repoId );
+ }
+
+ @Override
+ public boolean hasRepositoryGroup( String groupId )
+ {
+ return groupHandler.has( groupId );
+ }
+
protected void saveConfiguration( Configuration configuration ) throws IndeterminateConfigurationException, RegistryException
{
configurationHandler.save( configuration, ConfigurationHandler.REGISTRY_EVENT_TAG );
@@ -805,7 +871,7 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
{
throw new RepositoryException( "Fatal error. RepositoryGroupHandler not registered!" );
}
- return this.groupHandler.putRepositoryGroup( repositoryGroup );
+ return this.groupHandler.put( repositoryGroup );
}
finally
{
@@ -827,7 +893,7 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
rwLock.writeLock( ).lock( );
try
{
- return groupHandler.putRepositoryGroup( repositoryGroupConfiguration );
+ return groupHandler.put( repositoryGroupConfiguration );
}
finally
{
@@ -836,6 +902,21 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
}
+ @Override
+ public CheckedResult<RepositoryGroup, Map<String, List<ValidationError>>> putRepositoryGroupAndValidate( RepositoryGroupConfiguration repositoryGroupConfiguration )
+ throws RepositoryException
+ {
+ rwLock.writeLock( ).lock( );
+ try
+ {
+ return groupHandler.putWithCheck( repositoryGroupConfiguration, this.groupChecker );
+ }
+ finally
+ {
+ rwLock.writeLock( ).unlock( );
+ }
+ }
+
/**
* Adds a new repository group or updates the repository group with the same id. The given configuration object is updated, but
* the configuration is not saved.
@@ -851,7 +932,7 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
rwLock.writeLock( ).lock( );
try
{
- return groupHandler.putRepositoryGroup( repositoryGroupConfiguration, configuration );
+ return groupHandler.put( repositoryGroupConfiguration, configuration );
}
finally
{
@@ -1234,12 +1315,12 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
return;
}
final String id = repositoryGroup.getId( );
- if ( groupHandler.hasRepositoryGroup( id ) )
+ if ( groupHandler.has( id ) )
{
rwLock.writeLock( ).lock( );
try
{
- groupHandler.removeRepositoryGroup( id );
+ groupHandler.remove( id );
}
finally
{
@@ -1256,12 +1337,12 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
return;
}
final String id = repositoryGroup.getId( );
- if ( groupHandler.hasRepositoryGroup( id ) )
+ if ( groupHandler.has( id ) )
{
rwLock.writeLock( ).lock( );
try
{
- groupHandler.removeRepositoryGroup( id, configuration );
+ groupHandler.remove( id, configuration );
}
finally
{
@@ -1395,7 +1476,6 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
* @param repo The origin repository
* @return The cloned repository.
*/
- @Override
public ManagedRepository clone( ManagedRepository repo, String newId ) throws RepositoryException
{
if ( managedRepositories.containsKey( newId ) || remoteRepositories.containsKey( newId ) )
@@ -1411,15 +1491,15 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
}
@Override
- public <T extends Repository> Repository clone( T repo, String newId ) throws RepositoryException
+ public <T extends Repository> T clone( T repo, String newId ) throws RepositoryException
{
if ( repo instanceof RemoteRepository )
{
- return this.clone( (RemoteRepository) repo, newId );
+ return (T) this.clone( (RemoteRepository) repo, newId );
}
else if ( repo instanceof ManagedRepository )
{
- return this.clone( (ManagedRepository) repo, newId );
+ return (T) this.clone( (ManagedRepository) repo, newId );
}
else
{
@@ -1434,7 +1514,6 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
* @param repo The origin repository
* @return The cloned repository.
*/
- @Override
public RemoteRepository clone( RemoteRepository repo, String newId ) throws RepositoryException
{
if ( managedRepositories.containsKey( newId ) || remoteRepositories.containsKey( newId ) )
@@ -1463,6 +1542,35 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
}
}
+ @Override
+ public <R extends Repository> ValidationResponse<R> validateRepository( R repository )
+ {
+ Map<String, List<ValidationError>> errorMap = this.validators.stream( )
+ .filter( ( validator ) -> validator.getType( ).equals( RepositoryType.ALL ) || repository.getType( ).equals( validator.getType( ) ) )
+ .filter( val -> val.isFlavour( repository.getClass() ))
+ .flatMap( validator -> ((RepositoryValidator<R>)validator).apply( repository ).getResult().entrySet( ).stream( ) )
+ .collect( Collectors.toMap(
+ entry -> entry.getKey( ),
+ entry -> entry.getValue( ),
+ ( list1, list2 ) -> ListUtils.union( list1, list2 )
+ ) );
+ return new ValidationResponse( repository, errorMap );
+ }
+
+ @Override
+ public <R extends Repository> ValidationResponse<R> validateRepositoryForUpdate( R repository )
+ {
+ Map<String, List<ValidationError>> errorMap = this.validators.stream( )
+ .filter( ( validator ) -> validator.getType( ).equals( RepositoryType.ALL ) || repository.getType( ).equals( validator.getType( ) ) )
+ .filter( val -> val.isFlavour( repository.getClass() ))
+ .flatMap( validator -> ((RepositoryValidator<R>)validator).applyForUpdate( repository ).getResult().entrySet( ).stream( ) )
+ .collect( Collectors.toMap(
+ entry -> entry.getKey( ),
+ entry -> entry.getValue( ),
+ ( list1, list2 ) -> ListUtils.union( list1, list2 )
+ ) );
+ return new ValidationResponse( repository, errorMap );
+ }
@Override
public void configurationEvent( ConfigurationEvent event )
@@ -1509,22 +1617,25 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
{
RepositoryIndexEvent idxEvent = event;
EditableRepository repo = (EditableRepository) idxEvent.getRepository( );
- if ( repo != null ) {
+ if ( repo != null )
+ {
ArchivaIndexManager idxmgr = getIndexManager( repo.getType( ) );
if ( repo.getIndexingContext( ) != null )
{
try
{
- ArchivaIndexingContext newCtx = idxmgr.move( repo.getIndexingContext( ), repo );
- repo.setIndexingContext( newCtx );
- idxmgr.updateLocalIndexPath( repo );
+ ArchivaIndexingContext newCtx = idxmgr.move( repo.getIndexingContext( ), repo );
+ repo.setIndexingContext( newCtx );
+ idxmgr.updateLocalIndexPath( repo );
}
catch ( IndexCreationFailedException e )
{
log.error( "Could not move index to new directory: '{}'", e.getMessage( ), e );
}
- } else {
+ }
+ else
+ {
try
{
ArchivaIndexingContext context = idxmgr.createContext( repo );
diff --git a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/ConfigurationHandler.java b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/ConfigurationHandler.java
index c4ee51370..4c21083e9 100644
--- a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/ConfigurationHandler.java
+++ b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/ConfigurationHandler.java
@@ -24,6 +24,8 @@ import org.apache.archiva.configuration.ConfigurationListener;
import org.apache.archiva.configuration.IndeterminateConfigurationException;
import org.springframework.stereotype.Service;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
/**
* This is just a simple wrapper to access the archiva configuration used by the registry and associated classes
*
@@ -36,6 +38,8 @@ public class ConfigurationHandler
private ArchivaConfiguration archivaConfiguration;
+ final ReentrantReadWriteLock lock = new ReentrantReadWriteLock( );
+
public ConfigurationHandler( ArchivaConfiguration archivaConfiguration ) {
this.archivaConfiguration = archivaConfiguration;
}
@@ -68,4 +72,7 @@ public class ConfigurationHandler
archivaConfiguration.save( configuration, "" );
}
+ ReentrantReadWriteLock getLock() {
+ return lock;
+ }
}
diff --git a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/RepositoryGroupHandler.java b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/RepositoryGroupHandler.java
index 9a08e76ae..376be6665 100644
--- a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/RepositoryGroupHandler.java
+++ b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/RepositoryGroupHandler.java
@@ -20,18 +20,22 @@ package org.apache.archiva.repository.base;
import org.apache.archiva.components.registry.RegistryException;
import org.apache.archiva.configuration.Configuration;
import org.apache.archiva.configuration.IndeterminateConfigurationException;
+import org.apache.archiva.configuration.ManagedRepositoryConfiguration;
import org.apache.archiva.configuration.RepositoryGroupConfiguration;
import org.apache.archiva.indexer.merger.MergedRemoteIndexesScheduler;
+import org.apache.archiva.repository.CheckedResult;
import org.apache.archiva.repository.EditableRepository;
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.RepositoryHandler;
import org.apache.archiva.repository.RepositoryProvider;
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.RepositoryChecker;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -49,6 +53,7 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.stream.Collectors;
import static org.apache.archiva.indexer.ArchivaIndexManager.DEFAULT_INDEX_PATH;
@@ -59,52 +64,60 @@ import static org.apache.archiva.indexer.ArchivaIndexManager.DEFAULT_INDEX_PATH;
*
* @author Martin Stockhammer <martin_s@apache.org>
*/
-@Service("repositoryGroupHandler#default")
-public class RepositoryGroupHandler
+@Service( "repositoryGroupHandler#default" )
+public class RepositoryGroupHandler implements RepositoryHandler<RepositoryGroup, RepositoryGroupConfiguration>
{
- private static final Logger log = LoggerFactory.getLogger(RepositoryGroupHandler.class);
+ private static final Logger log = LoggerFactory.getLogger( RepositoryGroupHandler.class );
private final ArchivaRepositoryRegistry repositoryRegistry;
private final ConfigurationHandler configurationHandler;
private final MergedRemoteIndexesScheduler mergedRemoteIndexesScheduler;
- private Map<String, RepositoryGroup> repositoryGroups = new HashMap<>();
+ private final Map<String, RepositoryGroup> repositoryGroups = new HashMap<>( );
private Path groupsDirectory;
/**
* Creates a new instance. All dependencies are injected on the constructor.
- * @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 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
*/
public RepositoryGroupHandler( ArchivaRepositoryRegistry repositoryRegistry,
ConfigurationHandler configurationHandler,
- @Named("mergedRemoteIndexesScheduler#default") MergedRemoteIndexesScheduler mergedRemoteIndexesScheduler) {
+ @Named( "mergedRemoteIndexesScheduler#default" ) MergedRemoteIndexesScheduler mergedRemoteIndexesScheduler )
+ {
this.configurationHandler = configurationHandler;
this.mergedRemoteIndexesScheduler = mergedRemoteIndexesScheduler;
this.repositoryRegistry = repositoryRegistry;
}
+ @Override
@PostConstruct
- private void init() {
+ public void init( )
+ {
log.debug( "Initializing repository group handler " + repositoryRegistry.toString( ) );
+ initializeStorage( );
// We are registering this class on the registry. This is necessary to avoid circular dependencies via injection.
this.repositoryRegistry.registerGroupHandler( this );
- initializeStorage();
}
- public void initializeFromConfig() {
- this.repositoryGroups.clear();
- this.repositoryGroups.putAll( getRepositoryGroupsFromConfig( ) );
- for (RepositoryGroup group : this.repositoryGroups.values()) {
+ public void initializeFromConfig( )
+ {
+ this.repositoryGroups.clear( );
+ this.repositoryGroups.putAll( newInstancesFromConfig( ) );
+ for ( RepositoryGroup group : this.repositoryGroups.values( ) )
+ {
initializeGroup( group );
}
}
- private void initializeStorage() {
+ private void initializeStorage( )
+ {
Path baseDir = this.configurationHandler.getArchivaConfiguration( ).getRepositoryGroupBaseDir( );
- if (!Files.exists( baseDir) ) {
+ if ( !Files.exists( baseDir ) )
+ {
try
{
Files.createDirectories( baseDir );
@@ -117,86 +130,115 @@ public class RepositoryGroupHandler
this.groupsDirectory = baseDir;
}
- private void initializeGroup(RepositoryGroup repositoryGroup) {
- StorageAsset indexDirectoy = getMergedIndexDirectory( repositoryGroup );
- if (!indexDirectoy.exists()) {
+ private void initializeGroup( RepositoryGroup repositoryGroup )
+ {
+ StorageAsset indexDirectory = getMergedIndexDirectory( repositoryGroup );
+ if ( !indexDirectory.exists( ) )
+ {
try
{
- indexDirectoy.create( );
+ indexDirectory.create( );
}
catch ( IOException e )
{
- log.error( "Could not create index directory {} for group {}: {}", indexDirectoy, repositoryGroup.getId( ), e.getMessage( ) );
+ log.error( "Could not create index directory {} for group {}: {}", indexDirectory, repositoryGroup.getId( ), e.getMessage( ) );
}
}
- Path groupPath = groupsDirectory.resolve(repositoryGroup.getId() );
- if ( !Files.exists(groupPath) )
+ Path groupPath = groupsDirectory.resolve( repositoryGroup.getId( ) );
+ if ( !Files.exists( groupPath ) )
{
- try {
- Files.createDirectories(groupPath);
- } catch (IOException e) {
- log.error("Could not create repository group directory {}", groupPath);
+ try
+ {
+ Files.createDirectories( groupPath );
+ }
+ catch ( IOException e )
+ {
+ log.error( "Could not create repository group directory {}", groupPath );
}
}
mergedRemoteIndexesScheduler.schedule( repositoryGroup,
- indexDirectoy);
+ indexDirectory );
}
public StorageAsset getMergedIndexDirectory( RepositoryGroup group )
{
- if (group!=null) {
- return group.getFeature( IndexCreationFeature.class).get().getLocalIndexPath();
- } else {
+ if ( group != null )
+ {
+ return group.getFeature( IndexCreationFeature.class ).get( ).getLocalIndexPath( );
+ }
+ else
+ {
return null;
}
}
- public Map<String, RepositoryGroup> getRepositoryGroupsFromConfig() {
- try {
+
+ @Override
+ public Map<String, RepositoryGroup> newInstancesFromConfig( )
+ {
+ try
+ {
List<RepositoryGroupConfiguration> repositoryGroupConfigurations =
- this.configurationHandler.getBaseConfiguration().getRepositoryGroups();
+ this.configurationHandler.getBaseConfiguration( ).getRepositoryGroups( );
- if (repositoryGroupConfigurations == null) {
- return Collections.emptyMap();
+ if ( repositoryGroupConfigurations == null )
+ {
+ return Collections.emptyMap( );
}
- Map<String, RepositoryGroup> repositoryGroupMap = new LinkedHashMap<>(repositoryGroupConfigurations.size());
-
- Map<RepositoryType, RepositoryProvider> providerMap = repositoryRegistry.getRepositoryProviderMap();
- for (RepositoryGroupConfiguration repoConfig : repositoryGroupConfigurations) {
- RepositoryType repositoryType = RepositoryType.valueOf(repoConfig.getType());
- if (providerMap.containsKey(repositoryType)) {
- try {
- RepositoryGroup repo = createNewRepositoryGroup(providerMap.get(repositoryType), repoConfig);
- repositoryGroupMap.put(repo.getId(), repo);
- } catch (Exception e) {
- log.error("Could not create repository group {}: {}", repoConfig.getId(), e.getMessage(), e);
+ Map<String, RepositoryGroup> repositoryGroupMap = new LinkedHashMap<>( repositoryGroupConfigurations.size( ) );
+
+ Map<RepositoryType, RepositoryProvider> providerMap = repositoryRegistry.getRepositoryProviderMap( );
+ for ( RepositoryGroupConfiguration repoConfig : repositoryGroupConfigurations )
+ {
+ RepositoryType repositoryType = RepositoryType.valueOf( repoConfig.getType( ) );
+ if ( providerMap.containsKey( repositoryType ) )
+ {
+ try
+ {
+ RepositoryGroup repo = createNewRepositoryGroup( providerMap.get( repositoryType ), repoConfig );
+ repositoryGroupMap.put( repo.getId( ), repo );
+ }
+ catch ( Exception e )
+ {
+ log.error( "Could not create repository group {}: {}", repoConfig.getId( ), e.getMessage( ), e );
}
}
}
return repositoryGroupMap;
- } catch (Throwable e) {
- log.error("Could not initialize repositories from config: {}", e.getMessage(), e);
- return Collections.emptyMap();
+ }
+ catch ( Throwable e )
+ {
+ log.error( "Could not initialize repositories from config: {}", e.getMessage( ), e );
+ return Collections.emptyMap( );
}
}
- public RepositoryGroup createNewRepositoryGroup(RepositoryProvider provider, RepositoryGroupConfiguration config) throws RepositoryException
+ @Override
+ public RepositoryGroup newInstance( final RepositoryType type, String id ) throws RepositoryException
{
- RepositoryGroup repositoryGroup = provider.createRepositoryGroup(config);
- repositoryGroup.registerEventHandler( RepositoryEvent.ANY, repositoryRegistry);
- updateRepositoryReferences(provider, repositoryGroup, config);
- return repositoryGroup;
+ RepositoryProvider provider = repositoryRegistry.getProvider( type );
+ RepositoryGroupConfiguration config = new RepositoryGroupConfiguration( );
+ config.setId( id );
+ return createNewRepositoryGroup( provider, config );
}
- public void updateRepositoryReferences( RepositoryProvider provider, RepositoryGroup group, RepositoryGroupConfiguration configuration) {
- if (group instanceof EditableRepositoryGroup ) {
- EditableRepositoryGroup eGroup = (EditableRepositoryGroup) group;
- eGroup.setRepositories(configuration.getRepositories().stream()
- .map(r -> repositoryRegistry.getManagedRepository(r)).collect( Collectors.toList()));
- }
+ @Override
+ public RepositoryGroup newInstance( final RepositoryGroupConfiguration repositoryConfiguration ) throws RepositoryException
+ {
+ RepositoryType type = RepositoryType.valueOf( repositoryConfiguration.getType( ) );
+ RepositoryProvider provider = repositoryRegistry.getProvider( type );
+ return createNewRepositoryGroup( provider, repositoryConfiguration );
}
+ private RepositoryGroup createNewRepositoryGroup( RepositoryProvider provider, RepositoryGroupConfiguration config ) throws RepositoryException
+ {
+ RepositoryGroup repositoryGroup = provider.createRepositoryGroup( config );
+ updateReferences( repositoryGroup, config );
+ return repositoryGroup;
+ }
+
+
/**
* Adds a new repository group to the current list, or replaces the repository group definition with
* the same id, if it exists already.
@@ -205,36 +247,56 @@ public class RepositoryGroupHandler
* @param repositoryGroup the new repository group.
* @throws RepositoryException if the new repository group could not be saved to the configuration.
*/
- public RepositoryGroup putRepositoryGroup( RepositoryGroup repositoryGroup ) throws RepositoryException {
- final String id = repositoryGroup.getId();
- RepositoryGroup originRepoGroup = repositoryGroups.put(id, repositoryGroup);
- try {
- if (originRepoGroup != null && originRepoGroup != repositoryGroup) {
- this.mergedRemoteIndexesScheduler.unschedule( originRepoGroup );
- originRepoGroup.close();
- }
- RepositoryProvider provider = repositoryRegistry.getProvider( repositoryGroup.getType());
- RepositoryGroupConfiguration newCfg = provider.getRepositoryGroupConfiguration(repositoryGroup);
- Configuration configuration = this.configurationHandler.getBaseConfiguration();
- updateRepositoryReferences(provider, repositoryGroup, newCfg);
- RepositoryGroupConfiguration oldCfg = configuration.findRepositoryGroupById(id);
- if (oldCfg != null) {
- configuration.removeRepositoryGroup(oldCfg);
+ @Override
+ public RepositoryGroup put( final RepositoryGroup repositoryGroup ) throws RepositoryException
+ {
+ final String id = repositoryGroup.getId( );
+ RepositoryGroup originRepoGroup = repositoryGroups.remove( id );
+ try
+ {
+ if ( originRepoGroup != null && originRepoGroup != repositoryGroup )
+ {
+ this.mergedRemoteIndexesScheduler.unschedule( originRepoGroup );
+ originRepoGroup.close( );
+ }
+ RepositoryProvider provider = repositoryRegistry.getProvider( repositoryGroup.getType( ) );
+ RepositoryGroupConfiguration newCfg = provider.getRepositoryGroupConfiguration( repositoryGroup );
+ ReentrantReadWriteLock.WriteLock configLock = this.configurationHandler.getLock( ).writeLock( );
+ configLock.lock( );
+ try
+ {
+ Configuration configuration = this.configurationHandler.getBaseConfiguration( );
+ updateReferences( repositoryGroup, newCfg );
+ RepositoryGroupConfiguration oldCfg = configuration.findRepositoryGroupById( id );
+ if ( oldCfg != null )
+ {
+ configuration.removeRepositoryGroup( oldCfg );
}
- configuration.addRepositoryGroup(newCfg);
- repositoryRegistry.saveConfiguration(configuration);
+ configuration.addRepositoryGroup( newCfg );
+ configurationHandler.save( configuration, ConfigurationHandler.REGISTRY_EVENT_TAG );
initializeGroup( repositoryGroup );
- return repositoryGroup;
- } catch (Exception e) {
- // Rollback
- if (originRepoGroup != null) {
- repositoryGroups.put(id, originRepoGroup);
- } else {
- repositoryGroups.remove(id);
- }
- log.error("Exception during configuration update {}", e.getMessage(), e);
- throw new RepositoryException("Could not save the configuration" + (e.getMessage() == null ? "" : ": " + e.getMessage()));
}
+ finally
+ {
+ configLock.unlock( );
+ }
+ repositoryGroups.put( id, repositoryGroup );
+ return repositoryGroup;
+ }
+ catch ( Exception e )
+ {
+ // Rollback
+ if ( originRepoGroup != null )
+ {
+ repositoryGroups.put( id, originRepoGroup );
+ }
+ else
+ {
+ repositoryGroups.remove( id );
+ }
+ log.error( "Exception during configuration update {}", e.getMessage( ), e );
+ throw new RepositoryException( "Could not save the configuration" + ( e.getMessage( ) == null ? "" : ": " + e.getMessage( ) ), e);
+ }
}
/**
@@ -245,72 +307,153 @@ public class RepositoryGroupHandler
* @return the updated or created repository
* @throws RepositoryException if an error occurs, or the configuration is not valid.
*/
- public RepositoryGroup putRepositoryGroup( RepositoryGroupConfiguration repositoryGroupConfiguration ) throws RepositoryException {
- final String id = repositoryGroupConfiguration.getId();
- final RepositoryType repositoryType = RepositoryType.valueOf(repositoryGroupConfiguration.getType());
- Configuration configuration = this.configurationHandler.getBaseConfiguration();
- RepositoryGroup repositoryGroup = repositoryGroups.get(id);
- RepositoryGroupConfiguration oldCfg = repositoryGroup != null ? repositoryRegistry.getProvider(repositoryType).getRepositoryGroupConfiguration(repositoryGroup) : null;
- repositoryGroup = putRepositoryGroup(repositoryGroupConfiguration, configuration);
- try {
- repositoryRegistry.saveConfiguration(configuration);
- } catch ( IndeterminateConfigurationException | RegistryException e) {
- if (oldCfg != null) {
- repositoryRegistry.getProvider(repositoryType).updateRepositoryGroupInstance((EditableRepositoryGroup) repositoryGroup, oldCfg);
+ @Override
+ public RepositoryGroup put( RepositoryGroupConfiguration repositoryGroupConfiguration ) throws RepositoryException
+ {
+ final String id = repositoryGroupConfiguration.getId( );
+ final RepositoryType repositoryType = RepositoryType.valueOf( repositoryGroupConfiguration.getType( ) );
+ final RepositoryProvider provider = repositoryRegistry.getProvider( repositoryType );
+ RepositoryGroup currentRepository;
+ ReentrantReadWriteLock.WriteLock configLock = this.configurationHandler.getLock( ).writeLock( );
+ configLock.lock( );
+ try
+ {
+ Configuration configuration = this.configurationHandler.getBaseConfiguration( );
+ currentRepository = repositoryRegistry.getRepositoryGroup( id );
+ RepositoryGroup oldRepository = currentRepository == null ? null : clone( currentRepository );
+ try
+ {
+
+ if (currentRepository==null) {
+ currentRepository = put( repositoryGroupConfiguration, configuration );
+ } else
+ {
+ setRepositoryGroupDefaults( repositoryGroupConfiguration );
+ provider.updateRepositoryGroupInstance( (EditableRepositoryGroup) currentRepository, repositoryGroupConfiguration );
}
- log.error("Could not save the configuration for repository group {}: {}", id, e.getMessage(), e);
- throw new RepositoryException("Could not save the configuration for repository group " + id + ": " + e.getMessage());
+ configurationHandler.save( configuration, ConfigurationHandler.REGISTRY_EVENT_TAG );
+ updateReferences( currentRepository, repositoryGroupConfiguration );
+ initializeGroup( currentRepository );
+ this.repositoryGroups.put( id, currentRepository );
}
- return repositoryGroup;
+ catch ( IndeterminateConfigurationException | RegistryException | RepositoryException e )
+ {
+ // Trying a rollback
+ if ( oldRepository != null )
+ {
+ RepositoryGroupConfiguration oldCfg = provider.getRepositoryGroupConfiguration( oldRepository );
+ provider.updateRepositoryGroupInstance( (EditableRepositoryGroup) currentRepository, oldCfg);
+ replaceOrAddRepositoryConfig( oldCfg, configuration );
+ try
+ {
+ configurationHandler.save( configuration, ConfigurationHandler.REGISTRY_EVENT_TAG );
+ }
+ catch ( IndeterminateConfigurationException | RegistryException indeterminateConfigurationException )
+ {
+ log.error( "Fatal error, config save during rollback failed: {}", e.getMessage( ), e );
+ }
+ updateReferences( oldRepository, oldCfg );
+ initializeGroup( oldRepository );
+ }
+ log.error( "Could not save the configuration for repository group {}: {}", id, e.getMessage( ), e );
+ if (e instanceof RepositoryException) {
+ throw (RepositoryException) e;
+ } else
+ {
+ throw new RepositoryException( "Could not save the configuration for repository group " + id + ": " + e.getMessage( ) );
+ }
+ }
+ }
+ finally
+ {
+ configLock.unlock( );
+ }
+ return currentRepository;
}
- public RepositoryGroup putRepositoryGroup( RepositoryGroupConfiguration repositoryGroupConfiguration, Configuration configuration ) throws RepositoryException {
- final String id = repositoryGroupConfiguration.getId();
- final RepositoryType repoType = RepositoryType.valueOf(repositoryGroupConfiguration.getType());
- RepositoryGroup repo;
- setRepositoryGroupDefaults(repositoryGroupConfiguration);
- if (repositoryGroups.containsKey(id)) {
- repo = repositoryGroups.get(id);
- this.mergedRemoteIndexesScheduler.unschedule( repo );
- if (repo instanceof EditableRepositoryGroup) {
- repositoryRegistry.getProvider(repoType).updateRepositoryGroupInstance((EditableRepositoryGroup) repo, repositoryGroupConfiguration);
- } else {
- throw new RepositoryException("The repository is not editable " + id);
- }
- } else {
- repo = repositoryRegistry.getProvider(repoType).createRepositoryGroup(repositoryGroupConfiguration);
- repositoryGroups.put(id, repo);
+ @Override
+ public RepositoryGroup put( RepositoryGroupConfiguration repositoryGroupConfiguration, Configuration configuration ) throws RepositoryException
+ {
+ final String id = repositoryGroupConfiguration.getId( );
+ final RepositoryType repoType = RepositoryType.valueOf( repositoryGroupConfiguration.getType( ) );
+ RepositoryGroup repo;
+ setRepositoryGroupDefaults( repositoryGroupConfiguration );
+ if ( repositoryGroups.containsKey( id ) )
+ {
+ repo = clone( repositoryGroups.get( id ) );
+ if ( repo instanceof EditableRepositoryGroup )
+ {
+ repositoryRegistry.getProvider( repoType ).updateRepositoryGroupInstance( (EditableRepositoryGroup) repo, repositoryGroupConfiguration );
+ }
+ else
+ {
+ throw new RepositoryException( "The repository is not editable " + id );
}
- updateRepositoryReferences(repositoryRegistry.getProvider(repoType), repo, repositoryGroupConfiguration);
- replaceOrAddRepositoryConfig(repositoryGroupConfiguration, configuration);
- initializeGroup( repo );
- return repo;
+ }
+ else
+ {
+ repo = repositoryRegistry.getProvider( repoType ).createRepositoryGroup( repositoryGroupConfiguration );
+ }
+ replaceOrAddRepositoryConfig( repositoryGroupConfiguration, configuration );
+ return repo;
}
- private void setRepositoryGroupDefaults(RepositoryGroupConfiguration repositoryGroupConfiguration) {
- if ( StringUtils.isEmpty(repositoryGroupConfiguration.getMergedIndexPath())) {
- repositoryGroupConfiguration.setMergedIndexPath(DEFAULT_INDEX_PATH);
+ @Override
+ public <D> CheckedResult<RepositoryGroup, D> putWithCheck( RepositoryGroupConfiguration repositoryConfiguration, RepositoryChecker<RepositoryGroup, D> checker ) throws RepositoryException
+ {
+ final String id = repositoryConfiguration.getId( );
+ RepositoryGroup currentGroup = repositoryGroups.get( id );
+ Configuration configuration = configurationHandler.getBaseConfiguration( );
+ RepositoryGroup repositoryGroup = put( repositoryConfiguration, configuration );
+ CheckedResult<RepositoryGroup, D> result;
+ if ( currentGroup == null )
+ {
+ result = checker.apply( repositoryGroup );
}
- if (repositoryGroupConfiguration.getMergedIndexTtl() <= 0) {
- repositoryGroupConfiguration.setMergedIndexTtl(300);
+ else
+ {
+ result = checker.applyForUpdate( repositoryGroup );
}
- if (StringUtils.isEmpty(repositoryGroupConfiguration.getCronExpression())) {
- repositoryGroupConfiguration.setCronExpression("0 0 03 ? * MON");
+ if ( result.isValid( ) )
+ {
+ put( repositoryConfiguration );
}
+ return result;
}
- private void replaceOrAddRepositoryConfig(RepositoryGroupConfiguration repositoryGroupConfiguration, Configuration configuration) {
- RepositoryGroupConfiguration oldCfg = configuration.findRepositoryGroupById(repositoryGroupConfiguration.getId());
- if (oldCfg != null) {
- configuration.removeRepositoryGroup(oldCfg);
+
+ private void setRepositoryGroupDefaults( RepositoryGroupConfiguration repositoryGroupConfiguration )
+ {
+ if ( StringUtils.isEmpty( repositoryGroupConfiguration.getMergedIndexPath( ) ) )
+ {
+ repositoryGroupConfiguration.setMergedIndexPath( DEFAULT_INDEX_PATH );
+ }
+ if ( repositoryGroupConfiguration.getMergedIndexTtl( ) <= 0 )
+ {
+ repositoryGroupConfiguration.setMergedIndexTtl( 300 );
+ }
+ if ( StringUtils.isEmpty( repositoryGroupConfiguration.getCronExpression( ) ) )
+ {
+ repositoryGroupConfiguration.setCronExpression( "0 0 03 ? * MON" );
}
- configuration.addRepositoryGroup(repositoryGroupConfiguration);
}
- public void removeRepositoryFromGroups( ManagedRepository repo) {
- if (repo != null) {
- repositoryGroups.values().stream().filter(repoGroup -> repoGroup instanceof EditableRepository ).
- map(repoGroup -> (EditableRepositoryGroup) repoGroup).forEach(repoGroup -> repoGroup.removeRepository(repo));
+ private void replaceOrAddRepositoryConfig( RepositoryGroupConfiguration repositoryGroupConfiguration, Configuration configuration )
+ {
+ RepositoryGroupConfiguration oldCfg = configuration.findRepositoryGroupById( repositoryGroupConfiguration.getId( ) );
+ if ( oldCfg != null )
+ {
+ configuration.removeRepositoryGroup( oldCfg );
+ }
+ configuration.addRepositoryGroup( repositoryGroupConfiguration );
+ }
+
+ public void removeRepositoryFromGroups( ManagedRepository repo )
+ {
+ if ( repo != null )
+ {
+ repositoryGroups.values( ).stream( ).filter( repoGroup -> repoGroup instanceof EditableRepository ).
+ map( repoGroup -> (EditableRepositoryGroup) repoGroup ).forEach( repoGroup -> repoGroup.removeRepository( repo ) );
}
}
@@ -321,75 +464,122 @@ public class RepositoryGroupHandler
* @param id the id of the repository group to remove
* @throws RepositoryException if a error occurs during configuration save
*/
- public void removeRepositoryGroup( final String id ) throws RepositoryException {
- RepositoryGroup repo = getRepositoryGroup(id);
- if (repo != null) {
- try {
- repo = repositoryGroups.remove(id);
- if (repo != null) {
+ @Override
+ public void remove( final String id ) throws RepositoryException
+ {
+ RepositoryGroup repo = get( id );
+ if ( repo != null )
+ {
+ try
+ {
+ repo = repositoryGroups.remove( id );
+ if ( repo != null )
+ {
this.mergedRemoteIndexesScheduler.unschedule( repo );
- repo.close();
- Configuration configuration = this.configurationHandler.getBaseConfiguration();
- RepositoryGroupConfiguration cfg = configuration.findRepositoryGroupById(id);
- if (cfg != null) {
- configuration.removeRepositoryGroup(cfg);
+ repo.close( );
+ Configuration configuration = this.configurationHandler.getBaseConfiguration( );
+ RepositoryGroupConfiguration cfg = configuration.findRepositoryGroupById( id );
+ if ( cfg != null )
+ {
+ configuration.removeRepositoryGroup( cfg );
}
- this.configurationHandler.save(configuration, ConfigurationHandler.REGISTRY_EVENT_TAG );
+ this.configurationHandler.save( configuration, ConfigurationHandler.REGISTRY_EVENT_TAG );
}
- } catch (RegistryException | IndeterminateConfigurationException e) {
+ }
+ catch ( RegistryException | IndeterminateConfigurationException e )
+ {
// Rollback
- log.error("Could not save config after repository removal: {}", e.getMessage(), e);
- repositoryGroups.put(repo.getId(), repo);
- throw new RepositoryException("Could not save configuration after repository removal: " + e.getMessage());
+ log.error( "Could not save config after repository removal: {}", e.getMessage( ), e );
+ repositoryGroups.put( repo.getId( ), repo );
+ throw new RepositoryException( "Could not save configuration after repository removal: " + e.getMessage( ) );
}
}
}
- public void removeRepositoryGroup( String id, Configuration configuration ) throws RepositoryException {
- RepositoryGroup repo = repositoryGroups.get(id);
- if (repo != null) {
- repo = repositoryGroups.remove(id);
- if (repo != null) {
- this.mergedRemoteIndexesScheduler.unschedule( repo );
- repo.close();
- RepositoryGroupConfiguration cfg = configuration.findRepositoryGroupById(id);
- if (cfg != null) {
- configuration.removeRepositoryGroup(cfg);
- }
+ @Override
+ public void remove( String id, Configuration configuration ) throws RepositoryException
+ {
+ RepositoryGroup repo = repositoryGroups.get( id );
+ if ( repo != null )
+ {
+ repo = repositoryGroups.remove( id );
+ if ( repo != null )
+ {
+ this.mergedRemoteIndexesScheduler.unschedule( repo );
+ repo.close( );
+ RepositoryGroupConfiguration cfg = configuration.findRepositoryGroupById( id );
+ if ( cfg != null )
+ {
+ configuration.removeRepositoryGroup( cfg );
}
+ }
}
}
- public RepositoryGroup getRepositoryGroup( String groupId ) {
- return repositoryGroups.get(groupId);
+ @Override
+ public RepositoryGroup get( String groupId )
+ {
+ return repositoryGroups.get( groupId );
}
- public Collection<RepositoryGroup> getRepositoryGroups() {
+ @Override
+ public RepositoryGroup clone( RepositoryGroup repo ) throws RepositoryException
+ {
+ RepositoryProvider provider = repositoryRegistry.getProvider( repo.getType( ) );
+ RepositoryGroupConfiguration cfg = provider.getRepositoryGroupConfiguration( repo );
+ RepositoryGroup cloned = provider.createRepositoryGroup( cfg );
+ cloned.registerEventHandler( RepositoryEvent.ANY, repositoryRegistry );
+ return cloned;
+ }
+
+ @Override
+ public void updateReferences( RepositoryGroup repo, RepositoryGroupConfiguration repositoryConfiguration ) throws RepositoryException
+ {
+ if ( repo instanceof EditableRepositoryGroup )
+ {
+ EditableRepositoryGroup eGroup = (EditableRepositoryGroup) repo;
+ eGroup.setRepositories( repositoryConfiguration.getRepositories( ).stream( )
+ .map( repositoryRegistry::getManagedRepository ).collect( Collectors.toList( ) ) );
+ }
+
+ }
+
+ @Override
+ public Collection<RepositoryGroup> getAll( )
+ {
return repositoryGroups.values( );
}
- public boolean hasRepositoryGroup(String id) {
+ @Override
+ public boolean has( String id )
+ {
return repositoryGroups.containsKey( id );
}
@PreDestroy
- private void destroy() {
+ private void destroy( )
+ {
this.close( );
}
- public void close() {
- for (RepositoryGroup group : repositoryGroups.values()) {
+ @Override
+ public void close( )
+ {
+ for ( RepositoryGroup group : repositoryGroups.values( ) )
+ {
try
{
mergedRemoteIndexesScheduler.unschedule( group );
group.close( );
- } catch (Throwable e) {
+ }
+ catch ( Throwable e )
+ {
log.error( "Could not close repository group {}: {}", group.getId( ), e.getMessage( ) );
}
}
- this.repositoryGroups.clear();
+ this.repositoryGroups.clear( );
}
}
diff --git a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/validation/CommonGroupValidator.java b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/validation/CommonGroupValidator.java
new file mode 100644
index 000000000..f9fd6fd1e
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/validation/CommonGroupValidator.java
@@ -0,0 +1,144 @@
+package org.apache.archiva.repository.base.validation;
+/*
+ * 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.RepositoryGroup;
+import org.apache.archiva.repository.RepositoryRegistry;
+import org.apache.archiva.repository.base.ConfigurationHandler;
+import org.apache.archiva.repository.validation.AbstractRepositoryValidator;
+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.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ *
+ * A validator for repository groups. All validation errors are prefixed with category 'repository_group'.
+ *
+ * @author Martin Stockhammer <martin_s@apache.org>
+ */
+@Service( "repositoryValidator#common#group" )
+public class CommonGroupValidator extends AbstractRepositoryValidator<RepositoryGroup> implements RepositoryValidator<RepositoryGroup>
+{
+
+ private static final Pattern REPO_GROUP_ID_PATTERN = Pattern.compile( "[A-Za-z0-9\\._\\-]+" );
+ private final ConfigurationHandler configurationHandler;
+
+ private RepositoryRegistry repositoryRegistry;
+
+ public CommonGroupValidator( ConfigurationHandler configurationHandler )
+ {
+ this.configurationHandler = configurationHandler;
+ }
+
+
+ private Map<String, List<ValidationError>> appendError( Map<String, List<ValidationError>> errorMap, String errorKey, Object... parameter )
+ {
+ Map<String, List<ValidationError>> result;
+ result = errorMap == null ? new HashMap<>( ) : errorMap;
+ ValidationError error = ValidationError.ofKey( errorKey, parameter );
+ List<ValidationError> errList = result.computeIfAbsent( error.getAttribute( ), k -> new ArrayList<ValidationError>( ) );
+ errList.add( error );
+ return result;
+ }
+
+ public ValidationResponse apply( RepositoryGroup repositoryGroup, boolean updateMode ) throws IllegalArgumentException
+ {
+ final String repoGroupId = repositoryGroup.getId( );
+ Map<String, List<ValidationError>> errors = null;
+ if ( StringUtils.isBlank( repoGroupId ) )
+ {
+ errors = appendError( errors, "repository_group.id.empty" );
+ }
+
+ if ( repoGroupId.length( ) > 100 )
+ {
+ errors = appendError( errors, "repository_group.id.max_length", repoGroupId, Integer.toString( 100 ) );
+
+ }
+
+ Matcher matcher = REPO_GROUP_ID_PATTERN.matcher( repoGroupId );
+ if ( !matcher.matches( ) )
+ {
+ errors = appendError( errors, "repository_group.id.invalid_chars", "alphanumeric, '.', '-','_'" );
+ }
+
+ if ( repositoryGroup.getMergedIndexTTL( ) <= 0 )
+ {
+ errors = appendError( errors, "repository_group.merged_index_ttl.min", "0" );
+ }
+
+
+ if ( repositoryRegistry != null && !updateMode )
+ {
+ if ( repositoryRegistry.hasRepositoryGroup( repoGroupId ) )
+ {
+ errors = appendError( errors, "repository_group.id.group_exists", repoGroupId );
+ }
+ else if ( repositoryRegistry.hasManagedRepository( repoGroupId ) )
+ {
+ errors = appendError( errors, "repository_group.id.managed_exists" );
+ }
+ else if ( repositoryRegistry.hasRemoteRepository( repoGroupId ) )
+ {
+ errors = appendError( errors, "repository_group.id.remote_exists" );
+ }
+ }
+ return new ValidationResponse(repositoryGroup, errors );
+ }
+
+
+
+
+ public ConfigurationHandler getConfigurationHandler( )
+ {
+ return configurationHandler;
+ }
+
+ public RepositoryRegistry getRepositoryRegistry( )
+ {
+ return repositoryRegistry;
+ }
+
+ @Override
+ public void setRepositoryRegistry( RepositoryRegistry repositoryRegistry )
+ {
+ this.repositoryRegistry = repositoryRegistry;
+ }
+
+ @Override
+ public Class<RepositoryGroup> getFlavour( )
+ {
+ return RepositoryGroup.class;
+ }
+
+ @Override
+ public boolean isFlavour( Class<?> clazz )
+ {
+ return RepositoryGroup.class.isAssignableFrom( clazz );
+ }
+}
diff --git a/archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/base/ArchivaRepositoryRegistryTest.java b/archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/base/ArchivaRepositoryRegistryTest.java
index b7cbf1fb5..00bbbc8c1 100644
--- a/archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/base/ArchivaRepositoryRegistryTest.java
+++ b/archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/base/ArchivaRepositoryRegistryTest.java
@@ -30,15 +30,14 @@ import org.apache.archiva.repository.Repository;
import org.apache.archiva.repository.RepositoryException;
import org.apache.archiva.repository.RepositoryRegistry;
import org.apache.archiva.repository.RepositoryType;
-import org.apache.archiva.test.utils.ArchivaSpringJUnit4ClassRunner;
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+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;
@@ -50,12 +49,13 @@ import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Collection;
-import static org.junit.Assert.*;
+import static org.junit.jupiter.api.Assertions.*;
+
/**
* Test for RepositoryRegistry
*/
-@RunWith(ArchivaSpringJUnit4ClassRunner.class)
+@ExtendWith( SpringExtension.class)
@ContextConfiguration(locations = { "classpath*:/META-INF/spring-context.xml", "classpath:/spring-context.xml" })
public class ArchivaRepositoryRegistryTest
{
@@ -75,7 +75,7 @@ public class ArchivaRepositoryRegistryTest
private static Path cfgCopy;
private static Path archivaCfg;
- @BeforeClass
+ @BeforeAll
public static void classSetup() throws IOException, URISyntaxException
{
URL archivaCfgUri = Thread.currentThread().getContextClassLoader().getResource( "archiva.xml" );
@@ -86,7 +86,7 @@ public class ArchivaRepositoryRegistryTest
}
}
- @AfterClass
+ @AfterAll
public static void classTearDown() throws IOException
{
if (cfgCopy!=null) {
@@ -94,7 +94,7 @@ public class ArchivaRepositoryRegistryTest
}
}
- @Before
+ @BeforeEach
public void setUp( ) throws Exception
{
assertNotNull( repositoryRegistry );
@@ -111,7 +111,7 @@ public class ArchivaRepositoryRegistryTest
repositoryRegistry.reload();
}
- @After
+ @AfterEach
public void tearDown( ) throws Exception
{
Files.deleteIfExists( userCfg );
@@ -160,7 +160,7 @@ public class ArchivaRepositoryRegistryTest
assertTrue(repo instanceof ManagedRepository);
assertTrue( repo.hasIndex( ) );
assertTrue(repo.isScanned());
- Assert.assertEquals( RepositoryType.MAVEN, repo.getType());
+ assertEquals( RepositoryType.MAVEN, repo.getType());
}
@Test
@@ -213,7 +213,7 @@ public class ArchivaRepositoryRegistryTest
managedRepository = BasicManagedRepository.newFilesystemInstance("central", "Test repo", archivaConfiguration.getRepositoryBaseDir().resolve("central"));
managedRepository.setDescription( managedRepository.getPrimaryLocale(), "This is just a test" );
- ManagedRepository updatedRepo = null;
+ ManagedRepository updatedRepo;
try {
repositoryRegistry.putRepository( managedRepository );
throw new RuntimeException("Repository exception should be thrown, if there exists a remote repository already with that id");
@@ -224,12 +224,12 @@ public class ArchivaRepositoryRegistryTest
managedRepository.setDescription( managedRepository.getPrimaryLocale(), "This is just a test" );
updatedRepo = repositoryRegistry.putRepository( managedRepository );
- assertTrue(updatedRepo==managedRepository);
+ assertSame( updatedRepo, managedRepository );
assertNotNull(managedRepository.getContent());
assertEquals(6, repositoryRegistry.getRepositories().size());
ManagedRepository managedRepository1 = repositoryRegistry.getManagedRepository( "internal" );
assertEquals("Test repo", managedRepository1.getName());
- assertTrue(managedRepository1==managedRepository);
+ assertSame( managedRepository1, managedRepository );
}
@@ -253,7 +253,7 @@ public class ArchivaRepositoryRegistryTest
cfg.setId("internal");
cfg.setName("This is internal test 002");
repo = repositoryRegistry.putRepository( cfg );
- assertTrue(internalRepo==repo);
+ assertSame( internalRepo, repo );
assertEquals("This is internal test 002",repo.getName());
assertEquals(5, repositoryRegistry.getManagedRepositories().size());
@@ -284,7 +284,7 @@ public class ArchivaRepositoryRegistryTest
cfg.setId("internal");
cfg.setName("This is internal test 002");
repo = repositoryRegistry.putRepository( cfg, configuration );
- assertTrue(internalRepo==repo);
+ assertSame( internalRepo, repo );
assertEquals("This is internal test 002",repo.getName());
assertEquals(5, repositoryRegistry.getManagedRepositories().size());
@@ -299,16 +299,17 @@ public class ArchivaRepositoryRegistryTest
remoteRepository.setDescription( remoteRepository.getPrimaryLocale(), "This is just a test" );
RemoteRepository newRepo = repositoryRegistry.putRepository(remoteRepository);
- assertTrue(remoteRepository==newRepo);
+ assertSame( remoteRepository, newRepo );
assertNotNull(remoteRepository.getContent());
assertEquals(6, repositoryRegistry.getRepositories().size());
remoteRepository = BasicRemoteRepository.newFilesystemInstance( "internal", "Test repo", archivaConfiguration.getRemoteRepositoryBaseDir() );
remoteRepository.setDescription( remoteRepository.getPrimaryLocale(), "This is just a test" );
- RemoteRepository updatedRepo = null;
+ RemoteRepository updatedRepo;
try
{
updatedRepo = repositoryRegistry.putRepository( remoteRepository );
+ assertSame( remoteRepository, updatedRepo );
throw new RuntimeException("Should throw repository exception, if repository exists already and is not the same type.");
} catch (RepositoryException e) {
// OK
@@ -318,12 +319,12 @@ public class ArchivaRepositoryRegistryTest
remoteRepository.setDescription( remoteRepository.getPrimaryLocale(), "This is just a test" );
updatedRepo = repositoryRegistry.putRepository( remoteRepository );
- assertTrue(updatedRepo==remoteRepository);
+ assertSame( updatedRepo, remoteRepository );
assertNotNull(remoteRepository.getContent());
assertEquals(6, repositoryRegistry.getRepositories().size());
RemoteRepository remoteRepository1 = repositoryRegistry.getRemoteRepository( "central" );
assertEquals("Test repo", remoteRepository1.getName());
- assertTrue(remoteRepository1==remoteRepository);
+ assertSame( remoteRepository1, remoteRepository );
}
@Test
@@ -346,7 +347,7 @@ public class ArchivaRepositoryRegistryTest
cfg.setId("central");
cfg.setName("This is central test 002");
repo = repositoryRegistry.putRepository( cfg );
- assertTrue(internalRepo==repo);
+ assertSame( internalRepo, repo );
assertEquals("This is central test 002",repo.getName());
assertEquals(2, repositoryRegistry.getRemoteRepositories().size());
@@ -376,7 +377,7 @@ public class ArchivaRepositoryRegistryTest
cfg.setId("central");
cfg.setName("This is central test 002");
repo = repositoryRegistry.putRepository( cfg, configuration );
- assertTrue(internalRepo==repo);
+ assertSame( internalRepo, repo );
assertEquals("This is central test 002",repo.getName());
assertEquals(2, repositoryRegistry.getRemoteRepositories().size());
@@ -483,7 +484,7 @@ public class ArchivaRepositoryRegistryTest
assertNotNull(clone);
assertNull(clone.getContent());
assertEquals("Archiva Managed Internal Repository", clone.getName());
- assertFalse(managedRepository==clone);
+ assertNotSame( managedRepository, clone );
}
@@ -516,8 +517,15 @@ public class ArchivaRepositoryRegistryTest
assertNotNull(clone);
assertNull(clone.getContent());
assertEquals("Central Repository", clone.getName());
- assertFalse(remoteRepository==clone);
+ assertNotSame( remoteRepository, clone );
+
+ }
+ @Test
+ void validateRepository() {
+ Repository repo = repositoryRegistry.getRepository( "internal" );
+ assertNotNull( repo );
+ assertTrue( repositoryRegistry.validateRepository( repo ).isValid() );
}
} \ No newline at end of file
diff --git a/archiva-modules/archiva-maven/archiva-maven-repository/src/main/java/org/apache/archiva/repository/maven/MavenRepositoryProvider.java b/archiva-modules/archiva-maven/archiva-maven-repository/src/main/java/org/apache/archiva/repository/maven/MavenRepositoryProvider.java
index 2afc249bb..1deadfe38 100644
--- a/archiva-modules/archiva-maven/archiva-maven-repository/src/main/java/org/apache/archiva/repository/maven/MavenRepositoryProvider.java
+++ b/archiva-modules/archiva-maven/archiva-maven-repository/src/main/java/org/apache/archiva/repository/maven/MavenRepositoryProvider.java
@@ -27,8 +27,6 @@ import org.apache.archiva.configuration.RemoteRepositoryConfiguration;
import org.apache.archiva.configuration.RepositoryGroupConfiguration;
import org.apache.archiva.event.Event;
import org.apache.archiva.event.EventHandler;
-import org.apache.archiva.event.EventManager;
-import org.apache.archiva.event.EventType;
import org.apache.archiva.repository.EditableManagedRepository;
import org.apache.archiva.repository.EditableRemoteRepository;
import org.apache.archiva.repository.EditableRepository;
@@ -76,7 +74,7 @@ import static org.apache.archiva.indexer.ArchivaIndexManager.DEFAULT_INDEX_PATH;
import static org.apache.archiva.indexer.ArchivaIndexManager.DEFAULT_PACKED_INDEX_PATH;
/**
- * Provider for the maven2 repository implementations
+ * Provider for the maven2 repository implementation
*/
@Service("mavenRepositoryProvider")
public class MavenRepositoryProvider implements RepositoryProvider {
@@ -88,28 +86,7 @@ public class MavenRepositoryProvider implements RepositoryProvider {
@Inject
private FileLockManager fileLockManager;
- private class EventHandlerInfo {
- EventType<?> type;
- EventHandler<?> handler;
-
- public EventHandlerInfo( EventType<?> type, EventHandler<?> handler )
- {
- this.type = type;
- this.handler = handler;
- }
-
- public EventType<?> getType( )
- {
- return type;
- }
-
- public EventHandler<?> getHandler( )
- {
- return handler;
- }
- }
-
- private List<EventHandler<? super RepositoryEvent>> repositoryEventHandlers = new ArrayList<>( );
+ private final List<EventHandler<? super RepositoryEvent>> repositoryEventHandlers = new ArrayList<>( );
private static final Logger log = LoggerFactory.getLogger(MavenRepositoryProvider.class);
@@ -152,7 +129,7 @@ public class MavenRepositoryProvider implements RepositoryProvider {
try {
storage = new FilesystemStorage(baseDir.resolve(id), fileLockManager);
} catch (IOException e) {
- log.error("Could not initialize fileystem for repository {}", id);
+ log.error("Could not initialize filesystem for repository {}: '{}'", id, e.getMessage());
throw new RuntimeException(e);
}
MavenRemoteRepository repo = new MavenRemoteRepository( id, name, storage );
@@ -162,15 +139,15 @@ public class MavenRepositoryProvider implements RepositoryProvider {
@Override
public EditableRepositoryGroup createRepositoryGroup(String id, String name) {
- return createRepositoryGroup(id, name, archivaConfiguration.getRepositoryBaseDir());
+ return createRepositoryGroup(id, name, archivaConfiguration.getRepositoryGroupBaseDir().resolve( id ));
}
- public MavenRepositoryGroup createRepositoryGroup(String id, String name, Path baseDir) {
+ public MavenRepositoryGroup createRepositoryGroup(String id, String name, Path repositoryPath) {
FilesystemStorage storage;
try {
- storage = new FilesystemStorage(baseDir.resolve(id), fileLockManager);
+ storage = new FilesystemStorage(repositoryPath, fileLockManager);
} catch (IOException e) {
- log.error("Could not initialize fileystem for repository {}", id);
+ log.error("Could not initialize filesystem for repository {}: '{}'", id, e.getMessage());
throw new RuntimeException(e);
}
MavenRepositoryGroup group = new MavenRepositoryGroup( id, name, storage );
@@ -349,13 +326,21 @@ public class MavenRepositoryProvider implements RepositoryProvider {
@Override
public RepositoryGroup createRepositoryGroup(RepositoryGroupConfiguration configuration) throws RepositoryException {
- Path repositoryGroupBase = getArchivaConfiguration().getRepositoryGroupBaseDir();
+ Path repositoryPath = getRepositoryGroupPath( configuration );
MavenRepositoryGroup newGrp = createRepositoryGroup(configuration.getId(), configuration.getName(),
- repositoryGroupBase);
+ repositoryPath);
updateRepositoryGroupInstance(newGrp, configuration);
return newGrp;
}
+ private Path getRepositoryGroupPath(RepositoryGroupConfiguration configuration) {
+ if (StringUtils.isNotEmpty( configuration.getLocation() )) {
+ return Paths.get( configuration.getLocation( ) );
+ } else {
+ return getArchivaConfiguration( ).getRepositoryGroupBaseDir( ).resolve( configuration.getId( ) );
+ }
+ }
+
@Override
public void updateRepositoryGroupInstance(EditableRepositoryGroup repositoryGroup, RepositoryGroupConfiguration configuration) throws RepositoryException {
repositoryGroup.setName(repositoryGroup.getPrimaryLocale(), configuration.getName());
@@ -551,7 +536,8 @@ public class MavenRepositoryProvider implements RepositoryProvider {
return stagingRepository;
}
- private void setBaseConfig(EditableRepository repo, AbstractRepositoryConfiguration cfg) throws RepositoryException {
+ private void setBaseConfig( EditableRepository repo, AbstractRepositoryConfiguration cfg)
+ {
URI baseUri = archivaConfiguration.getRepositoryBaseDir().toUri();
repo.setBaseUri(baseUri);
diff --git a/archiva-modules/archiva-maven/archiva-maven-repository/src/test/java/org/apache/archiva/repository/maven/mock/RepositoryRegistryMock.java b/archiva-modules/archiva-maven/archiva-maven-repository/src/test/java/org/apache/archiva/repository/maven/mock/RepositoryRegistryMock.java
index 4ceed3865..c9fba72a6 100644
--- a/archiva-modules/archiva-maven/archiva-maven-repository/src/test/java/org/apache/archiva/repository/maven/mock/RepositoryRegistryMock.java
+++ b/archiva-modules/archiva-maven/archiva-maven-repository/src/test/java/org/apache/archiva/repository/maven/mock/RepositoryRegistryMock.java
@@ -23,7 +23,9 @@ import org.apache.archiva.repository.Repository;
import org.apache.archiva.repository.RepositoryException;
import org.apache.archiva.repository.base.ArchivaRepositoryRegistry;
import org.apache.archiva.repository.base.ConfigurationHandler;
+import org.apache.archiva.repository.validation.RepositoryValidator;
+import java.util.List;
import java.util.Map;
import java.util.TreeMap;
@@ -32,9 +34,9 @@ public class RepositoryRegistryMock extends ArchivaRepositoryRegistry
private Map<String, ManagedRepository> managedRepositories = new TreeMap<>();
- public RepositoryRegistryMock( ConfigurationHandler configurationHandler )
+ public RepositoryRegistryMock( ConfigurationHandler configurationHandler, List<RepositoryValidator<? extends Repository>> validatorList )
{
- super( configurationHandler );
+ super( configurationHandler, validatorList );
}
@Override
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 7eea24702..1f021d0f4 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
@@ -35,12 +35,16 @@ package org.apache.archiva.rest.api.model.v2;/*
*/
import io.swagger.v3.oas.annotations.media.Schema;
+import org.apache.archiva.repository.Repository;
+import org.apache.archiva.repository.features.IndexCreationFeature;
+import org.apache.archiva.repository.features.RepositoryFeature;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
+import java.util.stream.Collectors;
/**
* @author Martin Stockhammer <martin_s@apache.org>
@@ -63,16 +67,19 @@ public class RepositoryGroup implements Serializable
this.id = id;
}
- public static RepositoryGroup of( org.apache.archiva.admin.model.beans.RepositoryGroup modelObj ) {
+ public static RepositoryGroup of( org.apache.archiva.repository.RepositoryGroup modelObj ) {
RepositoryGroup result = new RepositoryGroup( );
MergeConfiguration mergeConfig = new MergeConfiguration( );
result.setMergeConfiguration( mergeConfig );
result.setId( modelObj.getId() );
- result.setLocation( modelObj.getLocation() );
- result.setRepositories( modelObj.getRepositories() );
- mergeConfig.setMergedIndexPath( modelObj.getMergedIndexPath() );
- mergeConfig.setMergedIndexTtlMinutes( modelObj.getMergedIndexTtl( ) );
- mergeConfig.setIndexMergeSchedule( modelObj.getCronExpression( ) );
+ result.setLocation( modelObj.getLocation().toString() );
+ result.setRepositories( modelObj.getRepositories().stream().map( Repository::getId ).collect( Collectors.toList()) );
+ if (modelObj.supportsFeature( IndexCreationFeature.class )) {
+ IndexCreationFeature icf = modelObj.getFeature( IndexCreationFeature.class ).get();
+ mergeConfig.setMergedIndexPath( icf.getIndexPath( ).toString() );
+ mergeConfig.setMergedIndexTtlMinutes( modelObj.getMergedIndexTTL( ) );
+ mergeConfig.setIndexMergeSchedule( modelObj.getSchedulingDefinition() );
+ }
return result;
}
diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/ValidationError.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/ValidationError.java
new file mode 100644
index 000000000..efa1ec987
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/ValidationError.java
@@ -0,0 +1,139 @@
+package org.apache.archiva.rest.api.model.v2;
+/*
+ * 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 io.swagger.v3.oas.annotations.media.Schema;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author Martin Stockhammer <martin_s@apache.org>
+ */
+@XmlRootElement(name = "validationError")
+@Schema(name = "ValidationError", description = "A validation error.")
+public class ValidationError implements Serializable
+{
+ private static final long serialVersionUID = 2079020598090660171L;
+
+ String key;
+ String field;
+ String category;
+ String type;
+ List<String> parameter;
+
+
+ public ValidationError( )
+ {
+ }
+
+ public ValidationError( String key, String field, String category, String type, List<String> parameter) {
+ this.key = key;
+ this.field = field;
+ this.category = category;
+ this.type = type;
+ if (parameter==null) {
+ this.parameter = new ArrayList<>( );
+ } else
+ {
+ this.parameter = parameter;
+ }
+ }
+
+ /**
+ * Creates a new instance based on the given error
+ * @param error the error instance
+ * @return
+ */
+ public static ValidationError of( org.apache.archiva.repository.validation.ValidationError error ) {
+ return error != null ? new ValidationError( error.getErrorKey( ), error.getAttribute( ), error.getCategory( ),
+ error.getType( ), error.getArguments( ).stream( ).map( Object::toString ).collect( Collectors.toList( ) ) )
+ : new ValidationError( );
+ }
+
+ /**
+ * Creates a new instance based on the field name and the error instance
+ * @param fieldName the name of the field to which the error applies
+ * @param error the error definition
+ * @return a new validation error instance
+ */
+ public static ValidationError of( String fieldName, org.apache.archiva.repository.validation.ValidationError error ) {
+ return error != null ? new ValidationError( error.getErrorKey( ), fieldName, error.getCategory( ),
+ error.getType( ), error.getArguments( ).stream( ).map( Object::toString ).collect( Collectors.toList( ) ) )
+ : new ValidationError( );
+ }
+
+ @Schema(name="key", description = "The full key of the validation error")
+ public String getKey( )
+ {
+ return key;
+ }
+
+ public void setKey( String key )
+ {
+ this.key = key;
+ }
+
+ @Schema(name="field", description = "The name of the field where the error was detected")
+ public String getField( )
+ {
+ return field;
+ }
+
+ public void setField( String field )
+ {
+ this.field = field;
+ }
+
+ @Schema(name="category", description = "The name of the category this error is assigned to")
+ public String getCategory( )
+ {
+ return category;
+ }
+
+ public void setCategory( String category )
+ {
+ this.category = category;
+ }
+
+ @Schema(name="type", description = "The type of the error. This is a unique string that defines the type of error, e.g. empty, bad_number_range, ... .")
+ public String getType( )
+ {
+ return type;
+ }
+
+ public void setType( String type )
+ {
+ this.type = type;
+ }
+
+ @Schema(name="parameter", description = "The list of parameters, that can be used to create a translated error message")
+ public List<String> getParameter( )
+ {
+ return parameter;
+ }
+
+ public void setParameter( List<String> parameter )
+ {
+ this.parameter = parameter;
+ }
+}
diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/ArchivaRestError.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/ArchivaRestError.java
index 0df947505..17c5b89d2 100644
--- a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/ArchivaRestError.java
+++ b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/ArchivaRestError.java
@@ -19,11 +19,13 @@ package org.apache.archiva.rest.api.services.v2;
*/
import io.swagger.v3.oas.annotations.media.Schema;
+import org.apache.archiva.rest.api.model.v2.ValidationError;
import org.apache.commons.lang3.StringUtils;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.Serializable;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
/**
@@ -37,7 +39,8 @@ public class ArchivaRestError
{
private static final long serialVersionUID = -8892617571273167067L;
- private List<ErrorMessage> errorMessages = new ArrayList<ErrorMessage>( 1 );
+ private List<ErrorMessage> errorMessages = new ArrayList<>( 1 );
+ private List<ValidationError> validationErrors;
public ArchivaRestError()
{
@@ -51,6 +54,19 @@ public class ArchivaRestError
{
errorMessages.add( new ErrorMessage( e.getMessage(), null ) );
}
+ if (e instanceof ValidationException) {
+ this.validationErrors = ( (ValidationException) e ).getValidationErrors( );
+ }
+ }
+
+ public ArchivaRestError( ValidationException e )
+ {
+ errorMessages.addAll( e.getErrorMessages() );
+ if ( e.getErrorMessages().isEmpty() && StringUtils.isNotEmpty( e.getMessage() ) )
+ {
+ errorMessages.add( new ErrorMessage( e.getMessage(), null ) );
+ }
+ this.validationErrors = e.getValidationErrors( );
}
@Schema(name="error_messages", description = "The list of errors that occurred while processing the REST request")
@@ -68,4 +84,15 @@ public class ArchivaRestError
{
this.errorMessages.add( errorMessage );
}
+
+ @Schema( name = "has_validation_errors", description = "True, if the error contains validation errors" )
+ public boolean hasValidationErrors( )
+ {
+ return this.validationErrors != null && this.validationErrors.size( ) > 0;
+ }
+
+ @Schema( name = "validation_errors", description = "The list of validation errors")
+ public List<ValidationError> getValidationErrors() {
+ return hasValidationErrors() ? this.validationErrors : Collections.emptyList( );
+ }
}
diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/ErrorKeys.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/ErrorKeys.java
index ab74ceaec..fee06c9e7 100644
--- a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/ErrorKeys.java
+++ b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/ErrorKeys.java
@@ -45,6 +45,9 @@ public interface ErrorKeys
{
String PREFIX = "archiva.";
+
+ String VALIDATION_ERROR = PREFIX + "validation_error";
+
String REPOSITORY_GROUP_PREFIX = PREFIX + "repository_group.";
String REPOSITORY_PREFIX = PREFIX + "repository.";
@@ -67,6 +70,7 @@ public interface ErrorKeys
String REPOSITORY_GROUP_NOT_FOUND = REPOSITORY_GROUP_PREFIX+"notfound";
String REPOSITORY_GROUP_ADD_FAILED = REPOSITORY_GROUP_PREFIX+"add.failed" ;
String REPOSITORY_GROUP_EXIST = REPOSITORY_GROUP_PREFIX+"exists";
+ String REPOSITORY_GROUP_UPDATE_FAILED = REPOSITORY_GROUP_PREFIX + "update.failed";
String REPOSITORY_GROUP_DELETE_FAILED = REPOSITORY_GROUP_PREFIX + "delete.failed";
String REPOSITORY_NOT_FOUND = REPOSITORY_PREFIX + "notfound";
diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/RepositoryGroupService.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/RepositoryGroupService.java
index a95c68f95..1c0b0595e 100644
--- a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/RepositoryGroupService.java
+++ b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/RepositoryGroupService.java
@@ -91,7 +91,7 @@ public interface RepositoryGroupService
@QueryParam( "order" ) @DefaultValue( "asc" ) String order )
throws ArchivaRestServiceException;
- @Path( "{repositoryGroupId}" )
+ @Path( "{id}" )
@GET
@Produces( {APPLICATION_JSON} )
@RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
@@ -112,7 +112,7 @@ public interface RepositoryGroupService
content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) )
}
)
- RepositoryGroup getRepositoryGroup( @PathParam( "repositoryGroupId" ) String repositoryGroupId )
+ RepositoryGroup getRepositoryGroup( @PathParam( "id" ) String repositoryGroupId )
throws ArchivaRestServiceException;
@Path( "" )
@@ -133,7 +133,7 @@ public interface RepositoryGroupService
},
responses = {
@ApiResponse( responseCode = "201",
- description = "If the list could be returned",
+ description = "If the repository group was created",
content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = RepositoryGroup.class ) )
),
@ApiResponse( responseCode = "303", description = "The repository group exists already",
@@ -150,7 +150,7 @@ public interface RepositoryGroupService
RepositoryGroup addRepositoryGroup( RepositoryGroup repositoryGroup )
throws ArchivaRestServiceException;
- @Path( "{repositoryGroupId}" )
+ @Path( "{id}" )
@PUT
@Consumes( {APPLICATION_JSON} )
@Produces( {APPLICATION_JSON} )
@@ -179,10 +179,10 @@ public interface RepositoryGroupService
content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) )
}
)
- RepositoryGroup updateRepositoryGroup( @PathParam( "repositoryGroupId" ) String groupId, RepositoryGroup repositoryGroup )
+ RepositoryGroup updateRepositoryGroup( @PathParam( "id" ) String groupId, RepositoryGroup repositoryGroup )
throws ArchivaRestServiceException;
- @Path( "{repositoryGroupId}" )
+ @Path( "{id}" )
@DELETE
@Produces( {APPLICATION_JSON} )
@RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
@@ -202,10 +202,10 @@ public interface RepositoryGroupService
content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
}
)
- Response deleteRepositoryGroup( @PathParam( "repositoryGroupId" ) String repositoryGroupId )
+ Response deleteRepositoryGroup( @PathParam( "id" ) String repositoryGroupId )
throws ArchivaRestServiceException;
- @Path( "{repositoryGroupId}/repositories/{repositoryId}" )
+ @Path( "{id}/repositories/{repositoryId}" )
@PUT
@Produces( {APPLICATION_JSON} )
@RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
@@ -225,11 +225,11 @@ public interface RepositoryGroupService
content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
}
)
- RepositoryGroup addRepositoryToGroup( @PathParam( "repositoryGroupId" ) String repositoryGroupId,
+ RepositoryGroup addRepositoryToGroup( @PathParam( "id" ) String repositoryGroupId,
@PathParam( "repositoryId" ) String repositoryId )
throws ArchivaRestServiceException;
- @Path( "{repositoryGroupId}/repositories/{repositoryId}" )
+ @Path( "{id}/repositories/{repositoryId}" )
@DELETE
@Produces( {APPLICATION_JSON} )
@RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
@@ -249,7 +249,7 @@ public interface RepositoryGroupService
content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
}
)
- RepositoryGroup deleteRepositoryFromGroup( @PathParam( "repositoryGroupId" ) String repositoryGroupId,
+ RepositoryGroup deleteRepositoryFromGroup( @PathParam( "id" ) String repositoryGroupId,
@PathParam( "repositoryId" ) String repositoryId )
throws ArchivaRestServiceException;
diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/ValidationException.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/ValidationException.java
new file mode 100644
index 000000000..bedb46d48
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/ValidationException.java
@@ -0,0 +1,85 @@
+package org.apache.archiva.rest.api.services.v2;
+/*
+ * 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.validation.ValidationResponse;
+import org.apache.archiva.rest.api.model.v2.ValidationError;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * Exception is thrown
+ * @author Martin Stockhammer <martin_s@apache.org>
+ */
+public class ValidationException extends ArchivaRestServiceException
+{
+ public static final int DEFAULT_CODE = 422;
+
+ public static final ErrorMessage DEFAULT_MESSAGE = new ErrorMessage( ErrorKeys.VALIDATION_ERROR );
+
+ private List<ValidationError> validationErrors;
+
+ public ValidationException( ) {
+ super( DEFAULT_MESSAGE, DEFAULT_CODE );
+ }
+
+ public ValidationException( int errorCode) {
+ super( DEFAULT_MESSAGE, errorCode );
+ }
+
+ 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 ) {
+ return new ValidationException( errorList.stream( ).map( ValidationError::of ).collect( Collectors.toList( ) ) );
+ }
+
+ public static <R extends Repository> ValidationException of( ValidationResponse<R> result ) {
+ if (result.isValid()) {
+ return new ValidationException( );
+ } else
+ {
+ return new ValidationException( result.getResult( ).entrySet( ).stream( ).flatMap(
+ v -> v.getValue( ).stream( ).map( e -> ValidationError.of( v.getKey( ), e ) ) ).collect( Collectors.toList( ) ) );
+ }
+ }
+
+ public List<ValidationError> getValidationErrors( )
+ {
+ return validationErrors==null? Collections.emptyList() : validationErrors;
+ }
+
+ public void setValidationErrors( List<ValidationError> validationErrors )
+ {
+ this.validationErrors = validationErrors;
+ }
+
+ public void addValidationError( ValidationError error) {
+ if (this.validationErrors==null) {
+ this.validationErrors = new ArrayList<>( );
+ }
+ this.validationErrors.add( error );
+ }
+}
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 44ce638ac..4535336d6 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
@@ -34,17 +34,23 @@ package org.apache.archiva.rest.services.v2;/*
* under the License.
*/
-import org.apache.archiva.admin.model.EntityExistsException;
-import org.apache.archiva.admin.model.EntityNotFoundException;
-import org.apache.archiva.admin.model.RepositoryAdminException;
-import org.apache.archiva.admin.model.group.RepositoryGroupAdmin;
+import org.apache.archiva.components.registry.RegistryException;
import org.apache.archiva.components.rest.model.PagedResult;
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.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.ValidationResponse;
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;
import org.apache.archiva.rest.api.services.v2.ErrorMessage;
import org.apache.archiva.rest.api.services.v2.RepositoryGroupService;
+import org.apache.archiva.rest.api.services.v2.ValidationException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -54,14 +60,11 @@ import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
-import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
-import static org.apache.archiva.rest.services.utils.AuditHelper.getAuditData;
-
/**
* REST V2 Implementation for repository groups.
*
@@ -72,25 +75,30 @@ import static org.apache.archiva.rest.services.utils.AuditHelper.getAuditData;
@Service("v2.repositoryGroupService#rest")
public class DefaultRepositoryGroupService implements RepositoryGroupService
{
+ private final ConfigurationHandler configurationHandler;
+
@Context
HttpServletResponse httpServletResponse;
@Context
UriInfo uriInfo;
- final private RepositoryGroupAdmin repositoryGroupAdmin;
+ final private RepositoryRegistry repositoryRegistry;
+
+
private static final Logger log = LoggerFactory.getLogger( DefaultRepositoryGroupService.class );
- private static final QueryHelper<org.apache.archiva.admin.model.beans.RepositoryGroup> QUERY_HELPER = new QueryHelper<>( new String[]{"id"} );
+ private static final QueryHelper<org.apache.archiva.repository.RepositoryGroup> QUERY_HELPER = new QueryHelper<>( new String[]{"id"} );
static
{
- QUERY_HELPER.addStringFilter( "id", org.apache.archiva.admin.model.beans.RepositoryGroup::getId );
- QUERY_HELPER.addNullsafeFieldComparator( "id", org.apache.archiva.admin.model.beans.RepositoryGroup::getId );
+ QUERY_HELPER.addStringFilter( "id", org.apache.archiva.repository.RepositoryGroup::getId );
+ QUERY_HELPER.addNullsafeFieldComparator( "id", org.apache.archiva.repository.RepositoryGroup::getId );
}
- public DefaultRepositoryGroupService(RepositoryGroupAdmin repositoryGroupAdmin) {
- this.repositoryGroupAdmin = repositoryGroupAdmin;
+ public DefaultRepositoryGroupService( RepositoryRegistry repositoryRegistry, ConfigurationHandler configurationHandler ) {
+ this.repositoryRegistry = repositoryRegistry;
+ this.configurationHandler = configurationHandler;
}
@Override
@@ -98,19 +106,14 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
{
try
{
- Predicate<org.apache.archiva.admin.model.beans.RepositoryGroup> filter = QUERY_HELPER.getQueryFilter( searchTerm );
- Comparator<org.apache.archiva.admin.model.beans.RepositoryGroup> ordering = QUERY_HELPER.getComparator( orderBy, QUERY_HELPER.isAscending( order ) );
- int totalCount = Math.toIntExact( repositoryGroupAdmin.getRepositoriesGroups( ).stream( ).filter( filter ).count( ) );
- List<RepositoryGroup> result = repositoryGroupAdmin.getRepositoriesGroups( ).stream( ).filter( filter ).sorted( ordering ).skip( offset ).limit( limit ).map(
+ Predicate<org.apache.archiva.repository.RepositoryGroup> filter = QUERY_HELPER.getQueryFilter( searchTerm );
+ Comparator<org.apache.archiva.repository.RepositoryGroup> ordering = QUERY_HELPER.getComparator( orderBy, QUERY_HELPER.isAscending( order ) );
+ int totalCount = Math.toIntExact( repositoryRegistry.getRepositoryGroups( ).stream( ).filter( filter ).count( ) );
+ List<RepositoryGroup> result = repositoryRegistry.getRepositoryGroups( ).stream( ).filter( filter ).sorted( ordering ).skip( offset ).limit( limit ).map(
RepositoryGroup::of
).collect( Collectors.toList( ) );
return new PagedResult<>( totalCount, offset, limit, result );
}
- catch ( RepositoryAdminException e )
- {
- log.error( "Repository admin error: {}", e.getMessage( ), e );
- throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_ADMIN_ERROR, e.getMessage( ) ) );
- }
catch ( ArithmeticException e )
{
log.error( "Could not convert total count: {}", e.getMessage( ) );
@@ -126,27 +129,16 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
{
throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_NOT_FOUND, "" ), 404 );
}
- try
- {
- org.apache.archiva.admin.model.beans.RepositoryGroup group = repositoryGroupAdmin.getRepositoryGroup( repositoryGroupId );
- return RepositoryGroup.of( group );
- }
- catch ( EntityNotFoundException e )
- {
- throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_NOT_FOUND, repositoryGroupId ), 404 );
- }
- catch ( RepositoryAdminException e )
- {
- throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_ADMIN_ERROR, e.getMessage( ) ) );
- }
+ org.apache.archiva.repository.RepositoryGroup group = repositoryRegistry.getRepositoryGroup( repositoryGroupId );
+ return RepositoryGroup.of( group );
}
- private org.apache.archiva.admin.model.beans.RepositoryGroup toModel( RepositoryGroup group )
+ private RepositoryGroupConfiguration toConfig( RepositoryGroup group )
{
- org.apache.archiva.admin.model.beans.RepositoryGroup result = new org.apache.archiva.admin.model.beans.RepositoryGroup( );
+ RepositoryGroupConfiguration result = new RepositoryGroupConfiguration( );
result.setId( group.getId( ) );
result.setLocation( group.getLocation( ) );
- result.setRepositories( new ArrayList<>( group.getRepositories( ) ) );
+ result.setRepositories( group.getRepositories( ) );
result.setMergedIndexPath( group.getMergeConfiguration( ).getMergedIndexPath( ) );
result.setMergedIndexTtl( group.getMergeConfiguration( ).getMergedIndexTtlMinutes( ) );
result.setCronExpression( group.getMergeConfiguration( ).getIndexMergeSchedule( ) );
@@ -156,19 +148,29 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
@Override
public RepositoryGroup addRepositoryGroup( RepositoryGroup repositoryGroup ) throws ArchivaRestServiceException
{
+ final String groupId = repositoryGroup.getId( );
+ if ( StringUtils.isEmpty( groupId ) ) {
+ throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_INVALID_ID, groupId ), 422 );
+ }
+ if (repositoryRegistry.hasRepositoryGroup( groupId )) {
+ httpServletResponse.setHeader( "Location", uriInfo.getAbsolutePathBuilder( ).path( groupId ).build( ).toString( ) );
+ throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_ID_EXISTS, groupId ), 303 );
+ }
try
{
- Boolean result = repositoryGroupAdmin.addRepositoryGroup( toModel( repositoryGroup ), getAuditData() );
- if ( result )
+ RepositoryGroupConfiguration configuration = toConfig( repositoryGroup );
+ Configuration config = configurationHandler.getBaseConfiguration( );
+ org.apache.archiva.repository.RepositoryGroup repo = repositoryRegistry.putRepositoryGroup( configuration, config);
+ if ( repo!=null )
{
- org.apache.archiva.admin.model.beans.RepositoryGroup newGroup = repositoryGroupAdmin.getRepositoryGroup( repositoryGroup.getId( ) );
- if ( newGroup != null )
- {
- return RepositoryGroup.of( newGroup );
- }
- else
+ ValidationResponse<org.apache.archiva.repository.RepositoryGroup> validationResult = repositoryRegistry.validateRepository( repo );
+ if ( validationResult.isValid( ) )
{
- throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_ADD_FAILED ) );
+ httpServletResponse.setStatus( 201 );
+ configurationHandler.save( config );
+ return RepositoryGroup.of( repo );
+ } else {
+ throw ValidationException.of( validationResult );
}
}
else
@@ -176,75 +178,54 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_ADD_FAILED ) );
}
}
- catch ( EntityExistsException e )
+ catch ( RepositoryException | IndeterminateConfigurationException | RegistryException e )
{
- httpServletResponse.setHeader( "Location", uriInfo.getAbsolutePathBuilder( ).path( repositoryGroup.getId( ) ).build( ).toString( ) );
- throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_EXIST, repositoryGroup.getId( ) ), 303 );
- }
- catch ( RepositoryAdminException e )
- {
- return handleAdminException( e );
- }
- }
-
- private RepositoryGroup handleAdminException( RepositoryAdminException e ) throws ArchivaRestServiceException
- {
- log.error( "Repository admin error: {}", e.getMessage( ), e );
- if ( e.keyExists( ) )
- {
- throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.PREFIX + e.getKey( ), e.getParameters( ) ) );
- }
- else
- {
- throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_ADMIN_ERROR, e.getMessage( ) ) );
+ throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_ADD_FAILED ) );
}
}
@Override
- public RepositoryGroup updateRepositoryGroup( String repositoryGroupId, RepositoryGroup repositoryGroup ) throws ArchivaRestServiceException
+ public RepositoryGroup updateRepositoryGroup( final String repositoryGroupId, final RepositoryGroup repositoryGroup ) throws ArchivaRestServiceException
{
if ( StringUtils.isEmpty( repositoryGroupId ) )
{
throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_NOT_FOUND, "" ), 404 );
}
- org.apache.archiva.admin.model.beans.RepositoryGroup updateGroup = toModel( repositoryGroup );
+ if ( !repositoryRegistry.hasRepositoryGroup( repositoryGroupId ) )
+ {
+ throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_NOT_FOUND ), 404 );
+ }
+ repositoryGroup.setId( repositoryGroupId );
+
try
{
- org.apache.archiva.admin.model.beans.RepositoryGroup originGroup = repositoryGroupAdmin.getRepositoryGroup( repositoryGroupId );
- if ( StringUtils.isEmpty( updateGroup.getId( ) ) )
- {
- updateGroup.setId( repositoryGroupId );
- }
- if ( StringUtils.isEmpty( updateGroup.getLocation( ) ) )
- {
- updateGroup.setLocation( originGroup.getLocation( ) );
- }
- if ( StringUtils.isEmpty( updateGroup.getMergedIndexPath( ) ) )
- {
- updateGroup.setMergedIndexPath( originGroup.getMergedIndexPath( ) );
- }
- if ( updateGroup.getCronExpression( ) == null )
- {
- updateGroup.setCronExpression( originGroup.getCronExpression( ) );
- }
- if ( updateGroup.getRepositories( ) == null || updateGroup.getRepositories( ).size( ) == 0 )
+ RepositoryGroupConfiguration configuration = toConfig( repositoryGroup );
+ Configuration config = configurationHandler.getBaseConfiguration( );
+ org.apache.archiva.repository.RepositoryGroup repo = repositoryRegistry.putRepositoryGroup( configuration, config);
+ if ( repo!=null )
{
- updateGroup.setRepositories( originGroup.getRepositories( ) );
+ ValidationResponse<org.apache.archiva.repository.RepositoryGroup> validationResult = repositoryRegistry.validateRepository( repo );
+ if ( validationResult.isValid( ) )
+ {
+ httpServletResponse.setStatus( 201 );
+ configurationHandler.save( config );
+ return RepositoryGroup.of( repo );
+ } else {
+ throw ValidationException.of( validationResult );
+ }
}
- if ( updateGroup.getMergedIndexTtl( ) <= 0 )
+ else
{
- updateGroup.setMergedIndexTtl( originGroup.getMergedIndexTtl( ) );
+ log.error( "Returned repository group was null {}", repositoryGroupId );
+ throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_UPDATE_FAILED ) );
}
- repositoryGroupAdmin.updateRepositoryGroup( updateGroup, getAuditData( ) );
- return RepositoryGroup.of( repositoryGroupAdmin.getRepositoryGroup( repositoryGroupId ) );
- }
- catch ( EntityNotFoundException e )
- {
- throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_NOT_FOUND, repositoryGroupId ), 404 );
+
}
- catch ( RepositoryAdminException e )
+ catch ( RepositoryException | IndeterminateConfigurationException | RegistryException e )
{
- return handleAdminException( e );
+ log.error( "Exception during repository group update: {}", e.getMessage( ), e );
+ throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_UPDATE_FAILED, e.getMessage() ) );
+
}
}
@@ -257,22 +238,16 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
}
try
{
- Boolean deleted = repositoryGroupAdmin.deleteRepositoryGroup( repositoryGroupId, getAuditData( ) );
- if ( !deleted )
- {
- throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_DELETE_FAILED ) );
+ org.apache.archiva.repository.RepositoryGroup group = repositoryRegistry.getRepositoryGroup( repositoryGroupId );
+ if (group==null) {
+ throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_NOT_FOUND, "" ), 404 );
}
+ repositoryRegistry.removeRepositoryGroup( group );
return Response.ok( ).build( );
}
- catch ( EntityNotFoundException e )
- {
- throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_NOT_FOUND, repositoryGroupId ), 404 );
- }
- catch ( RepositoryAdminException e )
+ catch ( RepositoryException e )
{
- handleAdminException( e );
- // cannot happen:
- return null;
+ throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_DELETE_FAILED ) );
}
}
@@ -289,28 +264,31 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
}
try
{
- repositoryGroupAdmin.addRepositoryToGroup( repositoryGroupId, repositoryId, getAuditData( ) );
- return RepositoryGroup.of( repositoryGroupAdmin.getRepositoryGroup( repositoryGroupId ) );
- }
- catch ( EntityNotFoundException e )
- {
- return handleNotFoundException( repositoryGroupId, repositoryId, e );
- }
- catch ( EntityExistsException e )
- {
- // This is thrown, if the repositoryId is already assigned to the group. We ignore this for the PUT action (nothing to do).
- try
- {
- return RepositoryGroup.of( repositoryGroupAdmin.getRepositoryGroup( repositoryGroupId ) );
+ org.apache.archiva.repository.RepositoryGroup repositoryGroup = repositoryRegistry.getRepositoryGroup( repositoryGroupId );
+ if (repositoryGroup==null) {
+ throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_NOT_FOUND, "" ), 404 );
+ }
+ if (!(repositoryGroup instanceof EditableRepositoryGroup )) {
+ log.error( "This group instance is not editable: {}", repositoryGroupId );
+ throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_UPDATE_FAILED, "" ), 500 );
}
- catch ( RepositoryAdminException repositoryAdminException )
+ EditableRepositoryGroup editableRepositoryGroup = (EditableRepositoryGroup) repositoryGroup;
+ if ( editableRepositoryGroup.getRepositories().stream().anyMatch( repo -> repositoryId.equals(repo.getId())) )
{
- return handleAdminException( e );
+ 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) {
+ throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_NOT_FOUND, "" ), 404 );
}
+ editableRepositoryGroup.addRepository( managedRepo );
+ org.apache.archiva.repository.RepositoryGroup newGroup = repositoryRegistry.putRepositoryGroup( editableRepositoryGroup );
+ return RepositoryGroup.of( newGroup );
}
- catch ( RepositoryAdminException e )
+ catch ( RepositoryException e )
{
- return handleAdminException( e );
+ throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_UPDATE_FAILED, e.getMessage() ), 500 );
}
}
@@ -327,34 +305,24 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
}
try
{
- repositoryGroupAdmin.deleteRepositoryFromGroup( repositoryGroupId, repositoryId, getAuditData( ) );
- return RepositoryGroup.of( repositoryGroupAdmin.getRepositoryGroup( repositoryGroupId ) );
- }
- catch ( EntityNotFoundException e )
- {
- return handleNotFoundException( repositoryGroupId, repositoryId, e );
- }
- catch ( RepositoryAdminException e )
- {
- return handleAdminException( e );
- }
- }
-
- protected RepositoryGroup handleNotFoundException( String repositoryGroupId, String repositoryId, EntityNotFoundException e ) throws ArchivaRestServiceException
- {
- if ( e.getParameters( ).length > 0 )
- {
- if ( repositoryGroupId.equals( e.getParameters( )[0] ) )
- {
- throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_NOT_FOUND, repositoryGroupId ), 404 );
+ org.apache.archiva.repository.RepositoryGroup repositoryGroup = repositoryRegistry.getRepositoryGroup( repositoryGroupId );
+ if (repositoryGroup==null) {
+ throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_NOT_FOUND, "" ), 404 );
}
- else if ( repositoryId.equals( e.getParameters( )[0] ) )
- {
- throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_NOT_FOUND, repositoryGroupId ), 404 );
+ 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;
+
+ editableRepositoryGroup.removeRepository( repositoryId );
+ org.apache.archiva.repository.RepositoryGroup newGroup = repositoryRegistry.putRepositoryGroup( editableRepositoryGroup );
+ return RepositoryGroup.of( newGroup );
+ }
+ catch ( RepositoryException e )
+ {
+ throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_UPDATE_FAILED, e.getMessage() ), 500 );
}
- log.warn( "Entity not found but neither group nor repo set in exception" );
- throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_NOT_FOUND, repositoryGroupId ), 404 );
}