This is an automated email from the ASF dual-hosted git repository.

martin_s pushed a commit to branch feature/storage_refactoring
in repository https://gitbox.apache.org/repos/asf/archiva.git

commit f39d6773bddbf33c2a90d6da6daada940ff6f011
Author: Martin Stockhammer <marti...@apache.org>
AuthorDate: Thu Sep 12 13:09:40 2019 +0200

    Enhancing repository events
---
 .../src/test/java/RepositoryProviderMock.java      |    3 +-
 .../repository/mock/RepositoryProviderMock.java    |    5 +-
 .../org/apache/archiva/repository/Repository.java  |    2 +-
 .../archiva/repository/RepositoryProvider.java     |    1 +
 .../{RepositoryEvent.java => events/Event.java}    |   50 +-
 .../EventType.java}                                |    9 +-
 .../LifecycleEvent.java}                           |   17 +-
 .../RepositoryEvent.java}                          |   20 +-
 .../{ => events}/RepositoryEventHandler.java       |   16 +-
 .../{ => events}/RepositoryEventListener.java      |    6 +-
 .../RepositoryRegistryEvent.java}                  |   17 +-
 .../RepositoryValueEvent.java}                     |   41 +-
 .../repository/features/AbstractFeature.java       |    6 +-
 .../repository/features/IndexCreationEvent.java    |   21 +-
 .../repository/features/IndexCreationFeature.java  |    6 +-
 .../repository/features/RemoteIndexFeature.java    |   10 +
 .../archiva/repository/AbstractRepository.java     |   56 +-
 .../archiva/repository/RepositoryRegistry.java     | 1181 +++++++++-----------
 .../repository/mock/RepositoryProviderMock.java    |    4 +-
 .../repository/mock/RepositoryProviderMock.java    |    5 +-
 20 files changed, 723 insertions(+), 753 deletions(-)

diff --git 
a/archiva-modules/archiva-base/archiva-consumers/archiva-consumer-archetype/src/main/resources/archetype-resources/src/test/java/RepositoryProviderMock.java
 
b/archiva-modules/archiva-base/archiva-consumers/archiva-consumer-archetype/src/main/resources/archetype-resources/src/test/java/RepositoryProviderMock.java
index 15cf17e..5302a74 100644
--- 
a/archiva-modules/archiva-base/archiva-consumers/archiva-consumer-archetype/src/main/resources/archetype-resources/src/test/java/RepositoryProviderMock.java
+++ 
b/archiva-modules/archiva-base/archiva-consumers/archiva-consumer-archetype/src/main/resources/archetype-resources/src/test/java/RepositoryProviderMock.java
@@ -36,6 +36,7 @@ import org.apache.archiva.repository.RepositoryCredentials;
 import org.apache.archiva.repository.RepositoryException;
 import org.apache.archiva.repository.RepositoryProvider;
 import org.apache.archiva.repository.RepositoryType;
+import org.apache.archiva.repository.events.Event;
 import org.apache.archiva.repository.features.ArtifactCleanupFeature;
 import org.apache.archiva.repository.features.IndexCreationFeature;
 import org.apache.archiva.repository.features.RemoteIndexFeature;
@@ -255,7 +256,7 @@ public class RepositoryProviderMock implements 
RepositoryProvider
     }
 
     @Override
-    public <T> void raise(org.apache.archiva.repository.RepositoryEvent<T> 
event) {
+    public void raise(Event event) {
 
     }
 
diff --git 
a/archiva-modules/archiva-base/archiva-consumers/archiva-core-consumers/src/test/java/org/apache/archiva/repository/mock/RepositoryProviderMock.java
 
b/archiva-modules/archiva-base/archiva-consumers/archiva-core-consumers/src/test/java/org/apache/archiva/repository/mock/RepositoryProviderMock.java
index a23ae0f..c10a5a8 100644
--- 
a/archiva-modules/archiva-base/archiva-consumers/archiva-core-consumers/src/test/java/org/apache/archiva/repository/mock/RepositoryProviderMock.java
+++ 
b/archiva-modules/archiva-base/archiva-consumers/archiva-core-consumers/src/test/java/org/apache/archiva/repository/mock/RepositoryProviderMock.java
@@ -32,7 +32,8 @@ import org.apache.archiva.repository.PasswordCredentials;
 import org.apache.archiva.repository.ReleaseScheme;
 import org.apache.archiva.repository.RemoteRepository;
 import org.apache.archiva.repository.RepositoryCredentials;
-import org.apache.archiva.repository.RepositoryEvent;
+import org.apache.archiva.repository.events.Event;
+import org.apache.archiva.repository.events.RepositoryValueEvent;
 import org.apache.archiva.repository.RepositoryException;
 import org.apache.archiva.repository.RepositoryGroup;
 import org.apache.archiva.repository.RepositoryProvider;
@@ -284,7 +285,7 @@ public class RepositoryProviderMock implements 
RepositoryProvider
     }
 
     @Override
-    public <T> void raise(RepositoryEvent<T> event) {
+    public void raise(Event event) {
 
     }
 }
diff --git 
a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/Repository.java
 
b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/Repository.java
index cc43ab2..9b26143 100644
--- 
a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/Repository.java
+++ 
b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/Repository.java
@@ -20,12 +20,12 @@ package org.apache.archiva.repository;
  */
 
 import org.apache.archiva.indexer.ArchivaIndexingContext;
+import org.apache.archiva.repository.events.RepositoryEventHandler;
 import org.apache.archiva.repository.storage.RepositoryStorage;
 import org.apache.archiva.repository.features.RepositoryFeature;
 import org.apache.archiva.repository.storage.StorageAsset;
 
 import java.net.URI;
-import java.nio.file.Path;
 import java.util.Locale;
 import java.util.Set;
 
diff --git 
a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryProvider.java
 
b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryProvider.java
index 1f26a5d..3a405fb 100644
--- 
a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryProvider.java
+++ 
b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryProvider.java
@@ -22,6 +22,7 @@ package org.apache.archiva.repository;
 import org.apache.archiva.configuration.ManagedRepositoryConfiguration;
 import org.apache.archiva.configuration.RemoteRepositoryConfiguration;
 import org.apache.archiva.configuration.RepositoryGroupConfiguration;
+import org.apache.archiva.repository.events.RepositoryEventListener;
 
 import java.io.IOException;
 import java.util.Set;
diff --git 
a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEvent.java
 
b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/events/Event.java
similarity index 61%
copy from 
archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEvent.java
copy to 
archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/events/Event.java
index 8a9db88..afac04c 100644
--- 
a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEvent.java
+++ 
b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/events/Event.java
@@ -1,4 +1,4 @@
-package org.apache.archiva.repository;
+package org.apache.archiva.repository.events;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -21,49 +21,47 @@ package org.apache.archiva.repository;
 
 import java.time.LocalDateTime;
 
-/**
- * Repository event. Repository events are used for providing information 
about repository changes.
- *
- * @param <T>
- */
-public class RepositoryEvent<T> {
+public class Event<O> {
 
+    Event previous;
+    final O originator;
     final EventType type;
-    final Repository repo;
-    final T value;
-    final T oldValue;
     final LocalDateTime instant;
 
-    public RepositoryEvent(EventType type, Repository repo, T oldValue, T 
value) {
+    public Event(EventType type, O originator) {
+        this.originator = originator;
         this.type = type;
-        this.repo = repo;
-        this.value = value;
-        this.oldValue = oldValue;
         this.instant = LocalDateTime.now();
     }
 
-    public interface EventType {
-        String name();
+    private <OO> Event(Event<OO> previous, O originator) {
+        this.previous = previous;
+        this.originator = originator;
+        this.type = previous.getType();
+        this.instant = previous.getInstant();
     }
 
-
     public EventType getType() {
         return type;
     };
 
-    public Repository getRepository() {
-        return repo;
-    };
+    public LocalDateTime getInstant() {
+        return instant;
+    }
 
-    public T getValue() {
-        return value;
+    public O getOriginator() {
+        return originator;
     }
 
-    public T getOldValue() {
-        return oldValue;
+    public <NO> Event<NO> recreate(NO newOrigin) {
+        return new Event(this, newOrigin);
     }
 
-    public LocalDateTime getInstant() {
-        return instant;
+    public Event getPreviousEvent() {
+        return previous;
+    }
+
+    public boolean hasPreviousEvent() {
+        return previous!=null;
     }
 }
diff --git 
a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEventListener.java
 
b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/events/EventType.java
similarity index 81%
copy from 
archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEventListener.java
copy to 
archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/events/EventType.java
index 0234f34..5004a15 100644
--- 
a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEventListener.java
+++ 
b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/events/EventType.java
@@ -1,4 +1,4 @@
-package org.apache.archiva.repository;
+package org.apache.archiva.repository.events;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -19,10 +19,7 @@ package org.apache.archiva.repository;
  * under the License.
  */
 
-/**
- * Listener that accepts repository events.
- */
-public interface RepositoryEventListener {
+public interface EventType {
 
-    <T> void raise(RepositoryEvent<T> event);
+    String name();
 }
diff --git 
a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEventHandler.java
 
b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/events/LifecycleEvent.java
similarity index 67%
copy from 
archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEventHandler.java
copy to 
archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/events/LifecycleEvent.java
index 7432627..5f69d1e 100644
--- 
a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEventHandler.java
+++ 
b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/events/LifecycleEvent.java
@@ -1,4 +1,4 @@
-package org.apache.archiva.repository;
+package org.apache.archiva.repository.events;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -19,14 +19,15 @@ package org.apache.archiva.repository;
  * under the License.
  */
 
-/**
- * Implementations of this interface are able to handle repository event 
listeners
- */
-public interface RepositoryEventHandler {
+import org.apache.archiva.repository.Repository;
 
-    void addListener(RepositoryEventListener listener);
+public class LifecycleEvent<O> extends RepositoryEvent<O> {
 
-    void removeListener(RepositoryEventListener listener);
+    public enum LifecycleEventType implements EventType {
+        REGISTERED,UNREGISTERED,UPDATED
+    }
 
-    void clearListeners();
+    public LifecycleEvent(LifecycleEventType type, O origin, Repository 
repository) {
+        super(type, origin, repository);
+    }
 }
diff --git 
a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEventHandler.java
 
b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/events/RepositoryEvent.java
similarity index 66%
copy from 
archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEventHandler.java
copy to 
archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/events/RepositoryEvent.java
index 7432627..dd5550b 100644
--- 
a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEventHandler.java
+++ 
b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/events/RepositoryEvent.java
@@ -1,4 +1,4 @@
-package org.apache.archiva.repository;
+package org.apache.archiva.repository.events;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -19,14 +19,18 @@ package org.apache.archiva.repository;
  * under the License.
  */
 
-/**
- * Implementations of this interface are able to handle repository event 
listeners
- */
-public interface RepositoryEventHandler {
+import org.apache.archiva.repository.Repository;
+
+public class RepositoryEvent<O> extends Event<O> {
 
-    void addListener(RepositoryEventListener listener);
+    private final Repository repository;
 
-    void removeListener(RepositoryEventListener listener);
+    public RepositoryEvent(EventType type, O origin, Repository repository) {
+        super(type, origin);
+        this.repository = repository;
+    }
 
-    void clearListeners();
+    public Repository getRepository() {
+        return repository;
+    }
 }
diff --git 
a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEventHandler.java
 
b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/events/RepositoryEventHandler.java
similarity index 64%
copy from 
archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEventHandler.java
copy to 
archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/events/RepositoryEventHandler.java
index 7432627..123ffb2 100644
--- 
a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEventHandler.java
+++ 
b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/events/RepositoryEventHandler.java
@@ -1,4 +1,4 @@
-package org.apache.archiva.repository;
+package org.apache.archiva.repository.events;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -19,14 +19,22 @@ package org.apache.archiva.repository;
  * under the License.
  */
 
+import java.util.Set;
+
 /**
- * Implementations of this interface are able to handle repository event 
listeners
+ * A repository event handler raises events to its registered listeners.
+ * Listeners may register for all events that are raised or only to a subset 
of events.
+ *
  */
 public interface RepositoryEventHandler {
 
-    void addListener(RepositoryEventListener listener);
+    void register(RepositoryEventListener listener);
+
+    void register(RepositoryEventListener listener, EventType type);
+
+    void register(RepositoryEventListener listener, Set<? extends EventType> 
types);
 
-    void removeListener(RepositoryEventListener listener);
+    void unregister(RepositoryEventListener listener);
 
     void clearListeners();
 }
diff --git 
a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEventListener.java
 
b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/events/RepositoryEventListener.java
similarity index 86%
rename from 
archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEventListener.java
rename to 
archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/events/RepositoryEventListener.java
index 0234f34..1f0b203 100644
--- 
a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEventListener.java
+++ 
b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/events/RepositoryEventListener.java
@@ -1,4 +1,4 @@
-package org.apache.archiva.repository;
+package org.apache.archiva.repository.events;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -19,10 +19,12 @@ package org.apache.archiva.repository;
  * under the License.
  */
 
+import org.apache.archiva.repository.events.RepositoryValueEvent;
+
 /**
  * Listener that accepts repository events.
  */
 public interface RepositoryEventListener {
 
-    <T> void raise(RepositoryEvent<T> event);
+    void raise(Event event);
 }
diff --git 
a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEventHandler.java
 
b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/events/RepositoryRegistryEvent.java
similarity index 72%
rename from 
archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEventHandler.java
rename to 
archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/events/RepositoryRegistryEvent.java
index 7432627..d9b891c 100644
--- 
a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEventHandler.java
+++ 
b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/events/RepositoryRegistryEvent.java
@@ -1,4 +1,4 @@
-package org.apache.archiva.repository;
+package org.apache.archiva.repository.events;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -19,14 +19,13 @@ package org.apache.archiva.repository;
  * under the License.
  */
 
-/**
- * Implementations of this interface are able to handle repository event 
listeners
- */
-public interface RepositoryEventHandler {
-
-    void addListener(RepositoryEventListener listener);
+public class RepositoryRegistryEvent<O> extends Event {
 
-    void removeListener(RepositoryEventListener listener);
+    public enum RegistryEventType implements EventType {
+        RELOADED,DESTROYED
+    }
 
-    void clearListeners();
+    public RepositoryRegistryEvent(RegistryEventType type, O origin) {
+        super(type, origin);
+    }
 }
diff --git 
a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEvent.java
 
b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/events/RepositoryValueEvent.java
similarity index 58%
rename from 
archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEvent.java
rename to 
archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/events/RepositoryValueEvent.java
index 8a9db88..6081717 100644
--- 
a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEvent.java
+++ 
b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/events/RepositoryValueEvent.java
@@ -1,4 +1,4 @@
-package org.apache.archiva.repository;
+package org.apache.archiva.repository.events;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -19,51 +19,30 @@ package org.apache.archiva.repository;
  * under the License.
  */
 
-import java.time.LocalDateTime;
+import org.apache.archiva.repository.Repository;
 
 /**
  * Repository event. Repository events are used for providing information 
about repository changes.
  *
- * @param <T>
+ * @param <V>
  */
-public class RepositoryEvent<T> {
+public class RepositoryValueEvent<O, V> extends RepositoryEvent<O> {
 
-    final EventType type;
-    final Repository repo;
-    final T value;
-    final T oldValue;
-    final LocalDateTime instant;
+    final V value;
+    final V oldValue;
 
-    public RepositoryEvent(EventType type, Repository repo, T oldValue, T 
value) {
-        this.type = type;
-        this.repo = repo;
+    public RepositoryValueEvent(EventType type, O origin, Repository repo, V 
oldValue, V value) {
+        super(type, origin, repo);
         this.value = value;
         this.oldValue = oldValue;
-        this.instant = LocalDateTime.now();
     }
 
-    public interface EventType {
-        String name();
-    }
-
-
-    public EventType getType() {
-        return type;
-    };
-
-    public Repository getRepository() {
-        return repo;
-    };
-
-    public T getValue() {
+    public V getValue() {
         return value;
     }
 
-    public T getOldValue() {
+    public V getOldValue() {
         return oldValue;
     }
 
-    public LocalDateTime getInstant() {
-        return instant;
-    }
 }
diff --git 
a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/features/AbstractFeature.java
 
b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/features/AbstractFeature.java
index 08d0bba..6b64d93 100644
--- 
a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/features/AbstractFeature.java
+++ 
b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/features/AbstractFeature.java
@@ -19,8 +19,8 @@ package org.apache.archiva.repository.features;
  * under the License.
  */
 
-import org.apache.archiva.repository.RepositoryEvent;
-import org.apache.archiva.repository.RepositoryEventListener;
+import org.apache.archiva.repository.events.Event;
+import org.apache.archiva.repository.events.RepositoryEventListener;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -56,7 +56,7 @@ public class AbstractFeature {
         this.listener.clear();
     }
 
-    protected <T> void raiseEvent(RepositoryEvent<T> event) {
+    public void pushEvent(Event event) {
         for(RepositoryEventListener listr : listener) {
             listr.raise(event);
         }
diff --git 
a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/features/IndexCreationEvent.java
 
b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/features/IndexCreationEvent.java
index 49a3d44..037ba47 100644
--- 
a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/features/IndexCreationEvent.java
+++ 
b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/features/IndexCreationEvent.java
@@ -20,29 +20,30 @@ package org.apache.archiva.repository.features;
  */
 
 import org.apache.archiva.repository.Repository;
-import org.apache.archiva.repository.RepositoryEvent;
+import org.apache.archiva.repository.events.EventType;
+import org.apache.archiva.repository.events.RepositoryValueEvent;
 
 import java.net.URI;
 
-public class IndexCreationEvent extends RepositoryEvent<URI> {
+public class IndexCreationEvent<O> extends RepositoryValueEvent<O, URI> {
 
     public enum Index implements EventType {
         INDEX_URI_CHANGE, PACKED_INDEX_URI_CHANGE
     }
 
-    IndexCreationEvent(Repository repo, URI oldValue, URI value) {
-        super(Index.INDEX_URI_CHANGE, repo, oldValue, value);
+    IndexCreationEvent(Repository repo, O origin, URI oldValue, URI value) {
+        super(Index.INDEX_URI_CHANGE, origin, repo, oldValue, value);
     }
 
-    IndexCreationEvent(Index type, Repository repo, URI oldValue, URI value) {
-        super(type, repo, oldValue, value);
+    IndexCreationEvent(Index type, O origin, Repository repo, URI oldValue, 
URI value) {
+        super(type, origin, repo, oldValue, value);
     }
 
-    public static final IndexCreationEvent indexUriChange(Repository repo, URI 
oldValue, URI newValue) {
-        return new IndexCreationEvent(Index.INDEX_URI_CHANGE, repo, oldValue, 
newValue);
+    public static final <O> IndexCreationEvent indexUriChange(O origin, 
Repository repo, URI oldValue, URI newValue) {
+        return new IndexCreationEvent(Index.INDEX_URI_CHANGE, origin, repo, 
oldValue, newValue);
     }
 
-    public static final IndexCreationEvent packedIndexUriChange(Repository 
repo, URI oldValue, URI newValue) {
-        return new IndexCreationEvent(Index.PACKED_INDEX_URI_CHANGE, repo, 
oldValue, newValue);
+    public static final <O> IndexCreationEvent packedIndexUriChange(O origin, 
Repository repo, URI oldValue, URI newValue) {
+        return new IndexCreationEvent(Index.PACKED_INDEX_URI_CHANGE, origin, 
repo, oldValue, newValue);
     }
 }
diff --git 
a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/features/IndexCreationFeature.java
 
b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/features/IndexCreationFeature.java
index 94812fc..cf7432c 100644
--- 
a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/features/IndexCreationFeature.java
+++ 
b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/features/IndexCreationFeature.java
@@ -21,7 +21,7 @@ package org.apache.archiva.repository.features;
 
 
 import org.apache.archiva.repository.Repository;
-import org.apache.archiva.repository.RepositoryEventListener;
+import org.apache.archiva.repository.events.RepositoryEventListener;
 import org.apache.archiva.repository.storage.StorageAsset;
 import org.apache.commons.lang3.StringUtils;
 
@@ -113,7 +113,7 @@ public class IndexCreationFeature extends AbstractFeature 
implements RepositoryF
     {
         URI oldVal = this.indexPath;
         this.indexPath = indexPath;
-        raiseEvent(IndexCreationEvent.indexUriChange(repo, oldVal, 
this.indexPath));
+        pushEvent(IndexCreationEvent.indexUriChange(this, repo, oldVal, 
this.indexPath));
 
     }
 
@@ -157,7 +157,7 @@ public class IndexCreationFeature extends AbstractFeature 
implements RepositoryF
     public void setPackedIndexPath(URI packedIndexPath) {
         URI oldVal = this.packedIndexPath;
         this.packedIndexPath = packedIndexPath;
-        raiseEvent(IndexCreationEvent.packedIndexUriChange(repo, oldVal, 
this.packedIndexPath));
+        pushEvent(IndexCreationEvent.packedIndexUriChange(this, repo, oldVal, 
this.packedIndexPath));
     }
 
     /**
diff --git 
a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/features/RemoteIndexFeature.java
 
b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/features/RemoteIndexFeature.java
index 3e15487..245b8b0 100644
--- 
a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/features/RemoteIndexFeature.java
+++ 
b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/features/RemoteIndexFeature.java
@@ -23,6 +23,7 @@ package org.apache.archiva.repository.features;
 import org.apache.commons.lang3.StringUtils;
 
 import java.net.URI;
+import java.net.URISyntaxException;
 import java.time.Duration;
 
 /**
@@ -32,6 +33,15 @@ public class RemoteIndexFeature implements 
RepositoryFeature<RemoteIndexFeature>
 
     private boolean downloadRemoteIndex = false;
     private URI indexUri;
+
+    {
+        try {
+            indexUri = new URI(".index");
+        } catch (URISyntaxException e) {
+            // Ignore
+        }
+    }
+
     private boolean downloadRemoteIndexOnStartup = false;
     private Duration downloadTimeout = Duration.ofSeconds( 600 );
     private String proxyId = "";
diff --git 
a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/AbstractRepository.java
 
b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/AbstractRepository.java
index 99c3dd0..d8c9e3b 100644
--- 
a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/AbstractRepository.java
+++ 
b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/AbstractRepository.java
@@ -24,6 +24,7 @@ import com.cronutils.model.definition.CronDefinition;
 import com.cronutils.model.definition.CronDefinitionBuilder;
 import com.cronutils.parser.CronParser;
 import org.apache.archiva.indexer.ArchivaIndexingContext;
+import org.apache.archiva.repository.events.*;
 import org.apache.archiva.repository.storage.RepositoryStorage;
 import org.apache.archiva.repository.storage.StorageAsset;
 import org.apache.archiva.repository.features.RepositoryFeature;
@@ -39,7 +40,6 @@ import java.net.URI;
 import java.nio.channels.ReadableByteChannel;
 import java.nio.channels.WritableByteChannel;
 import java.nio.file.CopyOption;
-import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -76,6 +76,7 @@ public abstract class AbstractRepository implements 
EditableRepository, Reposito
     private String layout = "default";
     public static final CronDefinition CRON_DEFINITION = 
CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ);
     private List<RepositoryEventListener> listeners = new ArrayList<>();
+    private Map<EventType, List<RepositoryEventListener>> listenerTypeMap = 
new HashMap<>();
 
 
     Map<Class<? extends RepositoryFeature<?>>, RepositoryFeature<?>> 
featureMap = new HashMap<>(  );
@@ -315,24 +316,65 @@ public abstract class AbstractRepository implements 
EditableRepository, Reposito
     }
 
     @Override
-    public <T> void raise(RepositoryEvent<T> event) {
-        for(RepositoryEventListener listener : listeners) {
-            listener.raise(event);
+    public void raise(Event event) {
+        callListeners(event, listeners);
+        if (listenerTypeMap.containsKey(event.getType())) {
+            callListeners(event, listenerTypeMap.get(event.getType()));
         }
     }
 
-    public void addListener(RepositoryEventListener listener) {
+    private void callListeners(Event event, List<RepositoryEventListener> 
evtListeners) {
+        for(RepositoryEventListener listener : evtListeners) {
+            try {
+                listener.raise(event);
+            } catch (Throwable e) {
+                log.error("Could not raise event {} on listener {}: {}", 
event, listener, e.getMessage());
+            }
+        }
+
+    }
+
+    @Override
+    public void register(RepositoryEventListener listener) {
         if (!this.listeners.contains(listener)) {
             this.listeners.add(listener);
         }
     }
 
-    public void removeListener(RepositoryEventListener listener) {
-        this.removeListener(listener);
+    @Override
+    public void register(RepositoryEventListener listener, EventType type) {
+        List<RepositoryEventListener> listeners;
+        if (listenerTypeMap.containsKey(type)) {
+            listeners = listenerTypeMap.get(type);
+        } else {
+            listeners = new ArrayList<>();
+            listenerTypeMap.put(type, listeners);
+        }
+        if (!listeners.contains(listener)) {
+            listeners.add(listener);
+        }
+
+    }
+
+    @Override
+    public void register(RepositoryEventListener listener, Set<? extends 
EventType> types) {
+        for (EventType type : types) {
+            register(listener, type);
+        }
+    }
+
+    @Override
+    public void unregister(RepositoryEventListener listener) {
+        listeners.remove(listener);
+        for (List<RepositoryEventListener> listeners : 
listenerTypeMap.values()) {
+            listeners.remove(listener);
+        }
     }
 
+    @Override
     public void clearListeners() {
         this.listeners.clear();
+        this.listenerTypeMap.clear();
     }
 
     @Override
diff --git 
a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/RepositoryRegistry.java
 
b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/RepositoryRegistry.java
index 316b1cf..a58f960 100644
--- 
a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/RepositoryRegistry.java
+++ 
b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/RepositoryRegistry.java
@@ -20,12 +20,9 @@ package org.apache.archiva.repository;
  */
 
 import org.apache.archiva.configuration.*;
-import org.apache.archiva.indexer.ArchivaIndexManager;
-import org.apache.archiva.indexer.ArchivaIndexingContext;
-import org.apache.archiva.indexer.IndexCreationFailedException;
-import org.apache.archiva.indexer.IndexManagerFactory;
-import org.apache.archiva.indexer.IndexUpdateFailedException;
+import org.apache.archiva.indexer.*;
 import org.apache.archiva.redback.components.registry.RegistryException;
+import org.apache.archiva.repository.events.*;
 import org.apache.archiva.repository.features.IndexCreationEvent;
 import org.apache.archiva.repository.features.IndexCreationFeature;
 import org.apache.archiva.repository.features.StagingRepositoryFeature;
@@ -38,13 +35,7 @@ import javax.annotation.PostConstruct;
 import javax.annotation.PreDestroy;
 import javax.inject.Inject;
 import javax.inject.Named;
-import java.util.ArrayList;
-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.*;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
@@ -54,16 +45,16 @@ 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.
- *
+ * <p>
  * The modification methods addXX and removeXX persist the changes immediately 
to the configuration. If the
  * configuration save fails the changes are rolled back.
- *
+ * <p>
  * TODO: Audit events
  */
-@Service( "repositoryRegistry" )
+@Service("repositoryRegistry")
 public class RepositoryRegistry implements ConfigurationListener, 
RepositoryEventHandler, RepositoryEventListener {
 
-    private static final Logger log = LoggerFactory.getLogger( 
RepositoryRegistry.class );
+    private static final Logger log = 
LoggerFactory.getLogger(RepositoryRegistry.class);
 
     /**
      * We inject all repository providers
@@ -82,164 +73,157 @@ public class RepositoryRegistry implements 
ConfigurationListener, RepositoryEven
     RepositoryContentFactory repositoryContentFactory;
 
     private List<RepositoryEventListener> listeners = new ArrayList<>();
+    private Map<EventType, List<RepositoryEventListener>> typeListenerMap = 
new HashMap<>();
 
 
-    private Map<String, ManagedRepository> managedRepositories = new 
HashMap<>( );
-    private Map<String, ManagedRepository> uManagedRepository = 
Collections.unmodifiableMap( managedRepositories );
+    private Map<String, ManagedRepository> managedRepositories = new 
HashMap<>();
+    private Map<String, ManagedRepository> uManagedRepository = 
Collections.unmodifiableMap(managedRepositories);
 
-    private Map<String, RemoteRepository> remoteRepositories = new HashMap<>( 
);
-    private Map<String, RemoteRepository> uRemoteRepositories = 
Collections.unmodifiableMap( remoteRepositories );
+    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 ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
+
+    private volatile boolean ignoreConfigEvents = false;
 
-    public void setArchivaConfiguration( ArchivaConfiguration 
archivaConfiguration) {
+    public void setArchivaConfiguration(ArchivaConfiguration 
archivaConfiguration) {
         this.archivaConfiguration = archivaConfiguration;
     }
 
     @PostConstruct
-    private void initialize( )
-    {
-        rwLock.writeLock( ).lock( );
-        try
-        {
+    private void initialize() {
+        rwLock.writeLock().lock();
+        try {
             log.debug("Initializing repository registry");
-            for(ManagedRepository rep : managedRepositories.values()) {
+            for (ManagedRepository rep : managedRepositories.values()) {
                 rep.close();
             }
-            managedRepositories.clear( );
-            managedRepositories.putAll( getManagedRepositoriesFromConfig( ) );
+            managedRepositories.clear();
+            updateManagedRepositoriesFromConfig();
             for (RemoteRepository repo : remoteRepositories.values()) {
                 repo.close();
             }
-            remoteRepositories.clear( );
-            remoteRepositories.putAll( getRemoteRepositoriesFromConfig( ) );
+            remoteRepositories.clear();
+            updateRemoteRepositoriesFromConfig();
 
             repositoryGroups.clear();
-            repositoryGroups.putAll(getRepositorGroupsFromConfig());
+            Map<String, RepositoryGroup> repositoryGroups = 
getRepositorGroupsFromConfig();
+            this.repositoryGroups.putAll(repositoryGroups);
 
             // archivaConfiguration.addChangeListener(this);
             archivaConfiguration.addListener(this);
+        } finally {
+            rwLock.writeLock().unlock();
         }
-        finally
-        {
-            rwLock.writeLock( ).unlock( );
-        }
+        pushEvent(new 
RepositoryRegistryEvent(RepositoryRegistryEvent.RegistryEventType.RELOADED, 
this));
     }
 
     @PreDestroy
     public void destroy() {
-        for(ManagedRepository rep : managedRepositories.values()) {
+        for (ManagedRepository rep : managedRepositories.values()) {
             rep.close();
         }
+        managedRepositories.clear();
         for (RemoteRepository repo : remoteRepositories.values()) {
             repo.close();
         }
+        remoteRepositories.clear();
+        pushEvent(new 
RepositoryRegistryEvent(RepositoryRegistryEvent.RegistryEventType.DESTROYED, 
this));
     }
 
 
-
-    private Map<RepositoryType, RepositoryProvider> createProviderMap( )
-    {
-        Map<RepositoryType, RepositoryProvider> map = new HashMap<>( );
-        if ( repositoryProviders != null )
-        {
-            for ( RepositoryProvider provider : repositoryProviders )
-            {
-                for ( RepositoryType type : provider.provides( ) )
-                {
-                    map.put( type, provider );
+    private Map<RepositoryType, RepositoryProvider> createProviderMap() {
+        Map<RepositoryType, RepositoryProvider> map = new HashMap<>();
+        if (repositoryProviders != null) {
+            for (RepositoryProvider provider : repositoryProviders) {
+                for (RepositoryType type : provider.provides()) {
+                    map.put(type, provider);
                 }
             }
         }
         return map;
     }
 
-    private 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 ) );
+    private 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));
     }
 
-    private Map<String, ManagedRepository> getManagedRepositoriesFromConfig( )
-    {
-        try
-        {
+    private void updateManagedRepositoriesFromConfig() {
+        try {
             List<ManagedRepositoryConfiguration> managedRepoConfigs =
-                getArchivaConfiguration( ).getConfiguration( 
).getManagedRepositories( );
+                    
getArchivaConfiguration().getConfiguration().getManagedRepositories();
 
-            if ( managedRepoConfigs == null )
-            {
-                return Collections.emptyMap();
+            if (managedRepoConfigs == null) {
+                return;
             }
 
-            Map<String, ManagedRepository> managedRepos = new LinkedHashMap<>( 
managedRepoConfigs.size( ) );
-
-            Map<RepositoryType, RepositoryProvider> providerMap = 
createProviderMap( );
-            for ( ManagedRepositoryConfiguration repoConfig : 
managedRepoConfigs )
-            {
-                if (managedRepos.containsKey(repoConfig.getId())) {
-                    log.warn( "Duplicate repository definitions for {} in 
config found.", repoConfig.getId( ) );
+            Map<RepositoryType, RepositoryProvider> providerMap = 
createProviderMap();
+            for (ManagedRepositoryConfiguration repoConfig : 
managedRepoConfigs) {
+                if (managedRepositories.containsKey(repoConfig.getId())) {
+                    log.warn("Duplicate repository definitions for {} in 
config found.", repoConfig.getId());
                     continue;
                 }
-                RepositoryType repositoryType = RepositoryType.valueOf( 
repoConfig.getType( ) );
-                if ( providerMap.containsKey( repositoryType ) )
-                {
-                    try
-                    {
-                        ManagedRepository repo = createNewManagedRepository( 
providerMap.get( repositoryType ), repoConfig );
-                        managedRepos.put( repo.getId( ), repo );
-                    }
-                    catch ( Exception e )
-                    {
-                        log.error( "Could not create managed repository {}: 
{}", repoConfig.getId( ), e.getMessage( ), e );
+                RepositoryType repositoryType = 
RepositoryType.valueOf(repoConfig.getType());
+                if (providerMap.containsKey(repositoryType)) {
+                    try {
+                        ManagedRepository repo = 
createNewManagedRepository(providerMap.get(repositoryType), repoConfig);
+                        managedRepositories.put(repo.getId(), repo);
+                        pushEvent(new 
LifecycleEvent(LifecycleEvent.LifecycleEventType.REGISTERED, this, repo));
+                    } catch (Exception e) {
+                        log.error("Could not create managed repository {}: 
{}", repoConfig.getId(), e.getMessage(), e);
                     }
                 }
             }
-            return managedRepos;
+            return;
         } catch (Throwable e) {
-            log.error("Could not initialize repositories from config: 
{}",e.getMessage(), e );
+            log.error("Could not initialize repositories from config: {}", 
e.getMessage(), e);
             //noinspection unchecked
-            return Collections.emptyMap();
+            return;
         }
     }
 
-    private ManagedRepository createNewManagedRepository( RepositoryProvider 
provider, ManagedRepositoryConfiguration cfg ) throws RepositoryException
-    {
+    private ManagedRepository createNewManagedRepository(RepositoryProvider 
provider, ManagedRepositoryConfiguration cfg) throws RepositoryException {
         log.debug("Creating repo {}", cfg.getId());
-        ManagedRepository repo = provider.createManagedInstance( cfg );
-        repo.addListener(this);
-        updateRepositoryReferences( provider, repo, cfg , null);
+        ManagedRepository repo = provider.createManagedInstance(cfg);
+        repo.register(this);
+        updateRepositoryReferences(provider, repo, cfg, null);
         return repo;
 
     }
 
-    @SuppressWarnings( "unchecked" )
-    private void updateRepositoryReferences(RepositoryProvider provider, 
ManagedRepository repo, ManagedRepositoryConfiguration cfg, Configuration 
configuration) throws RepositoryException
-    {
-        log.debug("Updating references of repo {}",repo.getId());
-        if ( repo.supportsFeature( StagingRepositoryFeature.class ) )
-        {
-            StagingRepositoryFeature feature = repo.getFeature( 
StagingRepositoryFeature.class ).get( );
-            if ( feature.isStageRepoNeeded( ) && 
feature.getStagingRepository() == null)
-            {
-                ManagedRepository stageRepo = getStagingRepository( provider, 
cfg, configuration);
-                managedRepositories.put(stageRepo.getId(), stageRepo);
-                feature.setStagingRepository( stageRepo );
-                if (configuration!=null) {
-                    replaceOrAddRepositoryConfig( 
provider.getManagedConfiguration( stageRepo ), configuration );
+    private String getStagingId(String repoId) {
+        return repoId + StagingRepositoryFeature.STAGING_REPO_POSTFIX;
+    }
+
+    @SuppressWarnings("unchecked")
+    private void updateRepositoryReferences(RepositoryProvider provider, 
ManagedRepository repo, ManagedRepositoryConfiguration cfg, Configuration 
configuration) throws RepositoryException {
+        log.debug("Updating references of repo {}", repo.getId());
+        if (repo.supportsFeature(StagingRepositoryFeature.class)) {
+            StagingRepositoryFeature feature = 
repo.getFeature(StagingRepositoryFeature.class).get();
+            if (feature.isStageRepoNeeded() && feature.getStagingRepository() 
== null) {
+                ManagedRepository stageRepo = 
getManagedRepository(getStagingId(repo.getId()));
+                if (stageRepo==null) {
+                    stageRepo = getStagingRepository(provider, cfg, 
configuration);
+                    managedRepositories.put(stageRepo.getId(), stageRepo);
+                    if (configuration != null) {
+                        
replaceOrAddRepositoryConfig(provider.getManagedConfiguration(stageRepo), 
configuration);
+                    }
                 }
+                feature.setStagingRepository(stageRepo);
+                pushEvent(new 
LifecycleEvent(LifecycleEvent.LifecycleEventType.REGISTERED, this, stageRepo));
             }
         }
-        if ( repo instanceof EditableManagedRepository)
-        {
+        if (repo instanceof EditableManagedRepository) {
             EditableManagedRepository editableRepo = 
(EditableManagedRepository) repo;
-            if (repo.getContent()==null) {
+            if (repo.getContent() == null) {
                 
editableRepo.setContent(repositoryContentFactory.getManagedRepositoryContent(repo));
+                editableRepo.getContent().setRepository(editableRepo);
             }
-            log.debug("Index repo: "+repo.hasIndex());
-            if (repo.hasIndex() && repo.getIndexingContext()==null) {
+            log.debug("Index repo: " + repo.hasIndex());
+            if (repo.hasIndex() && repo.getIndexingContext() == null) {
                 log.debug("Creating indexing context for {}", repo.getId());
                 createIndexingContext(editableRepo);
             }
@@ -258,129 +242,105 @@ public class RepositoryRegistry implements 
ConfigurationListener, RepositoryEven
                 
editableRepo.setIndexingContext(idxManager.createContext(editableRepo));
                 idxManager.updateLocalIndexPath(editableRepo);
             } catch (IndexCreationFailedException e) {
-                throw new RepositoryException("Could not create index for 
repository "+editableRepo.getId()+": "+e.getMessage(),e);
+                throw new RepositoryException("Could not create index for 
repository " + editableRepo.getId() + ": " + e.getMessage(), e);
             }
         }
     }
 
-    private ManagedRepository getStagingRepository(RepositoryProvider 
provider, ManagedRepositoryConfiguration baseRepoCfg, Configuration 
configuration) throws RepositoryException
-    {
-        ManagedRepository stageRepo = getManagedRepository( baseRepoCfg.getId( 
) + StagingRepositoryFeature.STAGING_REPO_POSTFIX );
-        if ( stageRepo == null )
-        {
-            stageRepo = provider.createStagingInstance( baseRepoCfg );
+    private ManagedRepository getStagingRepository(RepositoryProvider 
provider, ManagedRepositoryConfiguration baseRepoCfg, Configuration 
configuration) throws RepositoryException {
+        ManagedRepository stageRepo = 
getManagedRepository(getStagingId(baseRepoCfg.getId()));
+        if (stageRepo == null) {
+            stageRepo = provider.createStagingInstance(baseRepoCfg);
             if (stageRepo.supportsFeature(StagingRepositoryFeature.class)) {
                 
stageRepo.getFeature(StagingRepositoryFeature.class).get().setStageRepoNeeded(false);
             }
-            ManagedRepositoryConfiguration stageCfg = 
provider.getManagedConfiguration( stageRepo );
-            updateRepositoryReferences( provider, stageRepo, stageCfg, 
configuration);
+            ManagedRepositoryConfiguration stageCfg = 
provider.getManagedConfiguration(stageRepo);
+            updateRepositoryReferences(provider, stageRepo, stageCfg, 
configuration);
         }
         return stageRepo;
     }
 
 
-
-
-    private Map<String, RemoteRepository> getRemoteRepositoriesFromConfig( )
-    {
-        try
-        {
+    private void updateRemoteRepositoriesFromConfig() {
+        try {
             List<RemoteRepositoryConfiguration> remoteRepoConfigs =
-                getArchivaConfiguration( ).getConfiguration( 
).getRemoteRepositories( );
+                    
getArchivaConfiguration().getConfiguration().getRemoteRepositories();
 
-            if ( remoteRepoConfigs == null )
-            {
+            if (remoteRepoConfigs == null) {
                 //noinspection unchecked
-                return Collections.emptyMap();
+                return;
             }
 
-            Map<String, RemoteRepository> remoteRepos = new LinkedHashMap<>( 
remoteRepoConfigs.size( ) );
-
-            Map<RepositoryType, RepositoryProvider> providerMap = 
createProviderMap( );
-            for ( RemoteRepositoryConfiguration repoConfig : remoteRepoConfigs 
)
-            {
-                RepositoryType repositoryType = RepositoryType.valueOf( 
repoConfig.getType( ) );
-                if ( providerMap.containsKey( repositoryType ) )
-                {
-                    RepositoryProvider provider = getProvider( repositoryType 
);
-                    try
-                    {
+            Map<RepositoryType, RepositoryProvider> providerMap = 
createProviderMap();
+            for (RemoteRepositoryConfiguration repoConfig : remoteRepoConfigs) 
{
+                RepositoryType repositoryType = 
RepositoryType.valueOf(repoConfig.getType());
+                if (providerMap.containsKey(repositoryType)) {
+                    RepositoryProvider provider = getProvider(repositoryType);
+                    try {
 
-                        RemoteRepository remoteRepository = 
createNewRemoteRepository( provider, repoConfig );
-                        remoteRepos.put( repoConfig.getId( ), 
remoteRepository);
-                    }
-                    catch ( Exception e )
-                    {
-                        log.error( "Could not create repository {} from 
config: {}", repoConfig.getId( ), e.getMessage( ), e );
+                        RemoteRepository remoteRepository = 
createNewRemoteRepository(provider, repoConfig);
+                        remoteRepositories.put(repoConfig.getId(), 
remoteRepository);
+                        pushEvent(new 
LifecycleEvent(LifecycleEvent.LifecycleEventType.REGISTERED, this, 
remoteRepository));
+                    } catch (Exception e) {
+                        log.error("Could not create repository {} from config: 
{}", repoConfig.getId(), e.getMessage(), e);
                     }
                 }
             }
 
-            return remoteRepos;
+            return;
         } catch (Throwable e) {
             log.error("Could not initialize remote repositories from config: 
{}", e.getMessage(), e);
             //noinspection unchecked
-            return Collections.emptyMap();
+            return;
         }
     }
 
-    private RemoteRepository createNewRemoteRepository( RepositoryProvider 
provider, RemoteRepositoryConfiguration cfg ) throws RepositoryException
-    {
+    private RemoteRepository createNewRemoteRepository(RepositoryProvider 
provider, RemoteRepositoryConfiguration cfg) throws RepositoryException {
         log.debug("Creating remote repo {}", cfg.getId());
-        RemoteRepository repo = provider.createRemoteInstance( cfg );
-        repo.addListener(this);
-        updateRepositoryReferences( provider, repo, cfg , null);
+        RemoteRepository repo = provider.createRemoteInstance(cfg);
+        repo.register(this);
+        updateRepositoryReferences(provider, repo, cfg, null);
         return repo;
 
     }
 
-    @SuppressWarnings( "unchecked" )
-    private void updateRepositoryReferences( RepositoryProvider provider, 
RemoteRepository repo, RemoteRepositoryConfiguration cfg, Configuration 
configuration) throws RepositoryException
-    {
-        if ( repo instanceof EditableRemoteRepository && repo.getContent() == 
null)
-        {
+    @SuppressWarnings("unchecked")
+    private void updateRepositoryReferences(RepositoryProvider provider, 
RemoteRepository repo, RemoteRepositoryConfiguration cfg, Configuration 
configuration) throws RepositoryException {
+        if (repo instanceof EditableRemoteRepository && repo.getContent() == 
null) {
             EditableRemoteRepository editableRepo = (EditableRemoteRepository) 
repo;
-            editableRepo.setContent( 
repositoryContentFactory.getRemoteRepositoryContent( repo ) );
-            if (repo.supportsFeature(IndexCreationFeature.class) && 
repo.getIndexingContext()==null ) {
+            
editableRepo.setContent(repositoryContentFactory.getRemoteRepositoryContent(repo));
+            if (repo.supportsFeature(IndexCreationFeature.class) && 
repo.getIndexingContext() == null) {
                 createIndexingContext(editableRepo);
             }
         }
     }
 
-    private Map<String, RepositoryGroup> getRepositorGroupsFromConfig( )
-    {
-        try
-        {
+    private Map<String, RepositoryGroup> getRepositorGroupsFromConfig() {
+        try {
             List<RepositoryGroupConfiguration> repositoryGroupConfigurations =
-                    getArchivaConfiguration( ).getConfiguration( 
).getRepositoryGroups();
+                    
getArchivaConfiguration().getConfiguration().getRepositoryGroups();
 
-            if ( repositoryGroupConfigurations == null )
-            {
+            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 );
+            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 );
+            log.error("Could not initialize repositories from config: {}", 
e.getMessage(), e);
             //noinspection unchecked
             return Collections.emptyMap();
         }
@@ -388,7 +348,7 @@ public class RepositoryRegistry implements 
ConfigurationListener, RepositoryEven
 
     RepositoryGroup createNewRepositoryGroup(RepositoryProvider provider, 
RepositoryGroupConfiguration config) throws RepositoryException {
         RepositoryGroup repositoryGroup = 
provider.createRepositoryGroup(config);
-        repositoryGroup.addListener(this);
+        repositoryGroup.register(this);
         updateRepositoryReferences(provider, repositoryGroup, config);
         return repositoryGroup;
     }
@@ -400,8 +360,7 @@ public class RepositoryRegistry implements 
ConfigurationListener, RepositoryEven
         }
     }
 
-    private ArchivaConfiguration getArchivaConfiguration( )
-    {
+    private ArchivaConfiguration getArchivaConfiguration() {
         return this.archivaConfiguration;
     }
 
@@ -410,16 +369,12 @@ public class RepositoryRegistry implements 
ConfigurationListener, RepositoryEven
      *
      * @return a list of managed and remote repositories
      */
-    public Collection<Repository> getRepositories( )
-    {
-        rwLock.readLock( ).lock( );
-        try
-        {
-            return Stream.concat( managedRepositories.values( ).stream( ), 
remoteRepositories.values( ).stream( )).collect( Collectors.toList( ) );
-        }
-        finally
-        {
-            rwLock.readLock( ).unlock( );
+    public Collection<Repository> getRepositories() {
+        rwLock.readLock().lock();
+        try {
+            return Stream.concat(managedRepositories.values().stream(), 
remoteRepositories.values().stream()).collect(Collectors.toList());
+        } finally {
+            rwLock.readLock().unlock();
         }
     }
 
@@ -428,14 +383,11 @@ public class RepositoryRegistry implements 
ConfigurationListener, RepositoryEven
      *
      * @return a list of managed repositories
      */
-    public Collection<ManagedRepository> getManagedRepositories( )
-    {
+    public Collection<ManagedRepository> getManagedRepositories() {
         rwLock.readLock().lock();
-        try
-        {
-            return uManagedRepository.values( );
-        } finally
-        {
+        try {
+            return uManagedRepository.values();
+        } finally {
             rwLock.readLock().unlock();
         }
     }
@@ -445,19 +397,16 @@ public class RepositoryRegistry implements 
ConfigurationListener, RepositoryEven
      *
      * @return a list of remote repositories
      */
-    public Collection<RemoteRepository> getRemoteRepositories( )
-    {
+    public Collection<RemoteRepository> getRemoteRepositories() {
         rwLock.readLock().lock();
-        try
-        {
-            return uRemoteRepositories.values( );
-        } finally
-        {
+        try {
+            return uRemoteRepositories.values();
+        } finally {
             rwLock.readLock().unlock();
         }
     }
 
-    public Collection<RepositoryGroup>  getRepositoryGroups() {
+    public Collection<RepositoryGroup> getRepositoryGroups() {
         rwLock.readLock().lock();
         try {
             return uRepositoryGroups.values();
@@ -473,30 +422,23 @@ public class RepositoryRegistry implements 
ConfigurationListener, RepositoryEven
      * @param repoId the repository id
      * @return the repository if found, otherwise null
      */
-    public Repository getRepository( String repoId )
-    {
-        rwLock.readLock( ).lock( );
-        try
-        {
+    public Repository getRepository(String repoId) {
+        rwLock.readLock().lock();
+        try {
             log.debug("getRepository {}", repoId);
-            if ( managedRepositories.containsKey( repoId ) )
-            {
+            if (managedRepositories.containsKey(repoId)) {
                 log.debug("Managed repo");
-                return managedRepositories.get( repoId );
-            }
-            else if (remoteRepositories.containsKey(repoId))
-            {
+                return managedRepositories.get(repoId);
+            } else if (remoteRepositories.containsKey(repoId)) {
                 log.debug("Remote repo");
-                return remoteRepositories.get( repoId );
+                return remoteRepositories.get(repoId);
             } else if (repositoryGroups.containsKey(repoId)) {
                 return repositoryGroups.get(repoId);
             } else {
                 return null;
             }
-        }
-        finally
-        {
-            rwLock.readLock( ).unlock( );
+        } finally {
+            rwLock.readLock().unlock();
         }
     }
 
@@ -507,16 +449,12 @@ public class RepositoryRegistry implements 
ConfigurationListener, RepositoryEven
      * @param repoId the repository id
      * @return the managed repository if found, otherwise null
      */
-    public ManagedRepository getManagedRepository( String repoId )
-    {
-        rwLock.readLock( ).lock( );
-        try
-        {
-            return managedRepositories.get( repoId );
-        }
-        finally
-        {
-            rwLock.readLock( ).unlock( );
+    public ManagedRepository getManagedRepository(String repoId) {
+        rwLock.readLock().lock();
+        try {
+            return managedRepositories.get(repoId);
+        } finally {
+            rwLock.readLock().unlock();
         }
     }
 
@@ -527,20 +465,16 @@ public class RepositoryRegistry implements 
ConfigurationListener, RepositoryEven
      * @param repoId the repository id
      * @return the remote repository if found, otherwise null
      */
-    public RemoteRepository getRemoteRepository( String repoId )
-    {
-        rwLock.readLock( ).lock( );
-        try
-        {
-            return remoteRepositories.get( repoId );
-        }
-        finally
-        {
-            rwLock.readLock( ).unlock( );
+    public RemoteRepository getRemoteRepository(String repoId) {
+        rwLock.readLock().lock();
+        try {
+            return remoteRepositories.get(repoId);
+        } finally {
+            rwLock.readLock().unlock();
         }
     }
 
-    public RepositoryGroup getRepositoryGroup( String groupId ) {
+    public RepositoryGroup getRepositoryGroup(String groupId) {
         rwLock.readLock().lock();
         try {
             return repositoryGroups.get(groupId);
@@ -549,6 +483,19 @@ public class RepositoryRegistry implements 
ConfigurationListener, RepositoryEven
         }
     }
 
+    /*
+     * 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;
+        }
+    }
+
     /**
      * Adds a new repository to the current list, or replaces the repository 
definition with
      * the same id, if it exists already.
@@ -557,50 +504,43 @@ public class RepositoryRegistry implements 
ConfigurationListener, RepositoryEven
      * @param managedRepository the new repository.
      * @throws RepositoryException if the new repository could not be saved to 
the configuration.
      */
-    public ManagedRepository putRepository( ManagedRepository 
managedRepository ) throws RepositoryException
-    {
-        rwLock.writeLock( ).lock( );
-        try
-        {
+    public ManagedRepository putRepository(ManagedRepository 
managedRepository) throws RepositoryException {
+        rwLock.writeLock().lock();
+        try {
             final String id = managedRepository.getId();
-            if (remoteRepositories.containsKey( id )) {
-                throw new RepositoryException( "There exists a remote 
repository with id "+id+". Could not update with managed repository." );
+            if (remoteRepositories.containsKey(id)) {
+                throw new RepositoryException("There exists a remote 
repository with id " + id + ". Could not update with managed repository.");
             }
 
-            ManagedRepository originRepo = managedRepositories.put( id, 
managedRepository );
-            try
-            {
-                if (originRepo!=null) {
+            ManagedRepository originRepo = managedRepositories.put(id, 
managedRepository);
+            try {
+                if (originRepo != null) {
                     originRepo.close();
                 }
-                RepositoryProvider provider = getProvider( 
managedRepository.getType() );
-                ManagedRepositoryConfiguration newCfg = 
provider.getManagedConfiguration( managedRepository );
-                Configuration configuration = getArchivaConfiguration( 
).getConfiguration( );
-                updateRepositoryReferences( provider, managedRepository, 
newCfg, configuration );
-                ManagedRepositoryConfiguration oldCfg = 
configuration.findManagedRepositoryById( id );
-                if (oldCfg!=null) {
-                    configuration.removeManagedRepository( oldCfg );
+                RepositoryProvider provider = 
getProvider(managedRepository.getType());
+                ManagedRepositoryConfiguration newCfg = 
provider.getManagedConfiguration(managedRepository);
+                Configuration configuration = 
getArchivaConfiguration().getConfiguration();
+                updateRepositoryReferences(provider, managedRepository, 
newCfg, configuration);
+                ManagedRepositoryConfiguration oldCfg = 
configuration.findManagedRepositoryById(id);
+                if (oldCfg != null) {
+                    configuration.removeManagedRepository(oldCfg);
                 }
-                configuration.addManagedRepository( newCfg );
-                getArchivaConfiguration( ).save( configuration );
+                configuration.addManagedRepository(newCfg);
+                saveConfiguration(configuration);
+                pushEvent(new 
LifecycleEvent(LifecycleEvent.LifecycleEventType.REGISTERED, this, 
managedRepository));
                 return managedRepository;
-            }
-            catch ( Exception e )
-            {
+            } catch (Exception e) {
                 // Rollback
-                if ( originRepo != null )
-                {
-                    managedRepositories.put( id, originRepo );
+                if (originRepo != null) {
+                    managedRepositories.put(id, originRepo);
                 } else {
                     managedRepositories.remove(id);
                 }
                 log.error("Exception during configuration update {}", 
e.getMessage(), e);
-                throw new RepositoryException( "Could not save the 
configuration" + (e.getMessage( )==null?"":": "+e.getMessage()) );
+                throw new RepositoryException("Could not save the 
configuration" + (e.getMessage() == null ? "" : ": " + e.getMessage()));
             }
-        }
-        finally
-        {
-            rwLock.writeLock( ).unlock( );
+        } finally {
+            rwLock.writeLock().unlock();
         }
     }
 
@@ -612,34 +552,27 @@ public class RepositoryRegistry implements 
ConfigurationListener, RepositoryEven
      * @return the updated or created repository
      * @throws RepositoryException if an error occurs, or the configuration is 
not valid.
      */
-    public ManagedRepository putRepository( ManagedRepositoryConfiguration 
managedRepositoryConfiguration) throws RepositoryException
-    {
-        rwLock.writeLock( ).lock( );
-        try
-        {
+    public ManagedRepository putRepository(ManagedRepositoryConfiguration 
managedRepositoryConfiguration) throws RepositoryException {
+        rwLock.writeLock().lock();
+        try {
             final String id = managedRepositoryConfiguration.getId();
-            final RepositoryType repositoryType = RepositoryType.valueOf( 
managedRepositoryConfiguration.getType() );
+            final RepositoryType repositoryType = 
RepositoryType.valueOf(managedRepositoryConfiguration.getType());
             Configuration configuration = 
getArchivaConfiguration().getConfiguration();
             ManagedRepository repo = managedRepositories.get(id);
-            ManagedRepositoryConfiguration oldCfg = repo!=null ? getProvider( 
repositoryType ).getManagedConfiguration( repo ) : null;
-            repo = putRepository( managedRepositoryConfiguration, 
configuration );
-            try
-            {
-                getArchivaConfiguration().save(configuration);
-            }
-            catch ( IndeterminateConfigurationException | RegistryException e )
-            {
-                if (oldCfg!=null) {
-                    getProvider( repositoryType ).updateManagedInstance( 
(EditableManagedRepository)repo, oldCfg );
+            ManagedRepositoryConfiguration oldCfg = repo != null ? 
getProvider(repositoryType).getManagedConfiguration(repo) : null;
+            repo = putRepository(managedRepositoryConfiguration, 
configuration);
+            try {
+                saveConfiguration(configuration);
+            } catch (IndeterminateConfigurationException | RegistryException 
e) {
+                if (oldCfg != null) {
+                    
getProvider(repositoryType).updateManagedInstance((EditableManagedRepository) 
repo, oldCfg);
                 }
-                log.error("Could not save the configuration for repository {}: 
{}", id, e.getMessage(),e );
-                throw new RepositoryException( "Could not save the 
configuration for repository "+id+": "+e.getMessage() );
+                log.error("Could not save the configuration for repository {}: 
{}", id, e.getMessage(), e);
+                throw new RepositoryException("Could not save the 
configuration for repository " + id + ": " + e.getMessage());
             }
             return repo;
-        }
-        finally
-        {
-            rwLock.writeLock( ).unlock( );
+        } finally {
+            rwLock.writeLock().unlock();
         }
 
     }
@@ -649,40 +582,35 @@ public class RepositoryRegistry implements 
ConfigurationListener, RepositoryEven
      * the configuration is not saved.
      *
      * @param managedRepositoryConfiguration the new or changed repository 
configuration
-     * @param configuration the configuration object
+     * @param configuration                  the configuration object
      * @return the new or updated repository
      * @throws RepositoryException if the configuration cannot be saved or 
updated
      */
-    @SuppressWarnings( "unchecked" )
-    public ManagedRepository putRepository( ManagedRepositoryConfiguration 
managedRepositoryConfiguration, Configuration configuration) throws 
RepositoryException
-    {
-        rwLock.writeLock( ).lock( );
-        try
-        {
+    @SuppressWarnings("unchecked")
+    public ManagedRepository putRepository(ManagedRepositoryConfiguration 
managedRepositoryConfiguration, Configuration configuration) throws 
RepositoryException {
+        rwLock.writeLock().lock();
+        try {
             final String id = managedRepositoryConfiguration.getId();
-            final RepositoryType repoType = RepositoryType.valueOf( 
managedRepositoryConfiguration.getType() );
+            final RepositoryType repoType = 
RepositoryType.valueOf(managedRepositoryConfiguration.getType());
             ManagedRepository repo;
-            if (managedRepositories.containsKey( id )) {
+            if (managedRepositories.containsKey(id)) {
                 repo = managedRepositories.get(id);
-                if (repo instanceof EditableManagedRepository)
-                {
-                    getProvider( repoType ).updateManagedInstance( 
(EditableManagedRepository) repo, managedRepositoryConfiguration );
+                if (repo instanceof EditableManagedRepository) {
+                    
getProvider(repoType).updateManagedInstance((EditableManagedRepository) repo, 
managedRepositoryConfiguration);
                 } else {
-                    throw new RepositoryException( "The repository is not 
editable "+id );
+                    throw new RepositoryException("The repository is not 
editable " + id);
                 }
-            } else
-            {
-                repo = getProvider( repoType ).createManagedInstance( 
managedRepositoryConfiguration );
-                repo.addListener(this);
+            } else {
+                repo = 
getProvider(repoType).createManagedInstance(managedRepositoryConfiguration);
+                repo.register(this);
                 managedRepositories.put(id, repo);
             }
-            updateRepositoryReferences( getProvider( repoType  ), repo, 
managedRepositoryConfiguration, configuration );
-            replaceOrAddRepositoryConfig( managedRepositoryConfiguration, 
configuration );
+            updateRepositoryReferences(getProvider(repoType), repo, 
managedRepositoryConfiguration, configuration);
+            replaceOrAddRepositoryConfig(managedRepositoryConfiguration, 
configuration);
+            pushEvent(new 
LifecycleEvent(LifecycleEvent.LifecycleEventType.REGISTERED, this, repo));
             return repo;
-        }
-        finally
-        {
-            rwLock.writeLock( ).unlock( );
+        } finally {
+            rwLock.writeLock().unlock();
         }
     }
 
@@ -695,46 +623,38 @@ public class RepositoryRegistry implements 
ConfigurationListener, RepositoryEven
      * @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
-    {
-        rwLock.writeLock( ).lock( );
-        try
-        {
+    public RepositoryGroup putRepositoryGroup(RepositoryGroup repositoryGroup) 
throws RepositoryException {
+        rwLock.writeLock().lock();
+        try {
             final String id = repositoryGroup.getId();
-            RepositoryGroup originRepo = repositoryGroups.put( id, 
repositoryGroup );
-            try
-            {
-                if (originRepo!=null) {
+            RepositoryGroup originRepo = repositoryGroups.put(id, 
repositoryGroup);
+            try {
+                if (originRepo != null) {
                     originRepo.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 );
+                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 );
-                getArchivaConfiguration( ).save( configuration );
+                configuration.addRepositoryGroup(newCfg);
+                saveConfiguration(configuration);
                 return repositoryGroup;
-            }
-            catch ( Exception e )
-            {
+            } catch (Exception e) {
                 // Rollback
-                if ( originRepo != null )
-                {
-                    repositoryGroups.put( id, originRepo );
+                if (originRepo != null) {
+                    repositoryGroups.put(id, originRepo);
                 } 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()) );
+                throw new RepositoryException("Could not save the 
configuration" + (e.getMessage() == null ? "" : ": " + e.getMessage()));
             }
-        }
-        finally
-        {
-            rwLock.writeLock( ).unlock( );
+        } finally {
+            rwLock.writeLock().unlock();
         }
     }
 
@@ -746,34 +666,27 @@ public class RepositoryRegistry implements 
ConfigurationListener, RepositoryEven
      * @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
-    {
-        rwLock.writeLock( ).lock( );
-        try
-        {
+    public RepositoryGroup putRepositoryGroup(RepositoryGroupConfiguration 
repositoryGroupConfiguration) throws RepositoryException {
+        rwLock.writeLock().lock();
+        try {
             final String id = repositoryGroupConfiguration.getId();
-            final RepositoryType repositoryType = RepositoryType.valueOf( 
repositoryGroupConfiguration.getType() );
+            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
-            {
-                getArchivaConfiguration().save(configuration);
-            }
-            catch ( IndeterminateConfigurationException | RegistryException e )
-            {
-                if (oldCfg!=null) {
-                    getProvider( repositoryType 
).updateRepositoryGroupInstance( (EditableRepositoryGroup) repo, oldCfg );
+            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() );
+                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;
-        }
-        finally
-        {
-            rwLock.writeLock( ).unlock( );
+        } finally {
+            rwLock.writeLock().unlock();
         }
 
     }
@@ -783,41 +696,35 @@ public class RepositoryRegistry implements 
ConfigurationListener, RepositoryEven
      * the configuration is not saved.
      *
      * @param repositoryGroupConfiguration the new or changed repository 
configuration
-     * @param configuration the configuration object
+     * @param configuration                the configuration object
      * @return the new or updated repository
      * @throws RepositoryException if the configuration cannot be saved or 
updated
      */
-    @SuppressWarnings( "unchecked" )
-    public RepositoryGroup putRepositoryGroup( RepositoryGroupConfiguration 
repositoryGroupConfiguration, Configuration configuration) throws 
RepositoryException
-    {
-        rwLock.writeLock( ).lock( );
-        try
-        {
+    @SuppressWarnings("unchecked")
+    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() );
+            final RepositoryType repoType = 
RepositoryType.valueOf(repositoryGroupConfiguration.getType());
             RepositoryGroup repo;
             setRepositoryGroupDefaults(repositoryGroupConfiguration);
-            if (repositoryGroups.containsKey( id )) {
+            if (repositoryGroups.containsKey(id)) {
                 repo = repositoryGroups.get(id);
-                if (repo instanceof EditableRepositoryGroup)
-                {
-                    getProvider( repoType ).updateRepositoryGroupInstance( 
(EditableRepositoryGroup) repo, repositoryGroupConfiguration );
+                if (repo instanceof EditableRepositoryGroup) {
+                    
getProvider(repoType).updateRepositoryGroupInstance((EditableRepositoryGroup) 
repo, repositoryGroupConfiguration);
                 } else {
-                    throw new RepositoryException( "The repository is not 
editable "+id );
+                    throw new RepositoryException("The repository is not 
editable " + id);
                 }
-            } else
-            {
-                repo = getProvider( repoType ).createRepositoryGroup( 
repositoryGroupConfiguration );
-                repo.addListener(this);
+            } else {
+                repo = 
getProvider(repoType).createRepositoryGroup(repositoryGroupConfiguration);
+                repo.register(this);
                 repositoryGroups.put(id, repo);
             }
-            updateRepositoryReferences( getProvider( repoType  ), repo, 
repositoryGroupConfiguration );
-            replaceOrAddRepositoryConfig( repositoryGroupConfiguration, 
configuration );
+            updateRepositoryReferences(getProvider(repoType), repo, 
repositoryGroupConfiguration);
+            replaceOrAddRepositoryConfig(repositoryGroupConfiguration, 
configuration);
             return repo;
-        }
-        finally
-        {
-            rwLock.writeLock( ).unlock( );
+        } finally {
+            rwLock.writeLock().unlock();
         }
     }
 
@@ -825,7 +732,7 @@ public class RepositoryRegistry implements 
ConfigurationListener, RepositoryEven
         if 
(StringUtils.isEmpty(repositoryGroupConfiguration.getMergedIndexPath())) {
             
repositoryGroupConfiguration.setMergedIndexPath(DEFAULT_INDEX_PATH);
         }
-        if (repositoryGroupConfiguration.getMergedIndexTtl()<=0) {
+        if (repositoryGroupConfiguration.getMergedIndexTtl() <= 0) {
             repositoryGroupConfiguration.setMergedIndexTtl(300);
         }
         if 
(StringUtils.isEmpty(repositoryGroupConfiguration.getCronExpression())) {
@@ -834,79 +741,72 @@ public class RepositoryRegistry implements 
ConfigurationListener, RepositoryEven
     }
 
     private void replaceOrAddRepositoryConfig(ManagedRepositoryConfiguration 
managedRepositoryConfiguration, Configuration configuration) {
-        ManagedRepositoryConfiguration oldCfg = 
configuration.findManagedRepositoryById( managedRepositoryConfiguration.getId() 
);
-        if ( oldCfg !=null) {
-            configuration.removeManagedRepository( oldCfg );
+        ManagedRepositoryConfiguration oldCfg = 
configuration.findManagedRepositoryById(managedRepositoryConfiguration.getId());
+        if (oldCfg != null) {
+            configuration.removeManagedRepository(oldCfg);
         }
-        configuration.addManagedRepository( managedRepositoryConfiguration );
+        configuration.addManagedRepository(managedRepositoryConfiguration);
     }
 
     private void replaceOrAddRepositoryConfig(RemoteRepositoryConfiguration 
remoteRepositoryConfiguration, Configuration configuration) {
-        RemoteRepositoryConfiguration oldCfg = 
configuration.findRemoteRepositoryById( remoteRepositoryConfiguration.getId() );
-        if ( oldCfg !=null) {
-            configuration.removeRemoteRepository( oldCfg );
+        RemoteRepositoryConfiguration oldCfg = 
configuration.findRemoteRepositoryById(remoteRepositoryConfiguration.getId());
+        if (oldCfg != null) {
+            configuration.removeRemoteRepository(oldCfg);
         }
-        configuration.addRemoteRepository( remoteRepositoryConfiguration );
+        configuration.addRemoteRepository(remoteRepositoryConfiguration);
     }
 
     private void replaceOrAddRepositoryConfig(RepositoryGroupConfiguration 
repositoryGroupConfiguration, Configuration configuration) {
-        RepositoryGroupConfiguration oldCfg = 
configuration.findRepositoryGroupById( repositoryGroupConfiguration.getId() );
-        if ( oldCfg !=null) {
-            configuration.removeRepositoryGroup( oldCfg );
+        RepositoryGroupConfiguration oldCfg = 
configuration.findRepositoryGroupById(repositoryGroupConfiguration.getId());
+        if (oldCfg != null) {
+            configuration.removeRepositoryGroup(oldCfg);
         }
-        configuration.addRepositoryGroup( repositoryGroupConfiguration);
+        configuration.addRepositoryGroup(repositoryGroupConfiguration);
     }
 
-    public RemoteRepository putRepository( RemoteRepository remoteRepository, 
Configuration configuration) throws RepositoryException
-    {
-        rwLock.writeLock( ).lock( );
-        try
-        {
+    public RemoteRepository putRepository(RemoteRepository remoteRepository, 
Configuration configuration) throws RepositoryException {
+        rwLock.writeLock().lock();
+        try {
             final String id = remoteRepository.getId();
-            if (managedRepositories.containsKey( id )) {
-                throw new RepositoryException( "There exists a managed 
repository with id "+id+". Could not update with remote repository." );
+            if (managedRepositories.containsKey(id)) {
+                throw new RepositoryException("There exists a managed 
repository with id " + id + ". Could not update with remote repository.");
             }
-            RemoteRepository originRepo = remoteRepositories.put( id, 
remoteRepository );
-            RemoteRepositoryConfiguration oldCfg=null;
+            RemoteRepository originRepo = remoteRepositories.put(id, 
remoteRepository);
+            RemoteRepositoryConfiguration oldCfg = null;
             RemoteRepositoryConfiguration newCfg;
-            try
-            {
-                if (originRepo!=null) {
+            try {
+                if (originRepo != null) {
                     originRepo.close();
                 }
-                final RepositoryProvider provider = getProvider( 
remoteRepository.getType() );
-                newCfg = provider.getRemoteConfiguration( remoteRepository );
-                updateRepositoryReferences( provider, remoteRepository, 
newCfg, configuration );
-                oldCfg = configuration.findRemoteRepositoryById( id );
-                if (oldCfg!=null) {
-                    configuration.removeRemoteRepository( oldCfg );
+                final RepositoryProvider provider = 
getProvider(remoteRepository.getType());
+                newCfg = provider.getRemoteConfiguration(remoteRepository);
+                updateRepositoryReferences(provider, remoteRepository, newCfg, 
configuration);
+                oldCfg = configuration.findRemoteRepositoryById(id);
+                if (oldCfg != null) {
+                    configuration.removeRemoteRepository(oldCfg);
                 }
-                configuration.addRemoteRepository( newCfg );
+                configuration.addRemoteRepository(newCfg);
+                pushEvent(new 
LifecycleEvent(LifecycleEvent.LifecycleEventType.REGISTERED, this, 
remoteRepository));
                 return remoteRepository;
-            }
-            catch ( Exception e )
-            {
+            } catch (Exception e) {
                 // Rollback
-                if ( originRepo != null )
-                {
-                    remoteRepositories.put( id, originRepo );
+                if (originRepo != null) {
+                    remoteRepositories.put(id, originRepo);
                 } else {
-                    remoteRepositories.remove( id);
+                    remoteRepositories.remove(id);
                 }
-                if (oldCfg!=null) {
-                    RemoteRepositoryConfiguration cfg = 
configuration.findRemoteRepositoryById( id );
-                    if (cfg!=null) {
-                        configuration.removeRemoteRepository( cfg );
-                        configuration.addRemoteRepository( oldCfg );
+                if (oldCfg != null) {
+                    RemoteRepositoryConfiguration cfg = 
configuration.findRemoteRepositoryById(id);
+                    if (cfg != null) {
+                        configuration.removeRemoteRepository(cfg);
+                        configuration.addRemoteRepository(oldCfg);
                     }
                 }
                 log.error("Error while adding remote repository {}", 
e.getMessage(), e);
-                throw new RepositoryException( "Could not save the 
configuration" + (e.getMessage( )==null?"":": "+e.getMessage()) );
+                throw new RepositoryException("Could not save the 
configuration" + (e.getMessage() == null ? "" : ": " + e.getMessage()));
             }
-        }
-        finally
-        {
-            rwLock.writeLock( ).unlock( );
+        } finally {
+            rwLock.writeLock().unlock();
         }
     }
 
@@ -917,27 +817,20 @@ public class RepositoryRegistry implements 
ConfigurationListener, RepositoryEven
      * @param remoteRepository the remote repository to add
      * @throws RepositoryException if an error occurs during configuration save
      */
-    public RemoteRepository putRepository( RemoteRepository remoteRepository ) 
throws RepositoryException
-    {
-        rwLock.writeLock( ).lock( );
-        try
-        {
+    public RemoteRepository putRepository(RemoteRepository remoteRepository) 
throws RepositoryException {
+        rwLock.writeLock().lock();
+        try {
             Configuration configuration = 
getArchivaConfiguration().getConfiguration();
-            try
-            {
-                RemoteRepository repo = putRepository( remoteRepository, 
configuration );
-                getArchivaConfiguration().save(configuration);
+            try {
+                RemoteRepository repo = putRepository(remoteRepository, 
configuration);
+                saveConfiguration(configuration);
                 return repo;
-            }
-            catch ( RegistryException | IndeterminateConfigurationException e )
-            {
+            } catch (RegistryException | IndeterminateConfigurationException 
e) {
                 log.error("Error while saving remote repository {}", 
e.getMessage(), e);
-                throw new RepositoryException( "Could not save the 
configuration" + (e.getMessage( )==null?"":": "+e.getMessage()) );
+                throw new RepositoryException("Could not save the 
configuration" + (e.getMessage() == null ? "" : ": " + e.getMessage()));
             }
-        }
-        finally
-        {
-            rwLock.writeLock( ).unlock( );
+        } finally {
+            rwLock.writeLock().unlock();
         }
     }
 
@@ -949,34 +842,27 @@ public class RepositoryRegistry implements 
ConfigurationListener, RepositoryEven
      * @return the updated or created repository
      * @throws RepositoryException if an error occurs, or the configuration is 
not valid.
      */
-    public RemoteRepository putRepository( RemoteRepositoryConfiguration 
remoteRepositoryConfiguration) throws RepositoryException
-    {
-        rwLock.writeLock( ).lock( );
-        try
-        {
+    public RemoteRepository putRepository(RemoteRepositoryConfiguration 
remoteRepositoryConfiguration) throws RepositoryException {
+        rwLock.writeLock().lock();
+        try {
             final String id = remoteRepositoryConfiguration.getId();
-            final RepositoryType repositoryType = RepositoryType.valueOf( 
remoteRepositoryConfiguration.getType() );
+            final RepositoryType repositoryType = 
RepositoryType.valueOf(remoteRepositoryConfiguration.getType());
             Configuration configuration = 
getArchivaConfiguration().getConfiguration();
             RemoteRepository repo = remoteRepositories.get(id);
-            RemoteRepositoryConfiguration oldCfg = repo!=null ? getProvider( 
repositoryType ).getRemoteConfiguration( repo ) : null;
-            repo = putRepository( remoteRepositoryConfiguration, configuration 
);
-            try
-            {
-                getArchivaConfiguration().save(configuration);
-            }
-            catch ( IndeterminateConfigurationException | RegistryException e )
-            {
-                if (oldCfg!=null) {
-                    getProvider( repositoryType ).updateRemoteInstance( 
(EditableRemoteRepository)repo, oldCfg );
+            RemoteRepositoryConfiguration oldCfg = repo != null ? 
getProvider(repositoryType).getRemoteConfiguration(repo) : null;
+            repo = putRepository(remoteRepositoryConfiguration, configuration);
+            try {
+                saveConfiguration(configuration);
+            } catch (IndeterminateConfigurationException | RegistryException 
e) {
+                if (oldCfg != null) {
+                    
getProvider(repositoryType).updateRemoteInstance((EditableRemoteRepository) 
repo, oldCfg);
                 }
-                log.error("Could not save the configuration for repository {}: 
{}", id, e.getMessage(),e );
-                throw new RepositoryException( "Could not save the 
configuration for repository "+id+": "+e.getMessage() );
+                log.error("Could not save the configuration for repository {}: 
{}", id, e.getMessage(), e);
+                throw new RepositoryException("Could not save the 
configuration for repository " + id + ": " + e.getMessage());
             }
             return repo;
-        }
-        finally
-        {
-            rwLock.writeLock( ).unlock( );
+        } finally {
+            rwLock.writeLock().unlock();
         }
 
     }
@@ -986,40 +872,35 @@ public class RepositoryRegistry implements 
ConfigurationListener, RepositoryEven
      * the configuration is not saved.
      *
      * @param remoteRepositoryConfiguration the new or changed repository 
configuration
-     * @param configuration the configuration object
+     * @param configuration                 the configuration object
      * @return the new or updated repository
      * @throws RepositoryException if the configuration cannot be saved or 
updated
      */
-    @SuppressWarnings( "unchecked" )
-    public RemoteRepository putRepository( RemoteRepositoryConfiguration 
remoteRepositoryConfiguration, Configuration configuration) throws 
RepositoryException
-    {
-        rwLock.writeLock( ).lock( );
-        try
-        {
+    @SuppressWarnings("unchecked")
+    public RemoteRepository putRepository(RemoteRepositoryConfiguration 
remoteRepositoryConfiguration, Configuration configuration) throws 
RepositoryException {
+        rwLock.writeLock().lock();
+        try {
             final String id = remoteRepositoryConfiguration.getId();
-            final RepositoryType repoType = RepositoryType.valueOf( 
remoteRepositoryConfiguration.getType() );
+            final RepositoryType repoType = 
RepositoryType.valueOf(remoteRepositoryConfiguration.getType());
             RemoteRepository repo;
-            if (remoteRepositories.containsKey( id )) {
+            if (remoteRepositories.containsKey(id)) {
                 repo = remoteRepositories.get(id);
-                if (repo instanceof EditableRemoteRepository)
-                {
-                    getProvider( repoType ).updateRemoteInstance( 
(EditableRemoteRepository) repo, remoteRepositoryConfiguration );
+                if (repo instanceof EditableRemoteRepository) {
+                    
getProvider(repoType).updateRemoteInstance((EditableRemoteRepository) repo, 
remoteRepositoryConfiguration);
                 } else {
-                    throw new RepositoryException( "The repository is not 
editable "+id );
+                    throw new RepositoryException("The repository is not 
editable " + id);
                 }
-            } else
-            {
-                repo = getProvider( repoType ).createRemoteInstance( 
remoteRepositoryConfiguration );
-                repo.addListener(this);
+            } else {
+                repo = 
getProvider(repoType).createRemoteInstance(remoteRepositoryConfiguration);
+                repo.register(this);
                 remoteRepositories.put(id, repo);
             }
-            updateRepositoryReferences( getProvider( repoType  ), repo, 
remoteRepositoryConfiguration, configuration );
-            replaceOrAddRepositoryConfig( remoteRepositoryConfiguration, 
configuration );
+            updateRepositoryReferences(getProvider(repoType), repo, 
remoteRepositoryConfiguration, configuration);
+            replaceOrAddRepositoryConfig(remoteRepositoryConfiguration, 
configuration);
+            pushEvent(new 
LifecycleEvent(LifecycleEvent.LifecycleEventType.REGISTERED, this, repo));
             return repo;
-        }
-        finally
-        {
-            rwLock.writeLock( ).unlock( );
+        } finally {
+            rwLock.writeLock().unlock();
         }
 
 
@@ -1027,26 +908,25 @@ public class RepositoryRegistry implements 
ConfigurationListener, RepositoryEven
 
     public void removeRepository(String repoId) throws RepositoryException {
         Repository repo = getRepository(repoId);
-        if (repo!=null) {
+        if (repo != null) {
             removeRepository(repo);
         }
     }
 
-    @SuppressWarnings( "unchecked" )
-    public void removeRepository(Repository repo) throws RepositoryException
-    {
-        if (repo==null) {
+    @SuppressWarnings("unchecked")
+    public void removeRepository(Repository repo) throws RepositoryException {
+        if (repo == null) {
             log.warn("Trying to remove null repository");
             return;
         }
-        if (repo instanceof RemoteRepository ) {
-            removeRepository( (RemoteRepository)repo );
+        if (repo instanceof RemoteRepository) {
+            removeRepository((RemoteRepository) repo);
         } else if (repo instanceof ManagedRepository) {
-            removeRepository( (ManagedRepository)repo);
-        } else if (repo instanceof RepositoryGroup ) {
+            removeRepository((ManagedRepository) repo);
+        } else if (repo instanceof RepositoryGroup) {
             removeRepositoryGroup((RepositoryGroup) repo);
-        }else {
-            throw new RepositoryException( "Repository type not known: 
"+repo.getClass() );
+        } else {
+            throw new RepositoryException("Repository type not known: " + 
repo.getClass());
         }
     }
 
@@ -1057,64 +937,59 @@ public class RepositoryRegistry implements 
ConfigurationListener, RepositoryEven
      * @param managedRepository the managed repository to remove
      * @throws RepositoryException if a error occurs during configuration save
      */
-    public void removeRepository( ManagedRepository managedRepository ) throws 
RepositoryException
-    {
+    public void removeRepository(ManagedRepository managedRepository) throws 
RepositoryException {
         final String id = managedRepository.getId();
-        ManagedRepository repo = getManagedRepository( id );
-        if (repo!=null) {
+        ManagedRepository repo = getManagedRepository(id);
+        if (repo != null) {
             rwLock.writeLock().lock();
             try {
-                repo = managedRepositories.remove( id );
-                if (repo!=null) {
+                repo = managedRepositories.remove(id);
+                if (repo != null) {
                     repo.close();
                     removeRepositoryFromGroups(repo);
                     Configuration configuration = 
getArchivaConfiguration().getConfiguration();
-                    ManagedRepositoryConfiguration cfg = 
configuration.findManagedRepositoryById( id );
-                    if (cfg!=null) {
-                        configuration.removeManagedRepository( cfg );
+                    ManagedRepositoryConfiguration cfg = 
configuration.findManagedRepositoryById(id);
+                    if (cfg != null) {
+                        configuration.removeManagedRepository(cfg);
                     }
-                    getArchivaConfiguration().save( configuration );
+                    saveConfiguration(configuration);
                 }
-
-            }
-            catch ( RegistryException | IndeterminateConfigurationException e )
-            {
+                pushEvent(new 
LifecycleEvent(LifecycleEvent.LifecycleEventType.UNREGISTERED, this, repo));
+            } catch (RegistryException | IndeterminateConfigurationException 
e) {
                 // Rollback
                 log.error("Could not save config after repository removal: 
{}", e.getMessage(), e);
                 managedRepositories.put(repo.getId(), repo);
-                throw new RepositoryException( "Could not save configuration 
after repository removal: "+e.getMessage() );
-            } finally
-            {
+                throw new RepositoryException("Could not save configuration 
after repository removal: " + e.getMessage());
+            } finally {
                 rwLock.writeLock().unlock();
             }
         }
     }
 
     private void removeRepositoryFromGroups(ManagedRepository repo) {
-        if (repo!=null) {
+        if (repo != null) {
             repositoryGroups.values().stream().filter(repoGroup -> repoGroup 
instanceof EditableRepository).
                     map(repoGroup -> (EditableRepositoryGroup) 
repoGroup).forEach(repoGroup -> repoGroup.removeRepository(repo));
         }
     }
 
-    public void removeRepository(ManagedRepository managedRepository, 
Configuration configuration) throws RepositoryException
-    {
+    public void removeRepository(ManagedRepository managedRepository, 
Configuration configuration) throws RepositoryException {
         final String id = managedRepository.getId();
-        ManagedRepository repo = getManagedRepository( id );
-        if (repo!=null) {
+        ManagedRepository repo = getManagedRepository(id);
+        if (repo != null) {
             rwLock.writeLock().lock();
             try {
-                repo = managedRepositories.remove( id );
-                if (repo!=null) {
+                repo = managedRepositories.remove(id);
+                if (repo != null) {
                     repo.close();
                     removeRepositoryFromGroups(repo);
-                    ManagedRepositoryConfiguration cfg = 
configuration.findManagedRepositoryById( id );
-                    if (cfg!=null) {
-                        configuration.removeManagedRepository( cfg );
+                    ManagedRepositoryConfiguration cfg = 
configuration.findManagedRepositoryById(id);
+                    if (cfg != null) {
+                        configuration.removeManagedRepository(cfg);
                     }
                 }
-            } finally
-            {
+                pushEvent(new 
LifecycleEvent(LifecycleEvent.LifecycleEventType.UNREGISTERED, this, repo));
+            } finally {
                 rwLock.writeLock().unlock();
             }
         }
@@ -1129,55 +1004,49 @@ public class RepositoryRegistry implements 
ConfigurationListener, RepositoryEven
      * @param repositoryGroup the repository group to remove
      * @throws RepositoryException if a error occurs during configuration save
      */
-    public void removeRepositoryGroup( RepositoryGroup repositoryGroup ) 
throws RepositoryException
-    {
+    public void removeRepositoryGroup(RepositoryGroup repositoryGroup) throws 
RepositoryException {
         final String id = repositoryGroup.getId();
-        RepositoryGroup repo = getRepositoryGroup( id );
-        if (repo!=null) {
+        RepositoryGroup repo = getRepositoryGroup(id);
+        if (repo != null) {
             rwLock.writeLock().lock();
             try {
-                repo = repositoryGroups.remove( id );
-                if (repo!=null) {
+                repo = repositoryGroups.remove(id);
+                if (repo != null) {
                     repo.close();
                     Configuration configuration = 
getArchivaConfiguration().getConfiguration();
-                    RepositoryGroupConfiguration cfg = 
configuration.findRepositoryGroupById( id );
-                    if (cfg!=null) {
-                        configuration.removeRepositoryGroup( cfg );
+                    RepositoryGroupConfiguration cfg = 
configuration.findRepositoryGroupById(id);
+                    if (cfg != null) {
+                        configuration.removeRepositoryGroup(cfg);
                     }
-                    getArchivaConfiguration().save( configuration );
+                    saveConfiguration(configuration);
                 }
 
-            }
-            catch ( RegistryException | IndeterminateConfigurationException e )
-            {
+            } catch (RegistryException | IndeterminateConfigurationException 
e) {
                 // Rollback
                 log.error("Could not save config after repository removal: 
{}", e.getMessage(), e);
                 repositoryGroups.put(repo.getId(), repo);
-                throw new RepositoryException( "Could not save configuration 
after repository removal: "+e.getMessage() );
-            } finally
-            {
+                throw new RepositoryException("Could not save configuration 
after repository removal: " + e.getMessage());
+            } finally {
                 rwLock.writeLock().unlock();
             }
         }
     }
 
-    public void removeRepositoryGroup(RepositoryGroup repositoryGroup, 
Configuration configuration) throws RepositoryException
-    {
+    public void removeRepositoryGroup(RepositoryGroup repositoryGroup, 
Configuration configuration) throws RepositoryException {
         final String id = repositoryGroup.getId();
-        RepositoryGroup repo = getRepositoryGroup( id );
-        if (repo!=null) {
+        RepositoryGroup repo = getRepositoryGroup(id);
+        if (repo != null) {
             rwLock.writeLock().lock();
             try {
-                repo = repositoryGroups.remove( id );
-                if (repo!=null) {
+                repo = repositoryGroups.remove(id);
+                if (repo != null) {
                     repo.close();
-                    RepositoryGroupConfiguration cfg = 
configuration.findRepositoryGroupById( id );
-                    if (cfg!=null) {
-                        configuration.removeRepositoryGroup( cfg );
+                    RepositoryGroupConfiguration cfg = 
configuration.findRepositoryGroupById(id);
+                    if (cfg != null) {
+                        configuration.removeRepositoryGroup(cfg);
                     }
                 }
-            } finally
-            {
+            } finally {
                 rwLock.writeLock().unlock();
             }
         }
@@ -1185,17 +1054,17 @@ public class RepositoryRegistry implements 
ConfigurationListener, RepositoryEven
     }
 
     private void doRemoveRepo(RemoteRepository repo, Configuration 
configuration) {
-            repo.close();
-            RemoteRepositoryConfiguration cfg = 
configuration.findRemoteRepositoryById(repo.getId());
-            if (cfg != null) {
-                configuration.removeRemoteRepository(cfg);
-            }
-            List<ProxyConnectorConfiguration> proxyConnectors = new 
ArrayList<>(configuration.getProxyConnectors());
-            for (ProxyConnectorConfiguration proxyConnector : proxyConnectors) 
{
-                if (StringUtils.equals(proxyConnector.getTargetRepoId(), 
repo.getId())) {
-                    configuration.removeProxyConnector(proxyConnector);
-                }
+        repo.close();
+        RemoteRepositoryConfiguration cfg = 
configuration.findRemoteRepositoryById(repo.getId());
+        if (cfg != null) {
+            configuration.removeRemoteRepository(cfg);
+        }
+        List<ProxyConnectorConfiguration> proxyConnectors = new 
ArrayList<>(configuration.getProxyConnectors());
+        for (ProxyConnectorConfiguration proxyConnector : proxyConnectors) {
+            if (StringUtils.equals(proxyConnector.getTargetRepoId(), 
repo.getId())) {
+                configuration.removeProxyConnector(proxyConnector);
             }
+        }
     }
 
     /**
@@ -1205,47 +1074,43 @@ public class RepositoryRegistry implements 
ConfigurationListener, RepositoryEven
      * @param remoteRepository the remote repository to remove
      * @throws RepositoryException if a error occurs during configuration save
      */
-    public void removeRepository( RemoteRepository remoteRepository ) throws 
RepositoryException
-    {
+    public void removeRepository(RemoteRepository remoteRepository) throws 
RepositoryException {
 
         final String id = remoteRepository.getId();
-        RemoteRepository repo = getRemoteRepository( id );
-        if (repo!=null) {
+        RemoteRepository repo = getRemoteRepository(id);
+        if (repo != null) {
             rwLock.writeLock().lock();
             try {
-                repo = remoteRepositories.remove( id );
-                if (repo!=null) {
+                repo = remoteRepositories.remove(id);
+                if (repo != null) {
                     Configuration configuration = 
getArchivaConfiguration().getConfiguration();
                     doRemoveRepo(repo, configuration);
-                    getArchivaConfiguration().save( configuration );
+                    saveConfiguration(configuration);
                 }
-            }
-            catch ( RegistryException | IndeterminateConfigurationException e )
-            {
+                pushEvent(new 
LifecycleEvent(LifecycleEvent.LifecycleEventType.UNREGISTERED, this, repo));
+            } catch (RegistryException | IndeterminateConfigurationException 
e) {
                 // Rollback
                 log.error("Could not save config after repository removal: 
{}", e.getMessage(), e);
                 remoteRepositories.put(repo.getId(), repo);
-                throw new RepositoryException( "Could not save configuration 
after repository removal: "+e.getMessage() );
-            } finally
-            {
+                throw new RepositoryException("Could not save configuration 
after repository removal: " + e.getMessage());
+            } finally {
                 rwLock.writeLock().unlock();
             }
         }
     }
 
-    public void removeRepository( RemoteRepository remoteRepository, 
Configuration configuration) throws RepositoryException
-    {
+    public void removeRepository(RemoteRepository remoteRepository, 
Configuration configuration) throws RepositoryException {
         final String id = remoteRepository.getId();
-        RemoteRepository repo = getRemoteRepository( id );
-        if (repo!=null) {
+        RemoteRepository repo = getRemoteRepository(id);
+        if (repo != null) {
             rwLock.writeLock().lock();
             try {
-                repo = remoteRepositories.remove( id );
-                if (repo!=null) {
+                repo = remoteRepositories.remove(id);
+                if (repo != null) {
                     doRemoveRepo(repo, configuration);
                 }
-            } finally
-            {
+                pushEvent(new 
LifecycleEvent(LifecycleEvent.LifecycleEventType.UNREGISTERED, this, repo));
+            } finally {
                 rwLock.writeLock().unlock();
             }
         }
@@ -1265,7 +1130,7 @@ public class RepositoryRegistry implements 
ConfigurationListener, RepositoryEven
      * @param repo
      * @throws IndexUpdateFailedException
      */
-    @SuppressWarnings( "unchecked" )
+    @SuppressWarnings("unchecked")
     public void resetIndexingContext(Repository repo) throws 
IndexUpdateFailedException {
         if (repo.hasIndex() && repo instanceof EditableRepository) {
             EditableRepository eRepo = (EditableRepository) repo;
@@ -1282,27 +1147,26 @@ public class RepositoryRegistry implements 
ConfigurationListener, RepositoryEven
      * @param repo The origin repository
      * @return The cloned repository.
      */
-    public ManagedRepository clone(ManagedRepository repo, String newId) 
throws RepositoryException
-    {
+    public ManagedRepository clone(ManagedRepository repo, String newId) 
throws RepositoryException {
         if (managedRepositories.containsKey(newId) || 
remoteRepositories.containsKey(newId)) {
-            throw new RepositoryException("The given id exists already 
"+newId);
+            throw new RepositoryException("The given id exists already " + 
newId);
         }
         RepositoryProvider provider = getProvider(repo.getType());
         ManagedRepositoryConfiguration cfg = 
provider.getManagedConfiguration(repo);
         cfg.setId(newId);
         ManagedRepository cloned = provider.createManagedInstance(cfg);
-        cloned.addListener(this);
+        cloned.register(this);
         return cloned;
     }
 
-    @SuppressWarnings( "unchecked" )
+    @SuppressWarnings("unchecked")
     public <T extends Repository> Repository clone(T repo, String newId) 
throws RepositoryException {
-        if (repo instanceof RemoteRepository ) {
-            return this.clone((RemoteRepository)repo, newId);
+        if (repo instanceof RemoteRepository) {
+            return this.clone((RemoteRepository) repo, newId);
         } else if (repo instanceof ManagedRepository) {
-            return this.clone((ManagedRepository)repo, newId);
+            return this.clone((ManagedRepository) repo, newId);
         } else {
-            throw new RepositoryException("This repository class is not 
supported "+ repo.getClass().getName());
+            throw new RepositoryException("This repository class is not 
supported " + repo.getClass().getName());
         }
     }
 
@@ -1313,51 +1177,83 @@ public class RepositoryRegistry implements 
ConfigurationListener, RepositoryEven
      * @param repo The origin repository
      * @return The cloned repository.
      */
-    public RemoteRepository clone( RemoteRepository repo, String newId) throws 
RepositoryException
-    {
+    public RemoteRepository clone(RemoteRepository repo, String newId) throws 
RepositoryException {
         if (managedRepositories.containsKey(newId) || 
remoteRepositories.containsKey(newId)) {
-            throw new RepositoryException("The given id exists already 
"+newId);
+            throw new RepositoryException("The given id exists already " + 
newId);
         }
         RepositoryProvider provider = getProvider(repo.getType());
         RemoteRepositoryConfiguration cfg = 
provider.getRemoteConfiguration(repo);
         cfg.setId(newId);
         RemoteRepository cloned = provider.createRemoteInstance(cfg);
-        cloned.addListener(this);
+        cloned.register(this);
         return cloned;
     }
 
 
     @Override
     public void configurationEvent(ConfigurationEvent event) {
-
+        // Note: the ignoreConfigEvents flag does not work, if the config 
events are asynchronous.
+        if (!ignoreConfigEvents) {
+            reload();
+        }
     }
 
 
     @Override
-    public void addListener(RepositoryEventListener listener) {
+    public void register(RepositoryEventListener listener) {
         if (!this.listeners.contains(listener)) {
             this.listeners.add(listener);
         }
     }
 
     @Override
-    public void removeListener(RepositoryEventListener listener) {
+    public void register(RepositoryEventListener listener, EventType type) {
+        List<RepositoryEventListener> listeners;
+        if (typeListenerMap.containsKey(type)) {
+            listeners = typeListenerMap.get(type);
+        } else {
+            listeners = new ArrayList<>();
+            typeListenerMap.put(type, listeners);
+        }
+        if (!listeners.contains(listener)) {
+            listeners.add(listener);
+        }
+    }
+
+    @Override
+    public void register(RepositoryEventListener listener, Set<? extends 
EventType> types) {
+        for (EventType type : types) {
+            register(listener, type);
+        }
+    }
+
+    @Override
+    public void unregister(RepositoryEventListener listener) {
         this.listeners.remove(listener);
+        for (List<RepositoryEventListener> listeners : 
typeListenerMap.values()) {
+            listeners.remove(listener);
+        }
     }
 
     @Override
     public void clearListeners() {
         this.listeners.clear();
+        this.typeListenerMap.clear();
     }
 
-    @SuppressWarnings( "unchecked" )
+    @SuppressWarnings("unchecked")
     @Override
-    public <T> void raise(RepositoryEvent<T> event) {
-        if (event instanceof IndexCreationEvent ) {
-            if (managedRepositories.containsKey(event.getRepository().getId()) 
||
-                    
remoteRepositories.containsKey(event.getRepository().getId())) {
-                EditableRepository repo = (EditableRepository) 
event.getRepository();
-                if (repo != null && repo.getIndexingContext()!=null) {
+    public void raise(Event event) {
+        // To avoid event cycles:
+        if (sameOriginator(event)) {
+            return;
+        }
+        if (event instanceof IndexCreationEvent) {
+            IndexCreationEvent idxEvent = (IndexCreationEvent) event;
+            if 
(managedRepositories.containsKey(idxEvent.getRepository().getId()) ||
+                    
remoteRepositories.containsKey(idxEvent.getRepository().getId())) {
+                EditableRepository repo = (EditableRepository) 
idxEvent.getRepository();
+                if (repo != null && repo.getIndexingContext() != null) {
                     try {
                         ArchivaIndexManager idxmgr = 
getIndexManager(repo.getType());
                         if (idxmgr != null) {
@@ -1372,9 +1268,36 @@ public class RepositoryRegistry implements 
ConfigurationListener, RepositoryEven
                 }
             }
         }
-        for(RepositoryEventListener listener : listeners) {
-            listener.raise(event);
+        // We propagate all events to our listeners
+        pushEvent(event.recreate(this));
+    }
+
+    private boolean sameOriginator(Event event) {
+        if (event.getOriginator()==this) {
+            return true;
+        } else if (event.hasPreviousEvent()) {
+            return sameOriginator(event.getPreviousEvent());
+        } else {
+            return false;
+        }
+    }
+
+    private void pushEvent(Event<RepositoryRegistry> event) {
+        callListeners(event, listeners);
+        if (typeListenerMap.containsKey(event.getType())) {
+            callListeners(event, typeListenerMap.get(event.getType()));
         }
     }
 
+    private void callListeners(final Event<RepositoryRegistry> event, final 
List<RepositoryEventListener> evtListeners) {
+        for (RepositoryEventListener listener : evtListeners) {
+            try {
+                listener.raise(event);
+            } catch (Throwable e) {
+                log.error("Could not raise event {} on listener {}: {}", 
event, listener, e.getMessage());
+            }
+        }
+    }
+
+
 }
diff --git 
a/archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/mock/RepositoryProviderMock.java
 
b/archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/mock/RepositoryProviderMock.java
index 3a5e476..0f75218 100644
--- 
a/archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/mock/RepositoryProviderMock.java
+++ 
b/archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/mock/RepositoryProviderMock.java
@@ -23,6 +23,8 @@ import 
org.apache.archiva.configuration.ManagedRepositoryConfiguration;
 import org.apache.archiva.configuration.RemoteRepositoryConfiguration;
 import org.apache.archiva.configuration.RepositoryGroupConfiguration;
 import org.apache.archiva.repository.*;
+import org.apache.archiva.repository.events.Event;
+import org.apache.archiva.repository.events.RepositoryValueEvent;
 import org.apache.archiva.repository.features.ArtifactCleanupFeature;
 import org.apache.archiva.repository.features.IndexCreationFeature;
 import org.apache.archiva.repository.features.RemoteIndexFeature;
@@ -259,7 +261,7 @@ public class RepositoryProviderMock implements 
RepositoryProvider
     }
 
     @Override
-    public <T> void raise(RepositoryEvent<T> event) {
+    public void raise(Event event) {
 
     }
 }
diff --git 
a/archiva-modules/archiva-maven/archiva-maven-proxy/src/test/java/org/apache/archiva/repository/mock/RepositoryProviderMock.java
 
b/archiva-modules/archiva-maven/archiva-maven-proxy/src/test/java/org/apache/archiva/repository/mock/RepositoryProviderMock.java
index cc99d15..0a8c573 100644
--- 
a/archiva-modules/archiva-maven/archiva-maven-proxy/src/test/java/org/apache/archiva/repository/mock/RepositoryProviderMock.java
+++ 
b/archiva-modules/archiva-maven/archiva-maven-proxy/src/test/java/org/apache/archiva/repository/mock/RepositoryProviderMock.java
@@ -32,7 +32,8 @@ import org.apache.archiva.repository.PasswordCredentials;
 import org.apache.archiva.repository.ReleaseScheme;
 import org.apache.archiva.repository.RemoteRepository;
 import org.apache.archiva.repository.RepositoryCredentials;
-import org.apache.archiva.repository.RepositoryEvent;
+import org.apache.archiva.repository.events.Event;
+import org.apache.archiva.repository.events.RepositoryValueEvent;
 import org.apache.archiva.repository.RepositoryException;
 import org.apache.archiva.repository.RepositoryGroup;
 import org.apache.archiva.repository.RepositoryProvider;
@@ -280,7 +281,7 @@ public class RepositoryProviderMock implements 
RepositoryProvider
     }
 
     @Override
-    public <T> void raise(RepositoryEvent<T> event) {
+    public void raise(Event event) {
 
     }
 }

Reply via email to