aboutsummaryrefslogtreecommitdiffstats
path: root/archiva-modules/archiva-base
diff options
context:
space:
mode:
authorMartin Stockhammer <martin_s@apache.org>2021-06-01 22:46:51 +0200
committerMartin Stockhammer <martin_s@apache.org>2021-06-01 22:46:51 +0200
commit0ce53483a85b6b7a3a14417434edf56934b474ba (patch)
tree148acd378bdb456482396cb46c315024840fd807 /archiva-modules/archiva-base
parentca18ec34d706efa6fdc6ecde6277ba6004e8eb4e (diff)
downloadarchiva-0ce53483a85b6b7a3a14417434edf56934b474ba.tar.gz
archiva-0ce53483a85b6b7a3a14417434edf56934b474ba.zip
Centralizing repository group handling. First part.
Diffstat (limited to 'archiva-modules/archiva-base')
-rw-r--r--archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/ArchivaConfiguration.java14
-rw-r--r--archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/ConfigurationEvent.java54
-rw-r--r--archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/DefaultArchivaConfiguration.java23
-rw-r--r--archiva-modules/archiva-base/archiva-consumers/archiva-core-consumers/src/test/java/org/apache/archiva/consumers/core/repository/AbstractRepositoryPurgeTest.java5
-rw-r--r--archiva-modules/archiva-base/archiva-consumers/archiva-core-consumers/src/test/java/org/apache/archiva/consumers/core/repository/CleanupReleasedSnapshotsRepositoryPurgeTest.java2
-rw-r--r--archiva-modules/archiva-base/archiva-consumers/archiva-indexer-consumers/src/test/java/org/apache/archiva/consumers/lucene/NexusIndexerConsumerTest.java4
-rw-r--r--archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/group/DefaultRepositoryGroupAdmin.java20
-rw-r--r--archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/repository/AbstractRepositoryAdminTest.java5
-rw-r--r--archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/repository/group/RepositoryGroupAdminTest.java4
-rw-r--r--archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/event/RepositoryRegistryEvent.java15
-rw-r--r--archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/ArchivaRepositoryRegistry.java275
-rw-r--r--archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/ConfigurationHandler.java71
-rw-r--r--archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/RepositoryGroupHandler.java328
-rw-r--r--archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/base/ArchivaRepositoryRegistryTest.java4
14 files changed, 592 insertions, 232 deletions
diff --git a/archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/ArchivaConfiguration.java b/archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/ArchivaConfiguration.java
index 9d8ead089..f23025702 100644
--- a/archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/ArchivaConfiguration.java
+++ b/archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/ArchivaConfiguration.java
@@ -56,6 +56,20 @@ public interface ArchivaConfiguration
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.
*
* @return true if the configuration was created from the default-archiva.xml as opposed
diff --git a/archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/ConfigurationEvent.java b/archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/ConfigurationEvent.java
index 397c838fa..9639effbe 100644
--- a/archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/ConfigurationEvent.java
+++ b/archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/ConfigurationEvent.java
@@ -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;
}
}
diff --git a/archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/DefaultArchivaConfiguration.java b/archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/DefaultArchivaConfiguration.java
index 11ae70569..ee80fc8fc 100644
--- a/archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/DefaultArchivaConfiguration.java
+++ b/archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/archiva/configuration/DefaultArchivaConfiguration.java
@@ -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);
}
diff --git a/archiva-modules/archiva-base/archiva-consumers/archiva-core-consumers/src/test/java/org/apache/archiva/consumers/core/repository/AbstractRepositoryPurgeTest.java b/archiva-modules/archiva-base/archiva-consumers/archiva-core-consumers/src/test/java/org/apache/archiva/consumers/core/repository/AbstractRepositoryPurgeTest.java
index f1791b7d0..b2f66aa7f 100644
--- a/archiva-modules/archiva-base/archiva-consumers/archiva-core-consumers/src/test/java/org/apache/archiva/consumers/core/repository/AbstractRepositoryPurgeTest.java
+++ b/archiva-modules/archiva-base/archiva-consumers/archiva-core-consumers/src/test/java/org/apache/archiva/consumers/core/repository/AbstractRepositoryPurgeTest.java
@@ -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()
diff --git a/archiva-modules/archiva-base/archiva-consumers/archiva-core-consumers/src/test/java/org/apache/archiva/consumers/core/repository/CleanupReleasedSnapshotsRepositoryPurgeTest.java b/archiva-modules/archiva-base/archiva-consumers/archiva-core-consumers/src/test/java/org/apache/archiva/consumers/core/repository/CleanupReleasedSnapshotsRepositoryPurgeTest.java
index 76b6ce72d..8e497dc2c 100644
--- a/archiva-modules/archiva-base/archiva-consumers/archiva-core-consumers/src/test/java/org/apache/archiva/consumers/core/repository/CleanupReleasedSnapshotsRepositoryPurgeTest.java
+++ b/archiva-modules/archiva-base/archiva-consumers/archiva-core-consumers/src/test/java/org/apache/archiva/consumers/core/repository/CleanupReleasedSnapshotsRepositoryPurgeTest.java
@@ -74,6 +74,8 @@ public class CleanupReleasedSnapshotsRepositoryPurgeTest
@Inject
MetadataTools metadataTools;
+
+
@Before
@Override
public void setUp()
diff --git a/archiva-modules/archiva-base/archiva-consumers/archiva-indexer-consumers/src/test/java/org/apache/archiva/consumers/lucene/NexusIndexerConsumerTest.java b/archiva-modules/archiva-base/archiva-consumers/archiva-indexer-consumers/src/test/java/org/apache/archiva/consumers/lucene/NexusIndexerConsumerTest.java
index 85ee9426d..241eeb09b 100644
--- a/archiva-modules/archiva-base/archiva-consumers/archiva-indexer-consumers/src/test/java/org/apache/archiva/consumers/lucene/NexusIndexerConsumerTest.java
+++ b/archiva-modules/archiva-base/archiva-consumers/archiva-indexer-consumers/src/test/java/org/apache/archiva/consumers/lucene/NexusIndexerConsumerTest.java
@@ -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
diff --git a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/group/DefaultRepositoryGroupAdmin.java b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/group/DefaultRepositoryGroupAdmin.java
index ae6c4fd3b..13f3ce6f9 100644
--- a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/group/DefaultRepositoryGroupAdmin.java
+++ b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/group/DefaultRepositoryGroupAdmin.java
@@ -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();
+ }
+ }
}
diff --git a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/repository/AbstractRepositoryAdminTest.java b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/repository/AbstractRepositoryAdminTest.java
index d3086e2f7..993151a83 100644
--- a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/repository/AbstractRepositoryAdminTest.java
+++ b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/repository/AbstractRepositoryAdminTest.java
@@ -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");
diff --git a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/repository/group/RepositoryGroupAdminTest.java b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/repository/group/RepositoryGroupAdminTest.java
index ed6e28683..49fd38573 100644
--- a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/repository/group/RepositoryGroupAdminTest.java
+++ b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/repository/group/RepositoryGroupAdminTest.java
@@ -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
diff --git a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/event/RepositoryRegistryEvent.java b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/event/RepositoryRegistryEvent.java
index 1e1157959..7f3b62ddc 100644
--- a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/event/RepositoryRegistryEvent.java
+++ b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/event/RepositoryRegistryEvent.java
@@ -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);
}
diff --git a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/ArchivaRepositoryRegistry.java b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/ArchivaRepositoryRegistry.java
index b909e24de..6a3d0e0b3 100644
--- a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/ArchivaRepositoryRegistry.java
+++ b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/ArchivaRepositoryRegistry.java
@@ -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
@@ -89,15 +88,14 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
IndexManagerFactory indexManagerFactory;
@Inject
- ArchivaConfiguration archivaConfiguration;
-
- @Inject
List<MetadataReader> metadataReaderList;
@Inject
@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
index 000000000..c4ee51370
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/ConfigurationHandler.java
@@ -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
index 000000000..f4b02a2d6
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/base/RepositoryGroupHandler.java
@@ -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();
+ }
+
+}
diff --git a/archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/base/ArchivaRepositoryRegistryTest.java b/archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/base/ArchivaRepositoryRegistryTest.java
index 58965ed18..b7cbf1fb5 100644
--- a/archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/base/ArchivaRepositoryRegistryTest.java
+++ b/archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/base/ArchivaRepositoryRegistryTest.java
@@ -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;