]> source.dussan.org Git - archiva.git/commitdiff
Centralizing repository group handling. First part.
authorMartin Stockhammer <martin_s@apache.org>
Tue, 1 Jun 2021 20:46:51 +0000 (22:46 +0200)
committerMartin Stockhammer <martin_s@apache.org>
Tue, 1 Jun 2021 20:46:51 +0000 (22:46 +0200)
39 files changed:
archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/ArchivaConfiguration.java
archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/ConfigurationEvent.java
archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/DefaultArchivaConfiguration.java
archiva-modules/archiva-base/archiva-consumers/archiva-core-consumers/src/test/java/org/apache/archiva/consumers/core/repository/AbstractRepositoryPurgeTest.java
archiva-modules/archiva-base/archiva-consumers/archiva-core-consumers/src/test/java/org/apache/archiva/consumers/core/repository/CleanupReleasedSnapshotsRepositoryPurgeTest.java
archiva-modules/archiva-base/archiva-consumers/archiva-indexer-consumers/src/test/java/org/apache/archiva/consumers/lucene/NexusIndexerConsumerTest.java
archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/group/DefaultRepositoryGroupAdmin.java
archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/repository/AbstractRepositoryAdminTest.java
archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/repository/group/RepositoryGroupAdminTest.java
archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/event/RepositoryRegistryEvent.java
archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/ArchivaRepositoryRegistry.java
archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/ConfigurationHandler.java [new file with mode: 0644]
archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/RepositoryGroupHandler.java [new file with mode: 0644]
archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/base/ArchivaRepositoryRegistryTest.java
archiva-modules/archiva-maven/archiva-maven-indexer/src/test/java/org/apache/archiva/indexer/maven/MavenIndexManagerTest.java
archiva-modules/archiva-maven/archiva-maven-indexer/src/test/java/org/apache/archiva/indexer/maven/search/AbstractMavenRepositorySearch.java
archiva-modules/archiva-maven/archiva-maven-indexer/src/test/java/org/apache/archiva/indexer/maven/search/MavenRepositorySearchOSGITest.java
archiva-modules/archiva-maven/archiva-maven-indexer/src/test/java/org/apache/archiva/indexer/maven/search/MavenRepositorySearchPaginateTest.java
archiva-modules/archiva-maven/archiva-maven-proxy/src/test/java/org/apache/archiva/proxy/MockConfiguration.java
archiva-modules/archiva-maven/archiva-maven-repository/src/test/java/org/apache/archiva/repository/maven/metadata/storage/mock/MockConfiguration.java
archiva-modules/archiva-maven/archiva-maven-repository/src/test/java/org/apache/archiva/repository/maven/mock/RepositoryRegistryMock.java
archiva-modules/archiva-maven/archiva-maven-repository/src/test/java/org/apache/archiva/repository/maven/mock/configuration/StubConfiguration.java
archiva-modules/archiva-maven/archiva-maven-repository/src/test/java/org/apache/archiva/repository/maven/mock/configuration/TestConfiguration.java
archiva-modules/archiva-maven/archiva-maven-scheduler/src/test/java/org/apache/archiva/scheduler/indexing/maven/ArchivaIndexingTaskExecutorTest.java
archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/java/org/apache/archiva/scheduler/repository/AbstractArchivaRepositoryScanningTaskExecutorTest.java
archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/MavenManagedRepositoryService.java [deleted file]
archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/RepositoryGroupService.java
archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/maven/MavenManagedRepositoryService.java [new file with mode: 0644]
archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/DefaultRepositoriesService.java
archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/utils/AuditHelper.java [new file with mode: 0644]
archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/DefaultMavenManagedRepositoryService.java
archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/DefaultRepositoryGroupService.java
archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/resources/META-INF/spring-context.xml
archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/test/java/org/apache/archiva/rest/services/v2/AbstractNativeRestServices.java
archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/test/java/org/apache/archiva/rest/services/v2/NativeMavenManagedRepositoryServiceTest.java [new file with mode: 0644]
archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/test/resources/META-INF/spring-context-test.xml
archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/archiva/webdav/AbstractRepositoryServletTestCase.java
archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/archiva/webdav/ArchivaDavResourceFactoryTest.java
archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/archiva/webdav/RepositoryServletSecurityTest.java

index 9d8ead089a13ec4e2ceaba5c8104ec888cb87cc8..f230257020ce62fc6e2f3d523cbe3cfc7150086e 100644 (file)
@@ -55,6 +55,20 @@ public interface ArchivaConfiguration
     void save( Configuration configuration )
         throws RegistryException, IndeterminateConfigurationException;
 
+    /**
+     * Save any updated configuration. This method allows to add a tag to the thrown event.
+     * This allows to verify the origin if the caller is the same as the listener.
+     *
+     * @param configuration the configuration to save
+     * @param eventTag the tag to add to the thrown event
+     * @throws org.apache.archiva.components.registry.RegistryException
+     *          if there is a problem saving the registry data
+     * @throws IndeterminateConfigurationException
+     *          if the configuration cannot be saved because it was read from two sources
+     */
+    void save( Configuration configuration, String eventTag )
+        throws RegistryException, IndeterminateConfigurationException;
+
     /**
      * Determines if the configuration in use was as a result of a defaulted configuration.
      *
index 397c838fae1ccd797541501517e240812fb1c946..9639effbefa84308176ba14427c9e1723e98bbfb 100644 (file)
@@ -32,9 +32,17 @@ public class ConfigurationEvent
 
     private int type;
 
+    private String tag;
+
     public ConfigurationEvent( int type )
     {
         this.type = type;
+        tag = "";
+    }
+
+    public ConfigurationEvent(int type, String tag) {
+        this.type = type;
+        this.tag = tag;
     }
 
     public int getType()
@@ -42,35 +50,33 @@ public class ConfigurationEvent
         return type;
     }
 
+    public String getTag( )
+    {
+        return tag;
+    }
+
+    public void setTag( String tag )
+    {
+        this.tag = tag;
+    }
+
     @Override
-    public int hashCode()
+    public boolean equals( Object o )
     {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + type;
-        return result;
+        if ( this == o ) return true;
+        if ( o == null || getClass( ) != o.getClass( ) ) return false;
+
+        ConfigurationEvent that = (ConfigurationEvent) o;
+
+        if ( type != that.type ) return false;
+        return tag.equals( that.tag );
     }
 
     @Override
-    public boolean equals( Object obj )
+    public int hashCode( )
     {
-        if ( this == obj )
-        {
-            return true;
-        }
-        if ( obj == null )
-        {
-            return false;
-        }
-        if ( getClass() != obj.getClass() )
-        {
-            return false;
-        }
-        final ConfigurationEvent other = (ConfigurationEvent) obj;
-        if ( type != other.type )
-        {
-            return false;
-        }
-        return true;
+        int result = type;
+        result = 31 * result + tag.hashCode( );
+        return result;
     }
 }
index 11ae70569aa959f88d54cebe0b66b7a14e20ccc8..ee80fc8fc3677abd5286ddffa0935c2d80cb6d84 100644 (file)
@@ -410,7 +410,20 @@ public class DefaultArchivaConfiguration
 
     @SuppressWarnings("unchecked")
     @Override
-    public synchronized void save(Configuration configuration)
+    public synchronized void save(Configuration configuration) throws IndeterminateConfigurationException, RegistryException
+    {
+        save( configuration, "" );
+    }
+
+    /**
+     * Saves the configuration and adds the given tag to the event.
+     * @param configuration the configuration to save
+     * @param eventTag the tag to add to the configuration saved event
+     * @throws IndeterminateConfigurationException if the
+     * @throws RegistryException
+     */
+    @Override
+    public synchronized void save(Configuration configuration, String eventTag)
             throws IndeterminateConfigurationException, RegistryException {
         Registry section = registry.getSection(KEY + ".user");
         Registry baseSection = registry.getSection(KEY + ".base");
@@ -491,7 +504,7 @@ public class DefaultArchivaConfiguration
         this.configuration = unescapeExpressions(configuration);
         isConfigurationDefaulted = false;
 
-        triggerEvent(ConfigurationEvent.SAVED);
+        triggerEvent(ConfigurationEvent.SAVED, eventTag);
     }
 
     private void escapeCronExpressions(Configuration configuration) {
@@ -530,7 +543,7 @@ public class DefaultArchivaConfiguration
             addRegistryChangeListener(regListener);
         }
 
-        triggerEvent(ConfigurationEvent.SAVED);
+        triggerEvent(ConfigurationEvent.SAVED, "default-file");
 
         Registry section = registry.getSection(KEY + ".user");
         if (section == null) {
@@ -580,8 +593,8 @@ public class DefaultArchivaConfiguration
         }
     }
 
-    private void triggerEvent(int type) {
-        ConfigurationEvent evt = new ConfigurationEvent(type);
+    private void triggerEvent(int type, String eventTag) {
+        ConfigurationEvent evt = new ConfigurationEvent(type, eventTag);
         for (ConfigurationListener listener : listeners) {
             listener.configurationEvent(evt);
         }
index f1791b7d0156ae4927db534f3e11188b9850b837..b2f66aa7f6793c27ab5831d2c6c101731d8d1293 100644 (file)
@@ -26,6 +26,7 @@ import org.apache.archiva.metadata.repository.RepositorySessionFactory;
 import org.apache.archiva.repository.ManagedRepositoryContent;
 import org.apache.archiva.repository.RepositoryRegistry;
 import org.apache.archiva.repository.base.ArchivaRepositoryRegistry;
+import org.apache.archiva.repository.base.RepositoryGroupHandler;
 import org.apache.archiva.repository.maven.metadata.storage.Maven2RepositoryPathTranslator;
 import org.apache.archiva.repository.base.BasicManagedRepository;
 import org.apache.archiva.repository.ReleaseScheme;
@@ -113,6 +114,10 @@ public abstract class AbstractRepositoryPurgeTest
     @Inject
     protected ApplicationContext applicationContext;
 
+    @SuppressWarnings( "unused" )
+    @Inject
+    RepositoryGroupHandler repositoryGroupHandler;
+
 
     @Before
     public void setUp()
index 85ee9426d608e8a7947102cd902d5d78624ca241..241eeb09bd00f59227c40a4660d42928aa767cf1 100644 (file)
@@ -27,6 +27,7 @@ import org.apache.archiva.components.taskqueue.TaskQueueException;
 import org.apache.archiva.repository.base.ArchivaRepositoryRegistry;
 import org.apache.archiva.repository.base.BasicManagedRepository;
 import org.apache.archiva.repository.ReleaseScheme;
+import org.apache.archiva.repository.base.RepositoryGroupHandler;
 import org.apache.archiva.scheduler.ArchivaTaskScheduler;
 import org.apache.archiva.scheduler.indexing.ArtifactIndexingTask;
 import org.apache.archiva.test.utils.ArchivaSpringJUnit4ClassRunner;
@@ -96,6 +97,9 @@ public class NexusIndexerConsumerTest
     @Inject
     ArchivaRepositoryRegistry repositoryRegistry;
 
+    @SuppressWarnings( "unused" )
+    @Inject
+    RepositoryGroupHandler repositoryGroupHandler;
 
     @Override
     @Before
index ae6c4fd3b94c1f9eb71bb7a7875c22b4552f3e9f..13f3ce6f9f91c959806efff945e252e41b870b70 100644 (file)
@@ -29,11 +29,15 @@ import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin;
 import org.apache.archiva.admin.repository.AbstractRepositoryAdmin;
 import org.apache.archiva.configuration.Configuration;
 import org.apache.archiva.configuration.RepositoryGroupConfiguration;
+import org.apache.archiva.event.Event;
+import org.apache.archiva.event.EventHandler;
+import org.apache.archiva.event.EventType;
 import org.apache.archiva.metadata.model.facets.AuditEvent;
 import org.apache.archiva.indexer.merger.MergedRemoteIndexesScheduler;
 import org.apache.archiva.repository.EditableRepositoryGroup;
 import org.apache.archiva.repository.RepositoryException;
 import org.apache.archiva.repository.RepositoryRegistry;
+import org.apache.archiva.repository.event.RepositoryRegistryEvent;
 import org.apache.archiva.repository.features.IndexCreationFeature;
 import org.apache.archiva.repository.storage.StorageAsset;
 import org.apache.commons.lang3.StringUtils;
@@ -62,7 +66,7 @@ import java.util.stream.Collectors;
 @Service("repositoryGroupAdmin#default")
 public class DefaultRepositoryGroupAdmin
     extends AbstractRepositoryAdmin
-    implements RepositoryGroupAdmin
+    implements RepositoryGroupAdmin, EventHandler<Event>
 {
 
     private Logger log = LoggerFactory.getLogger( getClass() );
@@ -82,6 +86,10 @@ public class DefaultRepositoryGroupAdmin
     private Path groupsDirectory;
 
     @PostConstruct
+    public void baseInit() {
+        this.repositoryRegistry.registerEventHandler( EventType.ROOT, this );
+    }
+
     public void initialize()
     {
         String appServerBase = getRegistry().getString( "appserver.base" );
@@ -438,4 +446,14 @@ public class DefaultRepositoryGroupAdmin
         rg.setLocation( group.getLocation().toString() );
         return rg;
     }
+
+    @Override
+    public void handle( Event event )
+    {
+        if ( EventType.isInstanceOf( event.getType( ), RepositoryRegistryEvent.INITIALIZED ) )
+        {
+            log.debug( "Initializing RepositoryGroupAdmin" );
+            initialize();
+        }
+    }
 }
index d3086e2f7d8bbd72f39af90e40d949ce171fbb2d..993151a837ff6fd06f97ec440946fbdd88b9f851 100644 (file)
@@ -31,6 +31,7 @@ import org.apache.archiva.configuration.ArchivaConfiguration;
 import org.apache.archiva.redback.role.RoleManager;
 import org.apache.archiva.redback.users.User;
 import org.apache.archiva.redback.users.memory.SimpleUser;
+import org.apache.archiva.repository.base.RepositoryGroupHandler;
 import org.apache.archiva.test.utils.ArchivaSpringJUnit4ClassRunner;
 import org.apache.commons.lang3.StringUtils;
 import org.junit.Before;
@@ -84,6 +85,10 @@ public abstract class AbstractRepositoryAdminTest
     @Inject
     private ArchivaConfiguration archivaConfiguration;
 
+    @SuppressWarnings( "unused" )
+    @Inject
+    RepositoryGroupHandler repositoryGroupHandler;
+
     @Before
     public void initialize() {
         Path confFile = Paths.get(APPSERVER_BASE_PATH, "conf/archiva.xml");
index ed6e2868344d8501119c2bb8b8420607e4edf80b..49fd38573345702d0e750275fb82def388475604 100644 (file)
@@ -26,6 +26,7 @@ import org.apache.archiva.admin.repository.AbstractRepositoryAdminTest;
 import org.apache.archiva.metadata.model.facets.AuditEvent;
 import org.apache.archiva.repository.Repository;
 import org.apache.archiva.repository.RepositoryRegistry;
+import org.apache.archiva.repository.base.RepositoryGroupHandler;
 import org.junit.Test;
 
 import javax.inject.Inject;
@@ -44,6 +45,9 @@ public class RepositoryGroupAdminTest
     @Inject
     RepositoryRegistry repositoryRegistry;
 
+    @Inject
+    RepositoryGroupHandler repositoryGroupHandler;
+
     @Test
     public void addAndDeleteGroup()
         throws Exception
index 1e11579590661109265b7c5f1455a7d04a7bef5f..7f3b62ddca41c883c039f2a23ff5133a376e4a41 100644 (file)
@@ -47,6 +47,21 @@ public class RepositoryRegistryEvent extends Event
      */
     public static EventType<RepositoryRegistryEvent> INITIALIZED = new EventType(ANY, "REGISTRY.INITIALIZED");
 
+    /**
+     * When the repository groups are initialized
+     */
+    public static EventType<RepositoryRegistryEvent> GROUPS_INITIALIZED = new EventType(ANY, "REGISTRY.GROUPS_INITIALIZED");
+
+    /**
+     * When the managed repositories are initialized
+     */
+    public static EventType<RepositoryRegistryEvent> MANAGED_REPOS_INITIALIZED = new EventType(ANY, "REGISTRY.MANAGED_REPOS_INITIALIZED");
+
+    /**
+     * When the remote repositories are initialized
+     */
+    public static EventType<RepositoryRegistryEvent> REMOTE_REPOS_INITIALIZED = new EventType(ANY, "REGISTRY.REMOTE_REPOS_INITIALIZED");
+
     public RepositoryRegistryEvent(EventType<? extends RepositoryRegistryEvent> type, Object origin) {
         super(type, origin);
     }
index b909e24de0b15e18277d268dc5588cc6083f8e15..6a3d0e0b39fc2233288ef994390ca1b9782c6a9e 100644 (file)
@@ -28,7 +28,6 @@ import org.apache.archiva.components.registry.RegistryException;
 import org.apache.archiva.repository.EditableManagedRepository;
 import org.apache.archiva.repository.EditableRemoteRepository;
 import org.apache.archiva.repository.EditableRepository;
-import org.apache.archiva.repository.EditableRepositoryGroup;
 import org.apache.archiva.repository.ManagedRepository;
 import org.apache.archiva.repository.RemoteRepository;
 import org.apache.archiva.repository.Repository;
@@ -55,12 +54,11 @@ import javax.annotation.PreDestroy;
 import javax.inject.Inject;
 import javax.inject.Named;
 import java.util.*;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import static org.apache.archiva.indexer.ArchivaIndexManager.DEFAULT_INDEX_PATH;
-
 /**
  * Registry for repositories. This is the central entry point for repositories. It provides methods for
  * retrieving, adding and removing repositories.
@@ -78,6 +76,7 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
 {
 
     private static final Logger log = LoggerFactory.getLogger(RepositoryRegistry.class);
+    private final ConfigurationHandler configurationHandler;
 
     /**
      * We inject all repository providers
@@ -88,9 +87,6 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
     @Inject
     IndexManagerFactory indexManagerFactory;
 
-    @Inject
-    ArchivaConfiguration archivaConfiguration;
-
     @Inject
     List<MetadataReader> metadataReaderList;
 
@@ -98,6 +94,8 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
     @Named("repositoryContentFactory#default")
     RepositoryContentFactory repositoryContentFactory;
 
+
+
     private final EventManager eventManager;
 
 
@@ -107,20 +105,23 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
     private Map<String, RemoteRepository> remoteRepositories = new HashMap<>();
     private Map<String, RemoteRepository> uRemoteRepositories = Collections.unmodifiableMap(remoteRepositories);
 
-    private Map<String, RepositoryGroup> repositoryGroups = new HashMap<>();
-    private Map<String, RepositoryGroup> uRepositoryGroups = Collections.unmodifiableMap(repositoryGroups);
-
     private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
 
-    private volatile boolean ignoreConfigEvents = false;
+    private RepositoryGroupHandler groupHandler;
 
-    public ArchivaRepositoryRegistry() {
+    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) {
         this.eventManager = new EventManager(this);
+        this.configurationHandler = configurationHandler;
     }
 
     @Override
     public void setArchivaConfiguration( ArchivaConfiguration archivaConfiguration ) {
-        this.archivaConfiguration = archivaConfiguration;
+        this.configurationHandler.setArchivaConfiguration( archivaConfiguration );
     }
 
     @PostConstruct
@@ -128,21 +129,41 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
         rwLock.writeLock().lock();
         try {
             log.debug("Initializing repository registry");
-            updateManagedRepositoriesFromConfig();
-            updateRemoteRepositoriesFromConfig();
-
-            repositoryGroups.clear();
-            Map<String, RepositoryGroup> repositoryGroups = getRepositorGroupsFromConfig();
-            this.repositoryGroups.putAll(repositoryGroups);
-
-            // archivaConfiguration.addChangeListener(this);
-            archivaConfiguration.addListener(this);
+            updateManagedRepositoriesFromConfig( );
+            pushEvent( new RepositoryRegistryEvent( RepositoryRegistryEvent.MANAGED_REPOS_INITIALIZED, this ) );
+            managed_initialized.set( true );
+            updateRemoteRepositoriesFromConfig( );
+            pushEvent( new RepositoryRegistryEvent( RepositoryRegistryEvent.REMOTE_REPOS_INITIALIZED, this ) );
+            remote_initialized.set( true );
+
+            initializeRepositoryGroups();
+            this.configurationHandler.addListener(this);
         } finally {
             rwLock.writeLock().unlock();
         }
         pushEvent(new RepositoryRegistryEvent(RepositoryRegistryEvent.RELOADED, this));
+        if (managed_initialized.get() && remote_initialized.get() && groups_initalized.get( )) {
+            pushEvent( new RepositoryRegistryEvent( RepositoryRegistryEvent.INITIALIZED, this ) );
+        }
     }
 
+    private void initializeRepositoryGroups() {
+        if (this.groupHandler!=null) {
+            this.groupHandler.initializeFromConfig();
+            this.groups_initalized.set( true );
+            pushEvent( new RepositoryRegistryEvent( RepositoryRegistryEvent.GROUPS_INITIALIZED, this ) );
+        }
+    }
+
+    public void registerGroupHandler(RepositoryGroupHandler groupHandler) {
+        this.groupHandler = groupHandler;
+        initializeRepositoryGroups();
+        if (managed_initialized.get() && remote_initialized.get() && groups_initalized.get( )) {
+            pushEvent( new RepositoryRegistryEvent( RepositoryRegistryEvent.INITIALIZED, this ) );
+        }
+    }
+
+
     @PreDestroy
     public void destroy() {
         for (ManagedRepository rep : managedRepositories.values()) {
@@ -153,11 +174,12 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
             repo.close();
         }
         remoteRepositories.clear();
+        groupHandler.close();
         pushEvent(new RepositoryRegistryEvent(RepositoryRegistryEvent.DESTROYED, this));
     }
 
 
-    private Map<RepositoryType, RepositoryProvider> createProviderMap() {
+    protected Map<RepositoryType, RepositoryProvider> getRepositoryProviderMap() {
         Map<RepositoryType, RepositoryProvider> map = new HashMap<>();
         if (repositoryProviders != null) {
             for (RepositoryProvider provider : repositoryProviders) {
@@ -169,7 +191,7 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
         return map;
     }
 
-    private RepositoryProvider getProvider(RepositoryType type) throws RepositoryException
+    protected RepositoryProvider getProvider(RepositoryType type) throws RepositoryException
     {
         return repositoryProviders.stream().filter(repositoryProvider -> repositoryProvider.provides().contains(type)).findFirst().orElseThrow(() -> new RepositoryException("Repository type cannot be handled: " + type));
     }
@@ -182,7 +204,7 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
 
             Set<String> configRepoIds = new HashSet<>();
             List<ManagedRepositoryConfiguration> managedRepoConfigs =
-                    getArchivaConfiguration().getConfiguration().getManagedRepositories();
+                    configurationHandler.getBaseConfiguration().getManagedRepositories();
 
             if (managedRepoConfigs == null) {
                 return;
@@ -299,7 +321,7 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
     private void updateRemoteRepositoriesFromConfig() {
         try {
             List<RemoteRepositoryConfiguration> remoteRepoConfigs =
-                    getArchivaConfiguration().getConfiguration().getRemoteRepositories();
+                    configurationHandler.getBaseConfiguration().getRemoteRepositories();
 
             if (remoteRepoConfigs == null) {
                 return;
@@ -341,53 +363,8 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
         repo.registerEventHandler(RepositoryEvent.ANY, this);
     }
 
-    private Map<String, RepositoryGroup> getRepositorGroupsFromConfig() {
-        try {
-            List<RepositoryGroupConfiguration> repositoryGroupConfigurations =
-                    getArchivaConfiguration().getConfiguration().getRepositoryGroups();
-
-            if (repositoryGroupConfigurations == null) {
-                return Collections.emptyMap();
-            }
-
-            Map<String, RepositoryGroup> repositoryGroupMap = new LinkedHashMap<>(repositoryGroupConfigurations.size());
-
-            Map<RepositoryType, RepositoryProvider> providerMap = createProviderMap();
-            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();
-        }
-    }
-
-    private RepositoryGroup createNewRepositoryGroup(RepositoryProvider provider, RepositoryGroupConfiguration config) throws RepositoryException {
-        RepositoryGroup repositoryGroup = provider.createRepositoryGroup(config);
-        repositoryGroup.registerEventHandler(RepositoryEvent.ANY, this);
-        updateRepositoryReferences(provider, repositoryGroup, config);
-        return repositoryGroup;
-    }
 
-    private void updateRepositoryReferences(RepositoryProvider provider, RepositoryGroup group, RepositoryGroupConfiguration configuration) {
-        if (group instanceof EditableRepositoryGroup ) {
-            EditableRepositoryGroup eGroup = (EditableRepositoryGroup) group;
-            eGroup.setRepositories(configuration.getRepositories().stream().map(r -> getManagedRepository(r)).collect(Collectors.toList()));
-        }
-    }
 
-    private ArchivaConfiguration getArchivaConfiguration() {
-        return this.archivaConfiguration;
-    }
 
     /**
      * Returns all repositories that are registered. There is no defined order of the returned repositories.
@@ -438,7 +415,7 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
     public Collection<RepositoryGroup> getRepositoryGroups( ) {
         rwLock.readLock().lock();
         try {
-            return uRepositoryGroups.values();
+            return groupHandler.getRepositoryGroups( );
         } finally {
             rwLock.readLock().unlock();
         }
@@ -462,8 +439,8 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
             } else if (remoteRepositories.containsKey(repoId)) {
                 log.debug("Remote repo");
                 return remoteRepositories.get(repoId);
-            } else if (repositoryGroups.containsKey(repoId)) {
-                return repositoryGroups.get(repoId);
+            } else if (groupHandler.hasRepositoryGroup(repoId)) {
+                return groupHandler.getRepositoryGroup(repoId);
             } else {
                 return null;
             }
@@ -510,23 +487,14 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
     public RepositoryGroup getRepositoryGroup( String groupId ) {
         rwLock.readLock().lock();
         try {
-            return repositoryGroups.get(groupId);
+            return groupHandler.getRepositoryGroup(groupId);
         } finally {
             rwLock.readLock().unlock();
         }
     }
 
-    /*
-     * The <code>ignoreConfigEvents</code> works only for synchronized configuration events.
-     * If the configuration throws async events, we cannot know, if the event is caused by this instance or another thread.
-     */
-    private void saveConfiguration(Configuration configuration) throws IndeterminateConfigurationException, RegistryException {
-        ignoreConfigEvents = true;
-        try {
-            getArchivaConfiguration().save(configuration);
-        } finally {
-            ignoreConfigEvents = false;
-        }
+    protected void saveConfiguration(Configuration configuration) throws IndeterminateConfigurationException, RegistryException {
+        configurationHandler.save(configuration, ConfigurationHandler.REGISTRY_EVENT_TAG );
     }
 
     /**
@@ -552,7 +520,7 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
                 }
                 RepositoryProvider provider = getProvider(managedRepository.getType());
                 ManagedRepositoryConfiguration newCfg = provider.getManagedConfiguration(managedRepository);
-                Configuration configuration = getArchivaConfiguration().getConfiguration();
+                Configuration configuration = configurationHandler.getBaseConfiguration();
                 updateRepositoryReferences(provider, managedRepository, newCfg, configuration);
                 ManagedRepositoryConfiguration oldCfg = configuration.findManagedRepositoryById(id);
                 if (oldCfg != null) {
@@ -595,7 +563,7 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
         try {
             final String id = managedRepositoryConfiguration.getId();
             final RepositoryType repositoryType = RepositoryType.valueOf(managedRepositoryConfiguration.getType());
-            Configuration configuration = getArchivaConfiguration().getConfiguration();
+            Configuration configuration = configurationHandler.getBaseConfiguration();
             ManagedRepository repo = managedRepositories.get(id);
             ManagedRepositoryConfiguration oldCfg = repo != null ? getProvider(repositoryType).getManagedConfiguration(repo) : null;
             repo = putRepository(managedRepositoryConfiguration, configuration);
@@ -670,33 +638,10 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
     public RepositoryGroup putRepositoryGroup( RepositoryGroup repositoryGroup ) throws RepositoryException {
         rwLock.writeLock().lock();
         try {
-            final String id = repositoryGroup.getId();
-            RepositoryGroup originRepoGroup = repositoryGroups.put(id, repositoryGroup);
-            try {
-                if (originRepoGroup != null && originRepoGroup != repositoryGroup) {
-                    originRepoGroup.close();
-                }
-                RepositoryProvider provider = getProvider(repositoryGroup.getType());
-                RepositoryGroupConfiguration newCfg = provider.getRepositoryGroupConfiguration(repositoryGroup);
-                Configuration configuration = getArchivaConfiguration().getConfiguration();
-                updateRepositoryReferences(provider, repositoryGroup, newCfg);
-                RepositoryGroupConfiguration oldCfg = configuration.findRepositoryGroupById(id);
-                if (oldCfg != null) {
-                    configuration.removeRepositoryGroup(oldCfg);
-                }
-                configuration.addRepositoryGroup(newCfg);
-                saveConfiguration(configuration);
-                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()));
+            if (this.groupHandler==null) {
+                throw new RepositoryException( "Fatal error. RepositoryGroupHandler not registered!" );
             }
+            return this.groupHandler.putRepositoryGroup( repositoryGroup );
         } finally {
             rwLock.writeLock().unlock();
         }
@@ -714,22 +659,7 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
     public RepositoryGroup putRepositoryGroup( RepositoryGroupConfiguration repositoryGroupConfiguration ) throws RepositoryException {
         rwLock.writeLock().lock();
         try {
-            final String id = repositoryGroupConfiguration.getId();
-            final RepositoryType repositoryType = RepositoryType.valueOf(repositoryGroupConfiguration.getType());
-            Configuration configuration = getArchivaConfiguration().getConfiguration();
-            RepositoryGroup repo = repositoryGroups.get(id);
-            RepositoryGroupConfiguration oldCfg = repo != null ? getProvider(repositoryType).getRepositoryGroupConfiguration(repo) : null;
-            repo = putRepositoryGroup(repositoryGroupConfiguration, configuration);
-            try {
-                saveConfiguration(configuration);
-            } catch (IndeterminateConfigurationException | RegistryException e) {
-                if (oldCfg != null) {
-                    getProvider(repositoryType).updateRepositoryGroupInstance((EditableRepositoryGroup) repo, oldCfg);
-                }
-                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());
-            }
-            return repo;
+            return groupHandler.putRepositoryGroup( repositoryGroupConfiguration );
         } finally {
             rwLock.writeLock().unlock();
         }
@@ -749,41 +679,12 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
     public RepositoryGroup putRepositoryGroup( RepositoryGroupConfiguration repositoryGroupConfiguration, Configuration configuration ) throws RepositoryException {
         rwLock.writeLock().lock();
         try {
-            final String id = repositoryGroupConfiguration.getId();
-            final RepositoryType repoType = RepositoryType.valueOf(repositoryGroupConfiguration.getType());
-            RepositoryGroup repo;
-            setRepositoryGroupDefaults(repositoryGroupConfiguration);
-            if (repositoryGroups.containsKey(id)) {
-                repo = repositoryGroups.get(id);
-                if (repo instanceof EditableRepositoryGroup) {
-                    getProvider(repoType).updateRepositoryGroupInstance((EditableRepositoryGroup) repo, repositoryGroupConfiguration);
-                } else {
-                    throw new RepositoryException("The repository is not editable " + id);
-                }
-            } else {
-                repo = getProvider(repoType).createRepositoryGroup(repositoryGroupConfiguration);
-                repositoryGroups.put(id, repo);
-            }
-            updateRepositoryReferences(getProvider(repoType), repo, repositoryGroupConfiguration);
-            replaceOrAddRepositoryConfig(repositoryGroupConfiguration, configuration);
-            return repo;
+            return groupHandler.putRepositoryGroup( repositoryGroupConfiguration, configuration );
         } finally {
             rwLock.writeLock().unlock();
         }
     }
 
-    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");
-        }
-    }
-
     private void replaceOrAddRepositoryConfig(ManagedRepositoryConfiguration managedRepositoryConfiguration, Configuration configuration) {
         if (configuration != null) {
             ManagedRepositoryConfiguration oldCfg = configuration.findManagedRepositoryById(managedRepositoryConfiguration.getId());
@@ -874,7 +775,7 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
     public RemoteRepository putRepository( RemoteRepository remoteRepository ) throws RepositoryException {
         rwLock.writeLock().lock();
         try {
-            Configuration configuration = getArchivaConfiguration().getConfiguration();
+            Configuration configuration = configurationHandler.getBaseConfiguration();
             try {
                 RemoteRepository repo = putRepository(remoteRepository, configuration);
                 saveConfiguration(configuration);
@@ -902,7 +803,7 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
         try {
             final String id = remoteRepositoryConfiguration.getId();
             final RepositoryType repositoryType = RepositoryType.valueOf(remoteRepositoryConfiguration.getType());
-            Configuration configuration = getArchivaConfiguration().getConfiguration();
+            Configuration configuration = configurationHandler.getBaseConfiguration();
             RemoteRepository repo = remoteRepositories.get(id);
             RemoteRepositoryConfiguration oldCfg = repo != null ? getProvider(repositoryType).getRemoteConfiguration(repo) : null;
             repo = putRepository(remoteRepositoryConfiguration, configuration);
@@ -1012,8 +913,8 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
                 repo = managedRepositories.remove(id);
                 if (repo != null) {
                     repo.close();
-                    removeRepositoryFromGroups(repo);
-                    Configuration configuration = getArchivaConfiguration().getConfiguration();
+                    this.groupHandler.removeRepositoryFromGroups(repo);
+                    Configuration configuration = configurationHandler.getBaseConfiguration();
                     ManagedRepositoryConfiguration cfg = configuration.findManagedRepositoryById(id);
                     if (cfg != null) {
                         configuration.removeManagedRepository(cfg);
@@ -1032,12 +933,6 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
         }
     }
 
-    private void removeRepositoryFromGroups(ManagedRepository repo) {
-        if (repo != null) {
-            repositoryGroups.values().stream().filter(repoGroup -> repoGroup instanceof EditableRepository).
-                    map(repoGroup -> (EditableRepositoryGroup) repoGroup).forEach(repoGroup -> repoGroup.removeRepository(repo));
-        }
-    }
 
     @Override
     public void removeRepository( ManagedRepository managedRepository, Configuration configuration ) throws RepositoryException {
@@ -1052,7 +947,7 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
                 repo = managedRepositories.remove(id);
                 if (repo != null) {
                     repo.close();
-                    removeRepositoryFromGroups(repo);
+                    this.groupHandler.removeRepositoryFromGroups(repo);
                     ManagedRepositoryConfiguration cfg = configuration.findManagedRepositoryById(id);
                     if (cfg != null) {
                         configuration.removeManagedRepository(cfg);
@@ -1080,26 +975,10 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
             return;
         }
         final String id = repositoryGroup.getId();
-        RepositoryGroup repo = getRepositoryGroup(id);
-        if (repo != null) {
+        if (groupHandler.hasRepositoryGroup( id )) {
             rwLock.writeLock().lock();
             try {
-                repo = repositoryGroups.remove(id);
-                if (repo != null) {
-                    repo.close();
-                    Configuration configuration = getArchivaConfiguration().getConfiguration();
-                    RepositoryGroupConfiguration cfg = configuration.findRepositoryGroupById(id);
-                    if (cfg != null) {
-                        configuration.removeRepositoryGroup(cfg);
-                    }
-                    saveConfiguration(configuration);
-                }
-
-            } 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());
+            groupHandler.removeRepositoryGroup( id );
             } finally {
                 rwLock.writeLock().unlock();
             }
@@ -1112,23 +991,14 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
             return;
         }
         final String id = repositoryGroup.getId();
-        RepositoryGroup repo = getRepositoryGroup(id);
-        if (repo != null) {
+        if (groupHandler.hasRepositoryGroup( id )) {
             rwLock.writeLock().lock();
             try {
-                repo = repositoryGroups.remove(id);
-                if (repo != null) {
-                    repo.close();
-                    RepositoryGroupConfiguration cfg = configuration.findRepositoryGroupById(id);
-                    if (cfg != null) {
-                        configuration.removeRepositoryGroup(cfg);
-                    }
-                }
+                groupHandler.removeRepositoryGroup( id, configuration );
             } finally {
                 rwLock.writeLock().unlock();
             }
         }
-
     }
 
     private void doRemoveRepo(RemoteRepository repo, Configuration configuration) {
@@ -1164,7 +1034,7 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
             try {
                 repo = remoteRepositories.remove(id);
                 if (repo != null) {
-                    Configuration configuration = getArchivaConfiguration().getConfiguration();
+                    Configuration configuration = configurationHandler.getBaseConfiguration();
                     doRemoveRepo(repo, configuration);
                     saveConfiguration(configuration);
                 }
@@ -1292,8 +1162,9 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
 
     @Override
     public void configurationEvent(ConfigurationEvent event) {
-        // Note: the ignoreConfigEvents flag does not work, if the config events are asynchronous.
-        if (!ignoreConfigEvents) {
+        // We ignore the event, if the save was triggered by ourself
+        if ( !ConfigurationHandler.REGISTRY_EVENT_TAG.equals( event.getTag( ) ) )
+        {
             reload();
         }
     }
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
new file mode 100644 (file)
index 0000000..c4ee513
--- /dev/null
@@ -0,0 +1,71 @@
+package org.apache.archiva.repository.base;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.archiva.components.registry.RegistryException;
+import org.apache.archiva.configuration.ArchivaConfiguration;
+import org.apache.archiva.configuration.Configuration;
+import org.apache.archiva.configuration.ConfigurationListener;
+import org.apache.archiva.configuration.IndeterminateConfigurationException;
+import org.springframework.stereotype.Service;
+
+/**
+ * This is just a simple wrapper to access the archiva configuration used by the registry and associated classes
+ *
+ * @author Martin Stockhammer <martin_s@apache.org>
+ */
+@Service("configurationHandler#default")
+public class ConfigurationHandler
+{
+    public static final String REGISTRY_EVENT_TAG = "repositoryRegistry";
+
+    private ArchivaConfiguration archivaConfiguration;
+
+    public ConfigurationHandler( ArchivaConfiguration archivaConfiguration ) {
+        this.archivaConfiguration = archivaConfiguration;
+    }
+
+    public void addListener( ConfigurationListener listener ) {
+        this.archivaConfiguration.addListener( listener );
+    }
+
+    public ArchivaConfiguration getArchivaConfiguration( )
+    {
+        return archivaConfiguration;
+    }
+
+    public void setArchivaConfiguration( ArchivaConfiguration archivaConfiguration )
+    {
+        this.archivaConfiguration = archivaConfiguration;
+    }
+
+    public Configuration getBaseConfiguration() {
+        return archivaConfiguration.getConfiguration( );
+    }
+
+    public void save(Configuration configuration, String eventTag) throws IndeterminateConfigurationException, RegistryException
+    {
+        archivaConfiguration.save( configuration, eventTag);
+    }
+
+    public void save(Configuration configuration) throws IndeterminateConfigurationException, RegistryException
+    {
+        archivaConfiguration.save( configuration, "" );
+    }
+
+}
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
new file mode 100644 (file)
index 0000000..f4b02a2
--- /dev/null
@@ -0,0 +1,328 @@
+package org.apache.archiva.repository.base;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.archiva.components.registry.RegistryException;
+import org.apache.archiva.configuration.Configuration;
+import org.apache.archiva.configuration.IndeterminateConfigurationException;
+import org.apache.archiva.configuration.RepositoryGroupConfiguration;
+import org.apache.archiva.indexer.merger.MergedRemoteIndexesScheduler;
+import org.apache.archiva.repository.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.RepositoryProvider;
+import org.apache.archiva.repository.RepositoryType;
+import org.apache.archiva.repository.event.RepositoryEvent;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.inject.Named;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import static org.apache.archiva.indexer.ArchivaIndexManager.DEFAULT_INDEX_PATH;
+
+/**
+ * This class manages repository groups for the RepositoryRegistry.
+ * It is tightly coupled with the {@link ArchivaRepositoryRegistry}.
+ *
+ * @author Martin Stockhammer <martin_s@apache.org>
+ */
+@Service("repositoryGroupHandler#default")
+public class RepositoryGroupHandler
+{
+    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<>();
+
+    /**
+     * 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 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) {
+        this.configurationHandler = configurationHandler;
+        this.mergedRemoteIndexesScheduler = mergedRemoteIndexesScheduler;
+        this.repositoryRegistry = repositoryRegistry;
+    }
+
+    @PostConstruct
+    private void init() {
+        log.debug( "Initializing repository group handler " + repositoryRegistry.toString( ) );
+        // We are registering this class on the registry. This is necessary to avoid circular dependencies via injection.
+        this.repositoryRegistry.registerGroupHandler( this );
+    }
+
+    public void initializeFromConfig() {
+        this.repositoryGroups.clear();
+        this.repositoryGroups.putAll( getRepositorGroupsFromConfig( ) );
+    }
+
+    public Map<String, RepositoryGroup> getRepositorGroupsFromConfig() {
+        try {
+            List<RepositoryGroupConfiguration> repositoryGroupConfigurations =
+                this.configurationHandler.getBaseConfiguration().getRepositoryGroups();
+
+            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);
+                    }
+                }
+            }
+            return repositoryGroupMap;
+        } 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
+    {
+        RepositoryGroup repositoryGroup = provider.createRepositoryGroup(config);
+        repositoryGroup.registerEventHandler( RepositoryEvent.ANY, repositoryRegistry);
+        updateRepositoryReferences(provider, repositoryGroup, config);
+        return repositoryGroup;
+    }
+
+    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()));
+        }
+    }
+
+    /**
+     * Adds a new repository group to the current list, or replaces the repository group definition with
+     * the same id, if it exists already.
+     * The change is saved to the configuration immediately.
+     *
+     * @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) {
+                    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);
+                }
+                configuration.addRepositoryGroup(newCfg);
+                repositoryRegistry.saveConfiguration(configuration);
+                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()));
+            }
+    }
+
+    /**
+     * Adds a new repository group or updates the repository with the same id, if it exists already.
+     * The configuration is saved immediately.
+     *
+     * @param repositoryGroupConfiguration the repository configuration
+     * @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 repo = repositoryGroups.get(id);
+            RepositoryGroupConfiguration oldCfg = repo != null ? repositoryRegistry.getProvider(repositoryType).getRepositoryGroupConfiguration(repo) : null;
+            repo = putRepositoryGroup(repositoryGroupConfiguration, configuration);
+            try {
+                repositoryRegistry.saveConfiguration(configuration);
+            } catch ( IndeterminateConfigurationException | RegistryException e) {
+                if (oldCfg != null) {
+                    repositoryRegistry.getProvider(repositoryType).updateRepositoryGroupInstance((EditableRepositoryGroup) repo, oldCfg);
+                }
+                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());
+            }
+            return repo;
+    }
+
+    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);
+                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);
+            }
+            updateRepositoryReferences(repositoryRegistry.getProvider(repoType), repo, repositoryGroupConfiguration);
+            replaceOrAddRepositoryConfig(repositoryGroupConfiguration, configuration);
+            return repo;
+    }
+
+    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");
+        }
+    }
+
+    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));
+        }
+    }
+
+    /**
+     * Removes a repository group from the registry and configuration, if it exists.
+     * The change is saved to the configuration immediately.
+     *
+     * @param id the id of the repository group to remove
+     * @throws RepositoryException if 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) {
+                    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 );
+                }
+
+            } 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());
+            }
+        }
+    }
+
+    public void removeRepositoryGroup( String id, Configuration configuration ) throws RepositoryException {
+        RepositoryGroup repo = repositoryGroups.get(id);
+        if (repo != null) {
+                repo = repositoryGroups.remove(id);
+                if (repo != null) {
+                    repo.close();
+                    RepositoryGroupConfiguration cfg = configuration.findRepositoryGroupById(id);
+                    if (cfg != null) {
+                        configuration.removeRepositoryGroup(cfg);
+                    }
+                }
+        }
+
+    }
+
+    public RepositoryGroup getRepositoryGroup( String groupId ) {
+        return repositoryGroups.get(groupId);
+    }
+
+    public Collection<RepositoryGroup> getRepositoryGroups() {
+        return repositoryGroups.values( );
+    }
+
+    public boolean hasRepositoryGroup(String id) {
+        return repositoryGroups.containsKey( id );
+    }
+
+    @PreDestroy
+    private void destroy() {
+        this.close( );
+    }
+
+    public void close() {
+        for (RepositoryGroup group : repositoryGroups.values()) {
+            try
+            {
+                group.close( );
+            } catch (Throwable e) {
+                log.error( "Could not close repository group {}: {}", group.getId( ), e.getMessage( ) );
+            }
+        }
+        this.repositoryGroups.clear();
+    }
+
+}
index 58965ed18944a79cc0026cb1ca70cea34f4771a7..b7cbf1fb572de3050ac6be4a7fa85fe1eb5860d2 100644 (file)
@@ -66,6 +66,10 @@ public class ArchivaRepositoryRegistryTest
     @Inject
     ArchivaConfiguration archivaConfiguration;
 
+    @SuppressWarnings( "unused" )
+    @Inject
+    RepositoryGroupHandler repositoryGroupHandler;
+
     private static final Path userCfg = Paths.get(System.getProperty( "user.home" ), ".m2/archiva.xml");
 
     private static Path cfgCopy;
index c025180edb1b4215df9348f80c24a131e2540c6e..e8fc6ce1a0c08e70b95a43ff04033f5d5360ee0f 100644 (file)
@@ -24,6 +24,7 @@ import org.apache.archiva.indexer.ArchivaIndexingContext;
 import org.apache.archiva.indexer.IndexCreationFailedException;
 import org.apache.archiva.repository.base.ArchivaRepositoryRegistry;
 import org.apache.archiva.repository.RepositoryType;
+import org.apache.archiva.repository.base.RepositoryGroupHandler;
 import org.apache.archiva.repository.features.IndexCreationFeature;
 import org.apache.archiva.repository.features.RemoteIndexFeature;
 import org.apache.archiva.repository.maven.MavenManagedRepository;
@@ -61,6 +62,9 @@ public class MavenIndexManagerTest {
     @Inject
     ArchivaRepositoryRegistry repositoryRegistry;
 
+    @Inject
+    RepositoryGroupHandler groupHandler;
+
 
     private Path indexPath;
     private MavenManagedRepository repository;
index b94e6b8e5200f38e47dcb8ea397d802f28b3870d..575d078ad2108e3c1e35ee5c5a8431b6adf501f1 100644 (file)
@@ -31,6 +31,8 @@ import org.apache.archiva.indexer.search.SearchResults;
 import org.apache.archiva.proxy.ProxyRegistry;
 import org.apache.archiva.repository.base.ArchivaRepositoryRegistry;
 import org.apache.archiva.repository.Repository;
+import org.apache.archiva.repository.base.ConfigurationHandler;
+import org.apache.archiva.repository.base.RepositoryGroupHandler;
 import org.apache.archiva.repository.features.IndexCreationFeature;
 import org.apache.archiva.test.utils.ArchivaSpringJUnit4ClassRunner;
 import org.apache.commons.lang3.SystemUtils;
@@ -92,6 +94,9 @@ public abstract class AbstractMavenRepositorySearch
     @Inject
     ArchivaRepositoryRegistry repositoryRegistry;
 
+    @Inject
+    RepositoryGroupHandler repositoryGroupHandler;
+
     @Inject
     ProxyRegistry proxyRegistry;
 
@@ -143,7 +148,7 @@ public abstract class AbstractMavenRepositorySearch
         archivaConfig.addListener( EasyMock.anyObject( ConfigurationListener.class ) );
         EasyMock.expect( archivaConfig.getDefaultLocale() ).andReturn( Locale.getDefault( ) ).anyTimes();
         EasyMock.expect( archivaConfig.getConfiguration() ).andReturn(config).anyTimes();
-        archivaConfig.save(EasyMock.anyObject(Configuration.class));
+        archivaConfig.save(EasyMock.anyObject(Configuration.class), EasyMock.anyString());
         EasyMock.expectLastCall().anyTimes();
         archivaConfigControl.replay();
         repositoryRegistry.reload();
@@ -158,7 +163,7 @@ public abstract class AbstractMavenRepositorySearch
         archivaConfigControl.reset();
         EasyMock.expect( archivaConfig.getDefaultLocale() ).andReturn( Locale.getDefault( ) ).anyTimes();
         EasyMock.expect( archivaConfig.getConfiguration() ).andReturn(config).anyTimes();
-        archivaConfig.save(EasyMock.anyObject(Configuration.class));
+        archivaConfig.save(EasyMock.anyObject(Configuration.class), EasyMock.anyString());
         EasyMock.expectLastCall().anyTimes();
         archivaConfigControl.replay();
         repositoryRegistry.removeRepository(TEST_REPO_1);
@@ -259,7 +264,7 @@ public abstract class AbstractMavenRepositorySearch
         archivaConfigControl.reset();
         archivaConfig.addListener( EasyMock.anyObject( ConfigurationListener.class ) );
         EasyMock.expect( archivaConfig.getConfiguration() ).andReturn(config).anyTimes();
-        archivaConfig.save(EasyMock.anyObject(Configuration.class));
+        archivaConfig.save(EasyMock.anyObject(Configuration.class), EasyMock.anyString());
         EasyMock.expectLastCall().anyTimes();
         archivaConfigControl.replay();
         repositoryRegistry.reload();
index 8fe10eaf7f7f5d9d4e33df1755b1562c37e9fe03..90093edf0f6bb6111d3b6e784ff0aecb0e25b1ef 100644 (file)
@@ -23,6 +23,7 @@ import org.apache.archiva.indexer.search.SearchFields;
 import org.apache.archiva.indexer.search.SearchResultHit;
 import org.apache.archiva.indexer.search.SearchResults;
 import org.apache.archiva.repository.base.ArchivaRepositoryRegistry;
+import org.apache.archiva.repository.base.RepositoryGroupHandler;
 import org.easymock.EasyMock;
 import org.junit.After;
 import org.junit.Test;
@@ -43,6 +44,9 @@ public class MavenRepositorySearchOSGITest
     @Inject
     ArchivaRepositoryRegistry repositoryRegistry;
 
+    @Inject
+    RepositoryGroupHandler repositoryGroupHandler;
+
     @After
     @Override
     public void tearDown() throws Exception {
index 72cc69fc93e2d666db2aeee0428a95e89c356563..f1aa3eb9bd4b9ecac5b05d4556e042b851ad5b71 100644 (file)
@@ -24,6 +24,7 @@ import org.apache.archiva.indexer.search.SearchResultLimits;
 import org.apache.archiva.indexer.search.SearchResults;
 import org.apache.archiva.indexer.util.SearchUtil;
 import org.apache.archiva.repository.base.ArchivaRepositoryRegistry;
+import org.apache.archiva.repository.base.RepositoryGroupHandler;
 import org.apache.archiva.test.utils.ArchivaSpringJUnit4ClassRunner;
 import org.junit.After;
 import org.junit.Test;
@@ -31,6 +32,7 @@ import org.junit.runner.RunWith;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.test.context.ContextConfiguration;
 
+import javax.inject.Inject;
 import java.util.Arrays;
 
 /**
@@ -42,9 +44,12 @@ public class MavenRepositorySearchPaginateTest
     extends TestCase
 {
 
-    @Autowired
+    @Inject
     ArchivaRepositoryRegistry repositoryRegistry;
 
+    @Inject
+    RepositoryGroupHandler repositoryGroupHandler;
+
     @After
     public void endTests() {
         assert repositoryRegistry!=null;
index 7e3d945fa9493124a51b3615a297c9dc2de91368..fb9fe0b8769936c1da93580984015818df329718 100644 (file)
@@ -111,6 +111,12 @@ public class MockConfiguration
         /* do nothing */
     }
 
+    @Override
+    public void save( Configuration configuration, String eventTag ) throws RegistryException, IndeterminateConfigurationException
+    {
+        // do nothing
+    }
+
     public void triggerChange( String name, String value )
     {
         for ( org.apache.archiva.components.registry.RegistryListener listener : registryListeners )
index 018f85eac3e927bda78c571915bb4c35746c01b5..7085e96a4d7b95e1b7bf4d20053543f132862c0a 100644 (file)
@@ -27,6 +27,7 @@ import org.apache.archiva.configuration.ArchivaRuntimeConfiguration;
 import org.apache.archiva.configuration.Configuration;
 import org.apache.archiva.configuration.ConfigurationListener;
 import org.apache.archiva.configuration.FileType;
+import org.apache.archiva.configuration.IndeterminateConfigurationException;
 import org.apache.archiva.configuration.RepositoryScanningConfiguration;
 import org.apache.commons.lang3.StringUtils;
 import org.easymock.IMocksControl;
@@ -109,6 +110,12 @@ public class MockConfiguration
         /* do nothing */
     }
 
+    @Override
+    public void save( Configuration configuration, String eventTag ) throws RegistryException, IndeterminateConfigurationException
+    {
+        // do nothing
+    }
+
     public void triggerChange( String name, String value )
     {
         for(RegistryListener listener: registryListeners)
index 9966d8bb1d3876b3bd6eb3b2f0ae55399ed777de..4ceed3865f8e9b4503561baf179d78ff4240d48d 100644 (file)
@@ -22,6 +22,7 @@ import org.apache.archiva.repository.ManagedRepository;
 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 java.util.Map;
 import java.util.TreeMap;
@@ -31,6 +32,11 @@ public class RepositoryRegistryMock extends ArchivaRepositoryRegistry
 
     private Map<String, ManagedRepository> managedRepositories = new TreeMap<>();
 
+    public RepositoryRegistryMock( ConfigurationHandler configurationHandler )
+    {
+        super( configurationHandler );
+    }
+
     @Override
     public ManagedRepository putRepository(ManagedRepository managedRepository) throws RepositoryException
     {
index 470f24b07c1cea763392a569436fd227190aeb2c..6a34278f69c7cedede24cc65a8124419b68a0a35 100644 (file)
@@ -56,6 +56,12 @@ public class StubConfiguration
         this.configuration = configuration;
     }
 
+    @Override
+    public void save( Configuration configuration, String eventTag ) throws RegistryException, IndeterminateConfigurationException
+    {
+        this.configuration = configuration;
+    }
+
     @Override
     public boolean isDefaulted()
     {
index 9914da9863770dd22d481a26fde97922d3298ef3..78625d7157cb8af22b9fbac7ad064fe944aa9592 100644 (file)
@@ -51,6 +51,12 @@ public class TestConfiguration
         this.configuration = configuration;
     }
 
+    @Override
+    public void save( Configuration configuration, String eventTag ) throws RegistryException, IndeterminateConfigurationException
+    {
+        this.configuration = configuration;
+    }
+
     @Override
     public boolean isDefaulted()
     {
index 450ebd3ef9429895e745392e145b34ea5bfca47a..d778d5c3bb95690aabdfde8887448d3b9dfa39a3 100644 (file)
@@ -26,6 +26,7 @@ import org.apache.archiva.repository.base.ArchivaRepositoryRegistry;
 import org.apache.archiva.repository.base.BasicManagedRepository;
 import org.apache.archiva.repository.ManagedRepository;
 import org.apache.archiva.repository.ReleaseScheme;
+import org.apache.archiva.repository.base.RepositoryGroupHandler;
 import org.apache.archiva.repository.storage.StorageAsset;
 import org.apache.archiva.repository.features.IndexCreationFeature;
 import org.apache.archiva.scheduler.indexing.ArtifactIndexingTask;
@@ -73,6 +74,9 @@ public class ArchivaIndexingTaskExecutorTest
     @Inject
     ArchivaRepositoryRegistry repositoryRegistry;
 
+    @Inject
+    RepositoryGroupHandler repositoryGroupHandler;
+
     @Inject
     private IndexUpdater indexUpdater;
 
index 1a6d39070ec8612a98c8249781953106c842c221..443078efb55293db316957b432aa943141ad72a2 100644 (file)
@@ -29,6 +29,7 @@ import org.apache.archiva.mock.MockRepositorySessionFactory;
 import org.apache.archiva.components.taskqueue.execution.TaskExecutor;
 import org.apache.archiva.repository.ManagedRepository;
 import org.apache.archiva.repository.RepositoryRegistry;
+import org.apache.archiva.repository.base.RepositoryGroupHandler;
 import org.apache.archiva.scheduler.repository.model.RepositoryTask;
 import org.apache.archiva.test.utils.ArchivaSpringJUnit4ClassRunner;
 import org.junit.After;
@@ -65,6 +66,9 @@ public abstract class AbstractArchivaRepositoryScanningTaskExecutorTest
     @Inject
     RepositoryRegistry repositoryRegistry;
 
+    @Inject
+    RepositoryGroupHandler groupHandler;
+
     @Inject
     @Named( value = "taskExecutor#test-repository-scanning" )
     protected TaskExecutor<RepositoryTask> taskExecutor;
diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/MavenManagedRepositoryService.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/MavenManagedRepositoryService.java
deleted file mode 100644 (file)
index 5aff95e..0000000
+++ /dev/null
@@ -1,366 +0,0 @@
-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 io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.Parameter;
-import io.swagger.v3.oas.annotations.headers.Header;
-import io.swagger.v3.oas.annotations.media.Content;
-import io.swagger.v3.oas.annotations.media.Schema;
-import io.swagger.v3.oas.annotations.responses.ApiResponse;
-import io.swagger.v3.oas.annotations.security.OAuthScope;
-import io.swagger.v3.oas.annotations.security.SecurityRequirement;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import org.apache.archiva.components.rest.model.PagedResult;
-import org.apache.archiva.redback.authorization.RedbackAuthorization;
-import org.apache.archiva.rest.api.model.v2.FileInfo;
-import org.apache.archiva.rest.api.model.v2.MavenManagedRepository;
-import org.apache.archiva.rest.api.model.v2.MavenManagedRepositoryUpdate;
-import org.apache.archiva.security.common.ArchivaRoleConstants;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.DefaultValue;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.util.List;
-
-import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
-import static org.apache.archiva.rest.api.services.v2.RestConfiguration.DEFAULT_PAGE_LIMIT;
-
-/**
- * @author Martin Stockhammer <martin_s@apache.org>
- * @since 3.0
- */
-@Schema( name = "ManagedRepositoryService", description = "Managing and configuration of managed repositories" )
-@Path( "repositories/maven/managed" )
-@Tag(name = "v2")
-@Tag(name = "v2/Repositories")
-public interface MavenManagedRepositoryService
-{
-    @Path( "" )
-    @GET
-    @Produces( {APPLICATION_JSON} )
-    @RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
-    @Operation( summary = "Returns all managed repositories.",
-        parameters = {
-            @Parameter( name = "q", description = "Search term" ),
-            @Parameter( name = "offset", description = "The offset of the first element returned" ),
-            @Parameter( name = "limit", description = "Maximum number of items to return in the response" ),
-            @Parameter( name = "orderBy", description = "List of attribute used for sorting (key, value)" ),
-            @Parameter( name = "order", description = "The sort order. Either ascending (asc) or descending (desc)" )
-        },
-        security = {
-            @SecurityRequirement(
-                name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION
-            )
-        },
-        responses = {
-            @ApiResponse( responseCode = "200",
-                description = "If the list could be returned",
-                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = PagedResult.class ) )
-            ),
-            @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to gather the information",
-                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) )
-        }
-    )
-    PagedResult<MavenManagedRepository> getManagedRepositories(
-        @QueryParam( "q" ) @DefaultValue( "" ) String searchTerm,
-        @QueryParam( "offset" ) @DefaultValue( "0" ) Integer offset,
-        @QueryParam( "limit" ) @DefaultValue( value = DEFAULT_PAGE_LIMIT ) Integer limit,
-        @QueryParam( "orderBy" ) @DefaultValue( "id" ) List<String> orderBy,
-        @QueryParam( "order" ) @DefaultValue( "asc" ) String order )
-        throws ArchivaRestServiceException;
-
-
-    @Path( "{id}" )
-    @GET
-    @Produces( {MediaType.APPLICATION_JSON} )
-    @RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
-    @Operation( summary = "Returns the managed repository with the given id.",
-        security = {
-            @SecurityRequirement(
-                name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION
-            )
-        },
-        responses = {
-            @ApiResponse( responseCode = "200",
-                description = "If the managed repository could be returned",
-                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = MavenManagedRepository.class ) )
-            ),
-            @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to gather the information",
-                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
-            @ApiResponse( responseCode = "404", description = "The managed repository with this id does not exist",
-                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) )
-        }
-    )
-    MavenManagedRepository getManagedRepository( @PathParam( "id" ) String repositoryId )
-        throws ArchivaRestServiceException;
-
-
-    @Path( "{id}" )
-    @DELETE
-    @Produces( {MediaType.APPLICATION_JSON} )
-    @RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
-    @Operation( summary = "Deletes the managed repository with the given id.",
-        security = {
-            @SecurityRequirement(
-                name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION
-            )
-        },
-        responses = {
-            @ApiResponse( responseCode = "200",
-                description = "If the managed repository could be returned"
-            ),
-            @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to gather the information",
-                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
-            @ApiResponse( responseCode = "404", description = "The managed repository with this id does not exist",
-                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) )
-        }
-    )
-    Response deleteManagedRepository( @PathParam( "id" ) String repositoryId,
-                                      @QueryParam( "deleteContent" ) boolean deleteContent )
-        throws ArchivaRestServiceException;
-
-
-    @Path( "" )
-    @POST
-    @Consumes( {MediaType.APPLICATION_JSON} )
-    @Produces( {MediaType.APPLICATION_JSON} )
-    @RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
-    @Operation( summary = "Creates the managed repository",
-        security = {
-            @SecurityRequirement(
-                name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION
-            )
-        },
-        responses = {
-            @ApiResponse( responseCode = "201",
-                description = "If the managed repository could be created",
-                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = MavenManagedRepository.class ) )
-            ),
-            @ApiResponse( responseCode = "303", description = "The repository exists already",
-                headers = {
-                    @Header( name = "Location", description = "The URL of existing repository ", schema = @Schema( type = "string" ) )
-                }
-            ),
-            @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to add repositories",
-                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
-            @ApiResponse( responseCode = "422", description = "The body data is not valid",
-                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) )
-        }
-    )
-    MavenManagedRepository addManagedRepository( MavenManagedRepository managedRepository )
-        throws ArchivaRestServiceException;
-
-
-    @Path( "{id}" )
-    @PUT
-    @Consumes( {MediaType.APPLICATION_JSON} )
-    @Produces( {MediaType.APPLICATION_JSON} )
-    @RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
-    @Operation( summary = "Updates the managed repository with the given id",
-        security = {
-            @SecurityRequirement(
-                name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION
-            )
-        },
-        responses = {
-            @ApiResponse( responseCode = "200",
-                description = "If the managed repository could be updated",
-                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = MavenManagedRepository.class ) )
-            ),
-            @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to add repositories",
-                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
-            @ApiResponse( responseCode = "422", description = "The body data is not valid",
-                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
-            @ApiResponse( responseCode = "404", description = "The managed repository with this id does not exist",
-                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) )
-        }
-    )
-    MavenManagedRepository updateManagedRepository( @PathParam( "id" ) String repositoryId,  MavenManagedRepositoryUpdate managedRepository )
-        throws ArchivaRestServiceException;
-
-
-    @Path( "{id}/path/{filePath: .+}" )
-    @GET
-    @Produces( {MediaType.APPLICATION_JSON} )
-    @RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_REPOSITORY_ACCESS, resource = "{id}")
-    @Operation( summary = "Returns the status of a given file in the repository",
-        security = {
-            @SecurityRequirement(
-                name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION
-            )
-        },
-        responses = {
-            @ApiResponse( responseCode = "200",
-                description = "If the file status is returned",
-                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = FileInfo.class ) )
-            ),
-            @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to add repositories",
-                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
-            @ApiResponse( responseCode = "404", description = "The managed repository with this id does not exist. Or the file does not exist.",
-                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) )
-        }
-    )
-    FileInfo getFileStatus( @PathParam( "id" ) String repositoryId, @PathParam( "filePath" ) String fileLocation )
-        throws ArchivaRestServiceException;
-
-
-    /**
-     * Permissions are checked in impl
-     * will copy an artifact from the source repository to the target repository
-     */
-    @Path ("{srcId}/path/{path: .+}/copyto/{dstId}")
-    @POST
-    @Produces({APPLICATION_JSON})
-    @RedbackAuthorization (noPermission = true)
-    @Operation( summary = "Copies a artifact from the source repository to the destination repository",
-        security = {
-            @SecurityRequirement(
-                name = ArchivaRoleConstants.OPERATION_REPOSITORY_ACCESS,
-                scopes = {
-                    "{srcId}"
-                }
-            ),
-            @SecurityRequirement(
-                name= ArchivaRoleConstants.OPERATION_REPOSITORY_UPLOAD,
-                scopes = {
-                    "{dstId}"
-                }
-            )
-
-        },
-        responses = {
-            @ApiResponse( responseCode = "200",
-                description = "If the artifact was copied"
-            ),
-            @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to gather the information",
-                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
-            @ApiResponse( responseCode = "404", description = "The repository does not exist, or if the artifact was not found",
-                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) )
-        }
-    )
-    Response copyArtifact( @PathParam( "srcId" ) String srcRepositoryId, @PathParam( "dstId" ) String dstRepositoryId,
-                           @PathParam( "path" ) String path )
-        throws ArchivaRestServiceException;
-
-
-    @Path ("{id}/path/{path: .+}")
-    @DELETE
-    @Consumes ({ APPLICATION_JSON })
-    @RedbackAuthorization (noPermission = true)
-    @Operation( summary = "Deletes a artifact in the repository.",
-        security = {
-            @SecurityRequirement(
-                name = ArchivaRoleConstants.OPERATION_RUN_INDEXER
-            )
-        },
-        responses = {
-            @ApiResponse( responseCode = "200",
-                description = "If the artifact was deleted"
-            ),
-            @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to gather the information",
-                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
-            @ApiResponse( responseCode = "404", description = "The repository or the artifact does not exist",
-                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) )
-        }
-    )
-    Response deleteArtifact( @PathParam( "id" ) String repositoryId, @PathParam( "path" ) String path )
-        throws ArchivaRestServiceException;
-
-    @Path ( "{id}/co/{group}/{project}/{version}" )
-    @DELETE
-    @Produces ({ MediaType.APPLICATION_JSON })
-    @RedbackAuthorization (noPermission = true)
-    @Operation( summary = "Removes a version tree in the repository",
-        security = {
-            @SecurityRequirement(
-                name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION
-            )
-        },
-        responses = {
-            @ApiResponse( responseCode = "200",
-                description = "If the deletion was successful"
-            ),
-            @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to delete in repositories",
-                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
-            @ApiResponse( responseCode = "404", description = "The managed repository with this id does not exist. Or the version does not exist.",
-                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) )
-        }
-    )
-    Response removeProjectVersion( @PathParam ( "id" ) String repositoryId,
-                                   @PathParam ( "group" ) String namespace, @PathParam ( "project" ) String projectId,
-                                   @PathParam ( "version" ) String version )
-        throws org.apache.archiva.rest.api.services.ArchivaRestServiceException;
-
-
-    @Path ( "{id}/co/{group}/{project}" )
-    @DELETE
-    @Produces ({ MediaType.APPLICATION_JSON })
-    @RedbackAuthorization (noPermission = true)
-    @Operation( summary = "Removes a project tree in the repository",
-        security = {
-            @SecurityRequirement(
-                name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION
-            )
-        },
-        responses = {
-            @ApiResponse( responseCode = "200",
-                description = "If the deletion was successful"
-            ),
-            @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to delete in repositories",
-                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
-            @ApiResponse( responseCode = "404", description = "The managed repository with this id does not exist. Or the project does not exist.",
-                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) )
-        }
-    )
-    Response deleteProject( @PathParam ("id") String repositoryId, @PathParam ( "group" ) String namespace, @PathParam ( "project" ) String projectId )
-        throws org.apache.archiva.rest.api.services.ArchivaRestServiceException;
-
-    @Path ( "{id}/co/{namespace}" )
-    @DELETE
-    @Produces ({ MediaType.APPLICATION_JSON })
-    @RedbackAuthorization (noPermission = true)
-    @Operation( summary = "Removes a namespace tree in the repository",
-        security = {
-            @SecurityRequirement(
-                name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION
-            )
-        },
-        responses = {
-            @ApiResponse( responseCode = "200",
-                description = "If the deletion was successful"
-            ),
-            @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to delete namespaces in repositories",
-                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
-            @ApiResponse( responseCode = "404", description = "The managed repository with this id does not exist. Or the namespace does not exist.",
-                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) )
-        }
-    )
-    Response deleteNamespace( @PathParam ("id") String repositoryId, @PathParam ( "namespace" ) String namespace )
-        throws org.apache.archiva.rest.api.services.ArchivaRestServiceException;
-
-}
index 8a5b6eaeb0d7ce0849998274afa26f743dc8ab0e..a95c68f959d565676c534ef180c579b4c4349bbc 100644 (file)
@@ -55,20 +55,20 @@ import static org.apache.archiva.rest.api.services.v2.RestConfiguration.DEFAULT_
  * @since 3.0
  */
 @Path( "/repository_groups" )
-@Schema( name="RepositoryGroups", description = "Managing of repository groups or virtual repositories")
+@Schema( name = "RepositoryGroups", description = "Managing of repository groups or virtual repositories" )
 public interface RepositoryGroupService
 {
     @Path( "" )
     @GET
-    @Produces( { APPLICATION_JSON } )
+    @Produces( {APPLICATION_JSON} )
     @RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
     @Operation( summary = "Returns all repository group entries.",
         parameters = {
-            @Parameter(name = "q", description = "Search term"),
-            @Parameter(name = "offset", description = "The offset of the first element returned"),
-            @Parameter(name = "limit", description = "Maximum number of items to return in the response"),
-            @Parameter(name = "orderBy", description = "List of attribute used for sorting (key, value)"),
-            @Parameter(name = "order", description = "The sort order. Either ascending (asc) or descending (desc)")
+            @Parameter( name = "q", description = "Search term" ),
+            @Parameter( name = "offset", description = "The offset of the first element returned" ),
+            @Parameter( name = "limit", description = "Maximum number of items to return in the response" ),
+            @Parameter( name = "orderBy", description = "List of attribute used for sorting (key, value)" ),
+            @Parameter( name = "order", description = "The sort order. Either ascending (asc) or descending (desc)" )
         },
         security = {
             @SecurityRequirement(
@@ -78,22 +78,22 @@ public interface RepositoryGroupService
         responses = {
             @ApiResponse( responseCode = "200",
                 description = "If the list could be returned",
-                content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = PagedResult.class))
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = PagedResult.class ) )
             ),
             @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to gather the information",
-                content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) )
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) )
         }
     )
-    PagedResult<RepositoryGroup> getRepositoriesGroups(@QueryParam("q") @DefaultValue( "" ) String searchTerm,
-                                                       @QueryParam( "offset" ) @DefaultValue( "0" ) Integer offset,
-                                                       @QueryParam( "limit" ) @DefaultValue( value = DEFAULT_PAGE_LIMIT ) Integer limit,
-                                                       @QueryParam( "orderBy") @DefaultValue( "id" ) List<String> orderBy,
-                                                       @QueryParam("order") @DefaultValue( "asc" ) String order)
+    PagedResult<RepositoryGroup> getRepositoriesGroups( @QueryParam( "q" ) @DefaultValue( "" ) String searchTerm,
+                                                        @QueryParam( "offset" ) @DefaultValue( "0" ) Integer offset,
+                                                        @QueryParam( "limit" ) @DefaultValue( value = DEFAULT_PAGE_LIMIT ) Integer limit,
+                                                        @QueryParam( "orderBy" ) @DefaultValue( "id" ) List<String> orderBy,
+                                                        @QueryParam( "order" ) @DefaultValue( "asc" ) String order )
         throws ArchivaRestServiceException;
 
     @Path( "{repositoryGroupId}" )
     @GET
-    @Produces( { APPLICATION_JSON } )
+    @Produces( {APPLICATION_JSON} )
     @RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
     @Operation( summary = "Returns a single repository group configuration.",
         security = {
@@ -104,12 +104,12 @@ public interface RepositoryGroupService
         responses = {
             @ApiResponse( responseCode = "200",
                 description = "If the configuration is returned",
-                content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = RepositoryGroup.class))
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = RepositoryGroup.class ) )
             ),
             @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to gather the information",
-                content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) ),
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
             @ApiResponse( responseCode = "404", description = "The repository group with the given id does not exist",
-                content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) )
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) )
         }
     )
     RepositoryGroup getRepositoryGroup( @PathParam( "repositoryGroupId" ) String repositoryGroupId )
@@ -117,14 +117,14 @@ public interface RepositoryGroupService
 
     @Path( "" )
     @POST
-    @Consumes( { APPLICATION_JSON } )
-    @Produces( { APPLICATION_JSON } )
+    @Consumes( {APPLICATION_JSON} )
+    @Produces( {APPLICATION_JSON} )
     @RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
     @Operation( summary = "Creates a new group entry.",
         requestBody =
-            @RequestBody(required = true, description = "The configuration of the repository group.",
-                content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = RepositoryGroup.class))
-            )
+        @RequestBody( required = true, description = "The configuration of the repository group.",
+            content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = RepositoryGroup.class ) )
+        )
         ,
         security = {
             @SecurityRequirement(
@@ -134,17 +134,17 @@ public interface RepositoryGroupService
         responses = {
             @ApiResponse( responseCode = "201",
                 description = "If the list could be returned",
-                content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = RepositoryGroup.class))
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = RepositoryGroup.class ) )
             ),
             @ApiResponse( responseCode = "303", description = "The repository group exists already",
                 headers = {
-                    @Header( name="Location", description = "The URL of existing group", schema = @Schema(type="string"))
+                    @Header( name = "Location", description = "The URL of existing group", schema = @Schema( type = "string" ) )
                 }
             ),
             @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to gather the information",
-                content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) ),
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
             @ApiResponse( responseCode = "422", description = "The body data is not valid",
-                content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) )
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) )
         }
     )
     RepositoryGroup addRepositoryGroup( RepositoryGroup repositoryGroup )
@@ -152,13 +152,13 @@ public interface RepositoryGroupService
 
     @Path( "{repositoryGroupId}" )
     @PUT
-    @Consumes( { APPLICATION_JSON } )
-    @Produces( { APPLICATION_JSON } )
+    @Consumes( {APPLICATION_JSON} )
+    @Produces( {APPLICATION_JSON} )
     @RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
     @Operation( summary = "Returns all repository group entries.",
         requestBody =
-        @RequestBody(required = true, description = "The configuration of the repository group.",
-            content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = RepositoryGroup.class))
+        @RequestBody( required = true, description = "The configuration of the repository group.",
+            content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = RepositoryGroup.class ) )
         )
         ,
         security = {
@@ -169,14 +169,14 @@ public interface RepositoryGroupService
         responses = {
             @ApiResponse( responseCode = "200",
                 description = "If the group is returned",
-                content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = RepositoryGroup.class))
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = RepositoryGroup.class ) )
             ),
             @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to gather the information",
-                content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) ),
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
             @ApiResponse( responseCode = "404", description = "The group with the given id does not exist",
-                content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) ),
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
             @ApiResponse( responseCode = "422", description = "The body data is not valid",
-                content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) )
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) )
         }
     )
     RepositoryGroup updateRepositoryGroup( @PathParam( "repositoryGroupId" ) String groupId, RepositoryGroup repositoryGroup )
@@ -184,7 +184,7 @@ public interface RepositoryGroupService
 
     @Path( "{repositoryGroupId}" )
     @DELETE
-    @Produces( { APPLICATION_JSON } )
+    @Produces( {APPLICATION_JSON} )
     @RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
     @Operation( summary = "Deletes the repository group entry with the given id.",
         security = {
@@ -197,9 +197,9 @@ public interface RepositoryGroupService
                 description = "If the group was deleted"
             ),
             @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to delete the group",
-                content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) ),
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
             @ApiResponse( responseCode = "404", description = "The group with the given id does not exist",
-                content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) ),
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
         }
     )
     Response deleteRepositoryGroup( @PathParam( "repositoryGroupId" ) String repositoryGroupId )
@@ -207,7 +207,7 @@ public interface RepositoryGroupService
 
     @Path( "{repositoryGroupId}/repositories/{repositoryId}" )
     @PUT
-    @Produces( { APPLICATION_JSON } )
+    @Produces( {APPLICATION_JSON} )
     @RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
     @Operation( summary = "Adds the repository with the given id to the repository group.",
         security = {
@@ -220,18 +220,18 @@ public interface RepositoryGroupService
                 description = "If the repository was added or if it was already part of the group"
             ),
             @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to delete the group",
-                content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) ),
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
             @ApiResponse( responseCode = "404", description = "The group with the given id does not exist",
-                content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) ),
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
         }
     )
     RepositoryGroup addRepositoryToGroup( @PathParam( "repositoryGroupId" ) String repositoryGroupId,
-                                  @PathParam( "repositoryId" ) String repositoryId )
+                                          @PathParam( "repositoryId" ) String repositoryId )
         throws ArchivaRestServiceException;
 
     @Path( "{repositoryGroupId}/repositories/{repositoryId}" )
     @DELETE
-    @Produces( { APPLICATION_JSON } )
+    @Produces( {APPLICATION_JSON} )
     @RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
     @Operation( summary = "Removes the repository with the given id from the repository group.",
         security = {
@@ -244,13 +244,13 @@ public interface RepositoryGroupService
                 description = "If the repository was removed."
             ),
             @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to delete the group",
-                content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) ),
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
             @ApiResponse( responseCode = "404", description = "The group with the given id does not exist, or the repository was not part of the group.",
-                content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) ),
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
         }
     )
     RepositoryGroup deleteRepositoryFromGroup( @PathParam( "repositoryGroupId" ) String repositoryGroupId,
-                                       @PathParam( "repositoryId" ) String repositoryId )
+                                               @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/maven/MavenManagedRepositoryService.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/maven/MavenManagedRepositoryService.java
new file mode 100644 (file)
index 0000000..5e63682
--- /dev/null
@@ -0,0 +1,370 @@
+package org.apache.archiva.rest.api.services.v2.maven;
+/*
+ * 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.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.headers.Header;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.security.OAuthScope;
+import io.swagger.v3.oas.annotations.security.SecurityRequirement;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.apache.archiva.components.rest.model.PagedResult;
+import org.apache.archiva.redback.authorization.RedbackAuthorization;
+import org.apache.archiva.rest.api.model.v2.FileInfo;
+import org.apache.archiva.rest.api.model.v2.MavenManagedRepository;
+import org.apache.archiva.rest.api.model.v2.MavenManagedRepositoryUpdate;
+import org.apache.archiva.rest.api.services.v2.ArchivaRestError;
+import org.apache.archiva.rest.api.services.v2.ArchivaRestServiceException;
+import org.apache.archiva.security.common.ArchivaRoleConstants;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.List;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import static org.apache.archiva.rest.api.services.v2.RestConfiguration.DEFAULT_PAGE_LIMIT;
+
+/**
+ * Service interface for managing managed maven repositories
+ *
+ * @author Martin Stockhammer <martin_s@apache.org>
+ * @since 3.0
+ */
+@Schema( name = "ManagedRepositoryService", description = "Managing and configuration of managed repositories" )
+@Path( "repositories/maven/managed" )
+@Tag(name = "v2")
+@Tag(name = "v2/Repositories")
+public interface MavenManagedRepositoryService
+{
+    @Path( "" )
+    @GET
+    @Produces( {APPLICATION_JSON} )
+    @RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
+    @Operation( summary = "Returns all managed repositories.",
+        parameters = {
+            @Parameter( name = "q", description = "Search term" ),
+            @Parameter( name = "offset", description = "The offset of the first element returned" ),
+            @Parameter( name = "limit", description = "Maximum number of items to return in the response" ),
+            @Parameter( name = "orderBy", description = "List of attribute used for sorting (key, value)" ),
+            @Parameter( name = "order", description = "The sort order. Either ascending (asc) or descending (desc)" )
+        },
+        security = {
+            @SecurityRequirement(
+                name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION
+            )
+        },
+        responses = {
+            @ApiResponse( responseCode = "200",
+                description = "If the list could be returned",
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = PagedResult.class ) )
+            ),
+            @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to gather the information",
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) )
+        }
+    )
+    PagedResult<MavenManagedRepository> getManagedRepositories(
+        @QueryParam( "q" ) @DefaultValue( "" ) String searchTerm,
+        @QueryParam( "offset" ) @DefaultValue( "0" ) Integer offset,
+        @QueryParam( "limit" ) @DefaultValue( value = DEFAULT_PAGE_LIMIT ) Integer limit,
+        @QueryParam( "orderBy" ) @DefaultValue( "id" ) List<String> orderBy,
+        @QueryParam( "order" ) @DefaultValue( "asc" ) String order )
+        throws ArchivaRestServiceException;
+
+
+    @Path( "{id}" )
+    @GET
+    @Produces( {MediaType.APPLICATION_JSON} )
+    @RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
+    @Operation( summary = "Returns the managed repository with the given id.",
+        security = {
+            @SecurityRequirement(
+                name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION
+            )
+        },
+        responses = {
+            @ApiResponse( responseCode = "200",
+                description = "If the managed repository could be returned",
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = MavenManagedRepository.class ) )
+            ),
+            @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to gather the information",
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
+            @ApiResponse( responseCode = "404", description = "The managed repository with this id does not exist",
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) )
+        }
+    )
+    MavenManagedRepository getManagedRepository( @PathParam( "id" ) String repositoryId )
+        throws ArchivaRestServiceException;
+
+
+    @Path( "{id}" )
+    @DELETE
+    @Produces( {MediaType.APPLICATION_JSON} )
+    @RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
+    @Operation( summary = "Deletes the managed repository with the given id.",
+        security = {
+            @SecurityRequirement(
+                name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION
+            )
+        },
+        responses = {
+            @ApiResponse( responseCode = "200",
+                description = "If the managed repository could be returned"
+            ),
+            @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to gather the information",
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
+            @ApiResponse( responseCode = "404", description = "The managed repository with this id does not exist",
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) )
+        }
+    )
+    Response deleteManagedRepository( @PathParam( "id" ) String repositoryId,
+                                      @QueryParam( "deleteContent" ) boolean deleteContent )
+        throws ArchivaRestServiceException;
+
+
+    @Path( "" )
+    @POST
+    @Consumes( {MediaType.APPLICATION_JSON} )
+    @Produces( {MediaType.APPLICATION_JSON} )
+    @RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
+    @Operation( summary = "Creates the managed repository",
+        security = {
+            @SecurityRequirement(
+                name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION
+            )
+        },
+        responses = {
+            @ApiResponse( responseCode = "201",
+                description = "If the managed repository could be created",
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = MavenManagedRepository.class ) )
+            ),
+            @ApiResponse( responseCode = "303", description = "The repository exists already",
+                headers = {
+                    @Header( name = "Location", description = "The URL of existing repository ", schema = @Schema( type = "string" ) )
+                }
+            ),
+            @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to add repositories",
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
+            @ApiResponse( responseCode = "422", description = "The body data is not valid",
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) )
+        }
+    )
+    MavenManagedRepository addManagedRepository( MavenManagedRepository managedRepository )
+        throws ArchivaRestServiceException;
+
+
+    @Path( "{id}" )
+    @PUT
+    @Consumes( {MediaType.APPLICATION_JSON} )
+    @Produces( {MediaType.APPLICATION_JSON} )
+    @RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
+    @Operation( summary = "Updates the managed repository with the given id",
+        security = {
+            @SecurityRequirement(
+                name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION
+            )
+        },
+        responses = {
+            @ApiResponse( responseCode = "200",
+                description = "If the managed repository could be updated",
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = MavenManagedRepository.class ) )
+            ),
+            @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to add repositories",
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
+            @ApiResponse( responseCode = "422", description = "The body data is not valid",
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
+            @ApiResponse( responseCode = "404", description = "The managed repository with this id does not exist",
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) )
+        }
+    )
+    MavenManagedRepository updateManagedRepository( @PathParam( "id" ) String repositoryId,  MavenManagedRepositoryUpdate managedRepository )
+        throws ArchivaRestServiceException;
+
+
+    @Path( "{id}/path/{filePath: .+}" )
+    @GET
+    @Produces( {MediaType.APPLICATION_JSON} )
+    @RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_REPOSITORY_ACCESS, resource = "{id}")
+    @Operation( summary = "Returns the status of a given file in the repository",
+        security = {
+            @SecurityRequirement(
+                name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION
+            )
+        },
+        responses = {
+            @ApiResponse( responseCode = "200",
+                description = "If the file status is returned",
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = FileInfo.class ) )
+            ),
+            @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to add repositories",
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
+            @ApiResponse( responseCode = "404", description = "The managed repository with this id does not exist. Or the file does not exist.",
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) )
+        }
+    )
+    FileInfo getFileStatus( @PathParam( "id" ) String repositoryId, @PathParam( "filePath" ) String fileLocation )
+        throws ArchivaRestServiceException;
+
+
+    /**
+     * Permissions are checked in impl
+     * will copy an artifact from the source repository to the target repository
+     */
+    @Path ("{srcId}/path/{path: .+}/copyto/{dstId}")
+    @POST
+    @Produces({APPLICATION_JSON})
+    @RedbackAuthorization (noPermission = true)
+    @Operation( summary = "Copies a artifact from the source repository to the destination repository",
+        security = {
+            @SecurityRequirement(
+                name = ArchivaRoleConstants.OPERATION_REPOSITORY_ACCESS,
+                scopes = {
+                    "{srcId}"
+                }
+            ),
+            @SecurityRequirement(
+                name= ArchivaRoleConstants.OPERATION_REPOSITORY_UPLOAD,
+                scopes = {
+                    "{dstId}"
+                }
+            )
+
+        },
+        responses = {
+            @ApiResponse( responseCode = "200",
+                description = "If the artifact was copied"
+            ),
+            @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to gather the information",
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
+            @ApiResponse( responseCode = "404", description = "The repository does not exist, or if the artifact was not found",
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) )
+        }
+    )
+    Response copyArtifact( @PathParam( "srcId" ) String srcRepositoryId, @PathParam( "dstId" ) String dstRepositoryId,
+                           @PathParam( "path" ) String path )
+        throws ArchivaRestServiceException;
+
+
+    @Path ("{id}/path/{path: .+}")
+    @DELETE
+    @Consumes ({ APPLICATION_JSON })
+    @RedbackAuthorization (noPermission = true)
+    @Operation( summary = "Deletes a artifact in the repository.",
+        security = {
+            @SecurityRequirement(
+                name = ArchivaRoleConstants.OPERATION_RUN_INDEXER
+            )
+        },
+        responses = {
+            @ApiResponse( responseCode = "200",
+                description = "If the artifact was deleted"
+            ),
+            @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to gather the information",
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
+            @ApiResponse( responseCode = "404", description = "The repository or the artifact does not exist",
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) )
+        }
+    )
+    Response deleteArtifact( @PathParam( "id" ) String repositoryId, @PathParam( "path" ) String path )
+        throws ArchivaRestServiceException;
+
+    @Path ( "{id}/co/{group}/{project}/{version}" )
+    @DELETE
+    @Produces ({ MediaType.APPLICATION_JSON })
+    @RedbackAuthorization (noPermission = true)
+    @Operation( summary = "Removes a version tree in the repository",
+        security = {
+            @SecurityRequirement(
+                name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION
+            )
+        },
+        responses = {
+            @ApiResponse( responseCode = "200",
+                description = "If the deletion was successful"
+            ),
+            @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to delete in repositories",
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
+            @ApiResponse( responseCode = "404", description = "The managed repository with this id does not exist. Or the version does not exist.",
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) )
+        }
+    )
+    Response removeProjectVersion( @PathParam ( "id" ) String repositoryId,
+                                   @PathParam ( "group" ) String namespace, @PathParam ( "project" ) String projectId,
+                                   @PathParam ( "version" ) String version )
+        throws org.apache.archiva.rest.api.services.ArchivaRestServiceException;
+
+
+    @Path ( "{id}/co/{group}/{project}" )
+    @DELETE
+    @Produces ({ MediaType.APPLICATION_JSON })
+    @RedbackAuthorization (noPermission = true)
+    @Operation( summary = "Removes a project tree in the repository",
+        security = {
+            @SecurityRequirement(
+                name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION
+            )
+        },
+        responses = {
+            @ApiResponse( responseCode = "200",
+                description = "If the deletion was successful"
+            ),
+            @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to delete in repositories",
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
+            @ApiResponse( responseCode = "404", description = "The managed repository with this id does not exist. Or the project does not exist.",
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) )
+        }
+    )
+    Response deleteProject( @PathParam ("id") String repositoryId, @PathParam ( "group" ) String namespace, @PathParam ( "project" ) String projectId )
+        throws org.apache.archiva.rest.api.services.ArchivaRestServiceException;
+
+    @Path ( "{id}/co/{namespace}" )
+    @DELETE
+    @Produces ({ MediaType.APPLICATION_JSON })
+    @RedbackAuthorization (noPermission = true)
+    @Operation( summary = "Removes a namespace tree in the repository",
+        security = {
+            @SecurityRequirement(
+                name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION
+            )
+        },
+        responses = {
+            @ApiResponse( responseCode = "200",
+                description = "If the deletion was successful"
+            ),
+            @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to delete namespaces in repositories",
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
+            @ApiResponse( responseCode = "404", description = "The managed repository with this id does not exist. Or the namespace does not exist.",
+                content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) )
+        }
+    )
+    Response deleteNamespace( @PathParam ("id") String repositoryId, @PathParam ( "namespace" ) String namespace )
+        throws org.apache.archiva.rest.api.services.ArchivaRestServiceException;
+
+}
index f99b06db7915f718d7bcbf667f829c2cdc443cdf..06c2e4ee65e90acbea94f729b152a4c5fdae9768 100644 (file)
@@ -47,6 +47,7 @@ import org.apache.archiva.redback.system.SecuritySystem;
 import org.apache.archiva.redback.users.User;
 import org.apache.archiva.redback.users.UserManagerException;
 import org.apache.archiva.redback.users.UserNotFoundException;
+import org.apache.archiva.repository.base.RepositoryGroupHandler;
 import org.apache.archiva.repository.content.BaseRepositoryContentLayout;
 import org.apache.archiva.repository.content.ContentNotFoundException;
 import org.apache.archiva.repository.content.LayoutException;
@@ -128,6 +129,10 @@ public class DefaultRepositoriesService
     @Inject
     private RepositoryRegistry repositoryRegistry;
 
+    @SuppressWarnings( "unused" )
+    @Inject
+    private RepositoryGroupHandler repositoryGroupHandler;
+
     @Inject
     private SecuritySystem securitySystem;
 
diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/utils/AuditHelper.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/utils/AuditHelper.java
new file mode 100644 (file)
index 0000000..b6b4aca
--- /dev/null
@@ -0,0 +1,40 @@
+package org.apache.archiva.rest.services.utils;
+/*
+ * 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.admin.model.AuditInformation;
+import org.apache.archiva.redback.rest.services.RedbackAuthenticationThreadLocal;
+import org.apache.archiva.redback.rest.services.RedbackRequestInformation;
+import org.apache.archiva.redback.users.User;
+
+/**
+ * @author Martin Stockhammer <martin_s@apache.org>
+ */
+public class AuditHelper
+{
+    private static final AuditInformation NULL_RESULT = new AuditInformation( null, null );
+    public static AuditInformation getAuditData() {
+        RedbackRequestInformation redbackRequestInformation = RedbackAuthenticationThreadLocal.get( );
+        if (redbackRequestInformation==null) {
+            return NULL_RESULT;
+        } else
+        {
+            return new AuditInformation( redbackRequestInformation.getUser( ), redbackRequestInformation.getRemoteAddr( ) );
+        }
+    }
+}
index 6fd85d5cf47fe42662d956eed0f18e24e772d085..7b776a7f7513f3e51ed6dba4081fe184b33c1003 100644 (file)
@@ -35,35 +35,28 @@ import org.apache.archiva.redback.users.UserNotFoundException;
 import org.apache.archiva.repository.ManagedRepository;
 import org.apache.archiva.repository.ReleaseScheme;
 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.repository.content.ContentItem;
 import org.apache.archiva.repository.content.LayoutException;
-import org.apache.archiva.repository.storage.fs.FilesystemStorage;
 import org.apache.archiva.repository.storage.fs.FsStorageUtil;
-import org.apache.archiva.repository.storage.util.StorageUtil;
-import org.apache.archiva.rest.api.model.v2.Artifact;
 import org.apache.archiva.rest.api.model.v2.FileInfo;
 import org.apache.archiva.rest.api.model.v2.MavenManagedRepository;
 import org.apache.archiva.rest.api.model.v2.MavenManagedRepositoryUpdate;
 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.MavenManagedRepositoryService;
+import org.apache.archiva.rest.api.services.v2.maven.MavenManagedRepositoryService;
 import org.apache.archiva.security.common.ArchivaRoleConstants;
 import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
 
-import javax.inject.Inject;
 import javax.servlet.http.HttpServletResponse;
-import javax.ws.rs.PathParam;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
-import java.io.File;
 import java.io.IOException;
 import java.util.Collection;
 import java.util.Comparator;
@@ -103,7 +96,9 @@ public class DefaultMavenManagedRepositoryService implements MavenManagedReposit
     private RepositoryRegistry repositoryRegistry;
     private SecuritySystem securitySystem;
 
-    public DefaultMavenManagedRepositoryService( SecuritySystem securitySystem, RepositoryRegistry repositoryRegistry, ManagedRepositoryAdmin managedRepositoryAdmin )
+    public DefaultMavenManagedRepositoryService( SecuritySystem securitySystem,
+                                                 RepositoryRegistry repositoryRegistry,
+                                                 ManagedRepositoryAdmin managedRepositoryAdmin )
     {
         this.securitySystem = securitySystem;
         this.repositoryRegistry = repositoryRegistry;
@@ -113,8 +108,16 @@ public class DefaultMavenManagedRepositoryService implements MavenManagedReposit
     protected AuditInformation getAuditInformation( )
     {
         RedbackRequestInformation redbackRequestInformation = RedbackAuthenticationThreadLocal.get( );
-        User user = redbackRequestInformation == null ? null : redbackRequestInformation.getUser( );
-        String remoteAddr = redbackRequestInformation == null ? null : redbackRequestInformation.getRemoteAddr( );
+        User user;
+        String remoteAddr;
+        if (redbackRequestInformation==null) {
+            user = null;
+            remoteAddr = null;
+        } else
+        {
+            user = redbackRequestInformation.getUser( );
+            remoteAddr = redbackRequestInformation.getRemoteAddr( );
+        }
         return new AuditInformation( user, remoteAddr );
     }
 
index 9290873d695b26676d59d1484a3b220534fccb41..44ce638acba36755855d661e2f2f383cba3b6350 100644 (file)
@@ -34,16 +34,12 @@ package org.apache.archiva.rest.services.v2;/*
  * under the License.
  */
 
-import org.apache.archiva.admin.model.AuditInformation;
 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.rest.model.PagedResult;
 import org.apache.archiva.components.rest.util.QueryHelper;
-import org.apache.archiva.redback.rest.services.RedbackAuthenticationThreadLocal;
-import org.apache.archiva.redback.rest.services.RedbackRequestInformation;
-import org.apache.archiva.redback.users.User;
 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;
@@ -54,7 +50,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
 
-import javax.inject.Inject;
 import javax.servlet.http.HttpServletResponse;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.Response;
@@ -65,6 +60,8 @@ 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.
  *
@@ -81,8 +78,7 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
     @Context
     UriInfo uriInfo;
 
-    @Inject
-    private RepositoryGroupAdmin repositoryGroupAdmin;
+    final private RepositoryGroupAdmin repositoryGroupAdmin;
 
     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"} );
@@ -93,12 +89,8 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
     }
 
 
-    protected AuditInformation getAuditInformation( )
-    {
-        RedbackRequestInformation redbackRequestInformation = RedbackAuthenticationThreadLocal.get( );
-        User user = redbackRequestInformation == null ? null : redbackRequestInformation.getUser( );
-        String remoteAddr = redbackRequestInformation == null ? null : redbackRequestInformation.getRemoteAddr( );
-        return new AuditInformation( user, remoteAddr );
+    public DefaultRepositoryGroupService(RepositoryGroupAdmin repositoryGroupAdmin) {
+        this.repositoryGroupAdmin = repositoryGroupAdmin;
     }
 
     @Override
@@ -166,7 +158,7 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
     {
         try
         {
-            Boolean result = repositoryGroupAdmin.addRepositoryGroup( toModel( repositoryGroup ), getAuditInformation( ) );
+            Boolean result = repositoryGroupAdmin.addRepositoryGroup( toModel( repositoryGroup ), getAuditData() );
             if ( result )
             {
                 org.apache.archiva.admin.model.beans.RepositoryGroup newGroup = repositoryGroupAdmin.getRepositoryGroup( repositoryGroup.getId( ) );
@@ -243,7 +235,7 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
             {
                 updateGroup.setMergedIndexTtl( originGroup.getMergedIndexTtl( ) );
             }
-            repositoryGroupAdmin.updateRepositoryGroup( updateGroup, getAuditInformation( ) );
+            repositoryGroupAdmin.updateRepositoryGroup( updateGroup, getAuditData( ) );
             return RepositoryGroup.of( repositoryGroupAdmin.getRepositoryGroup( repositoryGroupId ) );
         }
         catch ( EntityNotFoundException e )
@@ -265,7 +257,7 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
         }
         try
         {
-            Boolean deleted = repositoryGroupAdmin.deleteRepositoryGroup( repositoryGroupId, getAuditInformation( ) );
+            Boolean deleted = repositoryGroupAdmin.deleteRepositoryGroup( repositoryGroupId, getAuditData( ) );
             if ( !deleted )
             {
                 throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_DELETE_FAILED ) );
@@ -297,7 +289,7 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
         }
         try
         {
-            repositoryGroupAdmin.addRepositoryToGroup( repositoryGroupId, repositoryId, getAuditInformation( ) );
+            repositoryGroupAdmin.addRepositoryToGroup( repositoryGroupId, repositoryId, getAuditData( ) );
             return RepositoryGroup.of( repositoryGroupAdmin.getRepositoryGroup( repositoryGroupId ) );
         }
         catch ( EntityNotFoundException e )
@@ -335,7 +327,7 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
         }
         try
         {
-            repositoryGroupAdmin.deleteRepositoryFromGroup( repositoryGroupId, repositoryId, getAuditInformation( ) );
+            repositoryGroupAdmin.deleteRepositoryFromGroup( repositoryGroupId, repositoryId, getAuditData( ) );
             return RepositoryGroup.of( repositoryGroupAdmin.getRepositoryGroup( repositoryGroupId ) );
         }
         catch ( EntityNotFoundException e )
index 53b445abbe4a5855d26e4d821e58e8a28be718aa..46dbc499a45e3cde9399732970ae227dfbf1f37c 100644 (file)
            http://cxf.apache.org/jaxrs
            http://cxf.apache.org/schemas/jaxrs.xsd" default-lazy-init="true">
 
-  <import resource="classpath:META-INF/cxf/cxf.xml"/>
-  <!--
-  <import resource="classpath:META-INF/cxf/cxf-extension-jaxrs-binding.xml"/>
-  -->
-  <import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
+  <import resource="classpath*:META-INF/cxf/cxf.xml"/>
+  <import resource="classpath*:META-INF/cxf/cxf-servlet.xml"/>
 
   <context:annotation-config/>
   <context:component-scan
       <ref bean="v2.defaultSecurityConfigurationService" />
       <ref bean="v2.repositoryGroupService#rest" />
       <ref bean="v2.repositoryService#rest"/>
+      <ref bean="v2.managedMavenRepositoryService#rest"/>
     </jaxrs:serviceBeans>
 
     <jaxrs:features>
index 06d6f742922a9d50479327d02f82f5657bf0650f..18093fa2130c11a6db3e049dd79769eec9b348cc 100644 (file)
@@ -378,7 +378,7 @@ public abstract class AbstractNativeRestServices
         }
         else
         {
-            log.error( "Serer is not in STARTED state!" );
+            log.error( "Server is not in STARTED state!" );
         }
     }
 
@@ -410,15 +410,11 @@ public abstract class AbstractNativeRestServices
         this.requestSpec = getRequestSpecBuilder( ).build( );
         RestAssured.basePath = basePath;
         RestAssured.config = RestAssuredConfig.config().objectMapperConfig(new ObjectMapperConfig().jackson2ObjectMapperFactory(
-            new Jackson2ObjectMapperFactory() {
-                @Override
-                public ObjectMapper create( Type cls, String charset) {
-                    ObjectMapper om = new ObjectMapper().findAndRegisterModules();
-                    om.configure( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
-                    om.setPropertyNamingStrategy( PropertyNamingStrategy.SNAKE_CASE );
-                    return om;
-                }
-
+            ( cls, charset ) -> {
+                ObjectMapper om = new ObjectMapper().findAndRegisterModules();
+                om.configure( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+                om.setPropertyNamingStrategy( PropertyNamingStrategy.SNAKE_CASE );
+                return om;
             }
         ));
     }
diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/test/java/org/apache/archiva/rest/services/v2/NativeMavenManagedRepositoryServiceTest.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/test/java/org/apache/archiva/rest/services/v2/NativeMavenManagedRepositoryServiceTest.java
new file mode 100644 (file)
index 0000000..f7d137f
--- /dev/null
@@ -0,0 +1,97 @@
+package org.apache.archiva.rest.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 io.restassured.path.json.JsonPath;
+import io.restassured.response.Response;
+import io.restassured.response.ResponseBody;
+import org.apache.archiva.components.rest.model.PagedResult;
+import org.apache.archiva.components.rest.model.PropertyEntry;
+import org.apache.archiva.rest.api.model.v2.BeanInformation;
+import org.apache.archiva.rest.api.model.v2.CacheConfiguration;
+import org.apache.archiva.rest.api.model.v2.LdapConfiguration;
+import org.apache.archiva.rest.api.model.v2.MavenManagedRepository;
+import org.apache.archiva.rest.api.services.v2.RestConfiguration;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.TestMethodOrder;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static io.restassured.RestAssured.given;
+import static io.restassured.http.ContentType.JSON;
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * @author Martin Stockhammer <martin_s@apache.org>
+ */
+@TestInstance( TestInstance.Lifecycle.PER_CLASS )
+@Tag( "rest-native" )
+@TestMethodOrder( MethodOrderer.OrderAnnotation.class )
+@DisplayName( "Native REST tests for V2 ManagedRepositoryService" )
+public class NativeMavenManagedRepositoryServiceTest extends AbstractNativeRestServices
+{
+    @Override
+    protected String getServicePath( )
+    {
+        return "/repositories/maven/managed";
+    }
+
+    @BeforeAll
+    void setup( ) throws Exception
+    {
+        super.setupNative( );
+    }
+
+    @AfterAll
+    void destroy( ) throws Exception
+    {
+        super.shutdownNative( );
+    }
+
+    @Test
+    @Order( 1 )
+    void testGetRepositories( )
+    {
+        String token = getAdminToken( );
+        Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON )
+            .when( )
+            .get( "" )
+            .then( ).statusCode( 200 ).extract( ).response( );
+        JsonPath json = response.getBody( ).jsonPath( );
+        assertEquals( 2, json.getInt( "pagination.total_count" ) );
+        assertEquals( 0, json.getInt( "pagination.offset" ) );
+        assertEquals( Integer.valueOf( RestConfiguration.DEFAULT_PAGE_LIMIT ), json.getInt( "pagination.limit" ) );
+        List<MavenManagedRepository> repositories = json.getList( "data", MavenManagedRepository.class );
+        assertEquals( "internal", repositories.get( 0 ).getId( ) );
+        assertEquals( "snapshots", repositories.get( 1 ).getId( ) );
+    }
+
+
+
+}
index bec39deeb55d43c55f7af6fc895e164386e555e1..19eba026f420fff9f18b1d06c24c9c54ed016458 100644 (file)
@@ -32,7 +32,7 @@
 
   <context:annotation-config/>
   <context:component-scan
-      base-package="org.apache.archiva.redback.keys,org.apache.archiva.rest.services.utils,org.apache.archiva.repository.content.maven2"/>
+      base-package="org.apache.archiva.redback.keys,org.apache.archiva.rest.services.utils,org.apache.archiva.repository.maven.content"/>
   
   <bean name="scheduler" class="org.apache.archiva.components.scheduler.DefaultScheduler">
     <property name="properties">
index 56b8445da6190e48a1023c457b2f154fc0564486..e81e0692b0fb3db3f0dc050062c0cd51e1d16293 100644 (file)
@@ -30,6 +30,7 @@ import org.apache.archiva.indexer.ArchivaIndexingContext;
 import org.apache.archiva.repository.base.ArchivaRepositoryRegistry;
 import org.apache.archiva.repository.ManagedRepository;
 import org.apache.archiva.repository.RepositoryType;
+import org.apache.archiva.repository.base.RepositoryGroupHandler;
 import org.apache.archiva.test.utils.ArchivaSpringJUnit4ClassRunner;
 import org.apache.archiva.webdav.httpunit.MkColMethodWebRequest;
 import org.apache.commons.io.FileUtils;
@@ -99,6 +100,9 @@ public abstract class AbstractRepositoryServletTestCase
     @Inject
     protected ApplicationContext applicationContext;
 
+    @SuppressWarnings( "unused" )
+    @Inject
+    RepositoryGroupHandler repositoryGroupHandler;
 
     @Inject
     ArchivaRepositoryRegistry repositoryRegistry;
index 450a3b92eec6ff264b56855f6c4e79a9d511858e..e2b259c5c8e8e45125bfc014c816a6bacbb21860 100644 (file)
@@ -34,6 +34,7 @@ import org.apache.archiva.configuration.FileTypes;
 import org.apache.archiva.configuration.RepositoryGroupConfiguration;
 import org.apache.archiva.metadata.repository.storage.RepositoryPathTranslator;
 import org.apache.archiva.repository.ManagedRepositoryContent;
+import org.apache.archiva.repository.base.RepositoryGroupHandler;
 import org.apache.archiva.repository.maven.content.MavenContentHelper;
 import org.apache.archiva.repository.maven.metadata.storage.ArtifactMappingProvider;
 import org.apache.archiva.proxy.ProxyRegistry;
@@ -158,6 +159,10 @@ public class ArchivaDavResourceFactoryTest
     @Inject
     FileTypes fileTypes;
 
+    @SuppressWarnings( "unused" )
+    @Inject
+    RepositoryGroupHandler repositoryGroupHandler;
+
     public Path getProjectBase() {
         if (this.projectBase.get()==null) {
             String pathVal = System.getProperty("mvn.project.base.dir");
@@ -194,8 +199,9 @@ public class ArchivaDavResourceFactoryTest
         expect (archivaConfiguration.getDefaultLocale()).andReturn( Locale.getDefault() ).anyTimes();
         archivaConfiguration.addListener( EasyMock.anyObject(  ) );
         expectLastCall().times(0, 4);
-        archivaConfiguration.save( config );
-
+        archivaConfiguration.save( eq(config));
+        expectLastCall().times( 0, 5 );
+        archivaConfiguration.save( eq(config), EasyMock.anyString());
         expectLastCall().times( 0, 5 );
         archivaConfigurationControl.replay();
 
index 0385c25e7e52d3eed74a9e3a79b7aca4c80aca6e..b8310c74017c32db00f463dc41c3b5a312571dd1 100644 (file)
@@ -35,6 +35,7 @@ import org.apache.archiva.redback.users.User;
 import org.apache.archiva.redback.users.memory.SimpleUser;
 import org.apache.archiva.repository.RepositoryRegistry;
 import org.apache.archiva.metadata.audit.TestAuditListener;
+import org.apache.archiva.repository.base.RepositoryGroupHandler;
 import org.apache.archiva.security.ServletAuthenticator;
 import org.apache.archiva.security.common.ArchivaRoleConstants;
 import org.apache.archiva.test.utils.ArchivaSpringJUnit4ClassRunner;
@@ -91,6 +92,10 @@ public class RepositoryServletSecurityTest
     @Inject
     protected RepositoryRegistry repositoryRegistry;
 
+    @SuppressWarnings( "unused" )
+    @Inject
+    RepositoryGroupHandler repositoryGroupHandler;
+
     private DavSessionProvider davSessionProvider;
 
     private IMocksControl servletAuthControl;