Finalizing event API

This commit is contained in:
Martin Stockhammer 2019-10-03 14:21:18 +02:00
parent 54148d4fc2
commit 69a4057630
23 changed files with 417 additions and 202 deletions

View File

@ -256,7 +256,7 @@ public class RepositoryProviderMock implements RepositoryProvider
} }
@Override @Override
public void raise(Event event) { public void handle(Event event) {
} }

View File

@ -285,7 +285,7 @@ public class RepositoryProviderMock implements RepositoryProvider
} }
@Override @Override
public void raise(Event event) { public void handle(Event event) {
} }
} }

View File

@ -32,7 +32,7 @@ import org.apache.archiva.repository.ManagedRepository;
import org.apache.archiva.repository.RemoteRepository; import org.apache.archiva.repository.RemoteRepository;
import org.apache.archiva.repository.RepositoryRegistry; import org.apache.archiva.repository.RepositoryRegistry;
import org.apache.archiva.repository.RepositoryType; import org.apache.archiva.repository.RepositoryType;
import org.apache.archiva.repository.events.RepositoryEventListener; import org.apache.archiva.repository.events.EventHandler;
import org.apache.archiva.repository.events.RepositoryRegistryEvent; import org.apache.archiva.repository.events.RepositoryRegistryEvent;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -51,7 +51,7 @@ import java.util.stream.Collectors;
*/ */
@SuppressWarnings( "SpringJavaInjectionPointsAutowiringInspection" ) @SuppressWarnings( "SpringJavaInjectionPointsAutowiringInspection" )
@Service("proxyRegistry#default") @Service("proxyRegistry#default")
public class ArchivaProxyRegistry implements ProxyRegistry, RepositoryEventListener<RepositoryRegistryEvent> { public class ArchivaProxyRegistry implements ProxyRegistry, EventHandler<RepositoryRegistryEvent> {
private static final Logger log = LoggerFactory.getLogger(ArchivaProxyRegistry.class); private static final Logger log = LoggerFactory.getLogger(ArchivaProxyRegistry.class);
@ -84,7 +84,7 @@ public class ArchivaProxyRegistry implements ProxyRegistry, RepositoryEventListe
updateHandler(); updateHandler();
updateConnectors(); updateConnectors();
updateNetworkProxies(); updateNetworkProxies();
repositoryRegistry.register(RepositoryRegistryEvent.RELOADED, this); repositoryRegistry.registerEventHandler(RepositoryRegistryEvent.RELOADED, this);
} }
private ArchivaConfiguration getArchivaConfiguration() { private ArchivaConfiguration getArchivaConfiguration() {
@ -217,7 +217,7 @@ public class ArchivaProxyRegistry implements ProxyRegistry, RepositoryEventListe
} }
@Override @Override
public void raise(RepositoryRegistryEvent event) { public void handle(RepositoryRegistryEvent event) {
log.debug("Reload happened, updating proxy list"); log.debug("Reload happened, updating proxy list");
if (event.getType()== RepositoryRegistryEvent.RELOADED) { if (event.getType()== RepositoryRegistryEvent.RELOADED) {
init(); init();

View File

@ -20,7 +20,7 @@ package org.apache.archiva.repository;
*/ */
import org.apache.archiva.indexer.ArchivaIndexingContext; import org.apache.archiva.indexer.ArchivaIndexingContext;
import org.apache.archiva.repository.events.RepositoryEventSource; import org.apache.archiva.repository.events.EventSource;
import org.apache.archiva.repository.storage.RepositoryStorage; import org.apache.archiva.repository.storage.RepositoryStorage;
import org.apache.archiva.repository.features.RepositoryFeature; import org.apache.archiva.repository.features.RepositoryFeature;
import org.apache.archiva.repository.storage.StorageAsset; import org.apache.archiva.repository.storage.StorageAsset;
@ -35,7 +35,7 @@ import java.util.Set;
* *
* Created by Martin Stockhammer on 21.09.17. * Created by Martin Stockhammer on 21.09.17.
*/ */
public interface Repository extends RepositoryEventSource, RepositoryStorage { public interface Repository extends EventSource, RepositoryStorage {
/** /**
* Return the identifier of the repository. Repository identifier should be unique at least * Return the identifier of the repository. Repository identifier should be unique at least

View File

@ -22,7 +22,7 @@ package org.apache.archiva.repository;
import org.apache.archiva.configuration.ManagedRepositoryConfiguration; import org.apache.archiva.configuration.ManagedRepositoryConfiguration;
import org.apache.archiva.configuration.RemoteRepositoryConfiguration; import org.apache.archiva.configuration.RemoteRepositoryConfiguration;
import org.apache.archiva.configuration.RepositoryGroupConfiguration; import org.apache.archiva.configuration.RepositoryGroupConfiguration;
import org.apache.archiva.repository.events.RepositoryEventListener; import org.apache.archiva.repository.events.EventHandler;
import java.io.IOException; import java.io.IOException;
import java.util.Set; import java.util.Set;
@ -40,7 +40,7 @@ import java.util.Set;
* *
* *
*/ */
public interface RepositoryProvider extends RepositoryEventListener public interface RepositoryProvider extends EventHandler
{ {
/** /**

View File

@ -22,51 +22,91 @@ package org.apache.archiva.repository.events;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.EventObject; import java.util.EventObject;
public class Event extends EventObject { /**
* Base class for events. Events have a type and a source.
* The source is the instance that raised the event.
*
* There are different event types for a given event. The types are represented in a hierarchical structure.
*
* Events can be chained, which means a event listener can catch events and rethrow them as its own event.
*
*/
public class Event extends EventObject implements Cloneable {
public static final EventType<Event> ANY = new EventType(null, "ANY"); private static final long serialVersionUID = -7171846575892044990L;
Event previous; public static final EventType<Event> ANY = EventType.ROOT;
final Object originator;
final EventType<? extends Event> type; private Event previous;
final LocalDateTime instant; private final EventType<? extends Event> type;
private final LocalDateTime createTime;
public Event(EventType<? extends Event> type, Object originator) { public Event(EventType<? extends Event> type, Object originator) {
super(originator); super(originator);
this.originator = originator;
this.type = type; this.type = type;
this.instant = LocalDateTime.now(); this.createTime = LocalDateTime.now();
} }
private Event(Event previous, Object originator) { private Event(Event previous, Object originator) {
super(originator); super(originator);
this.previous = previous; this.previous = previous;
this.originator = originator;
this.type = previous.getType(); this.type = previous.getType();
this.instant = previous.getInstant(); this.createTime = previous.getCreateTime();
} }
/**
* Returns the event type that is associated with this event instance.
* @return the event type
*/
public EventType<? extends Event> getType() { public EventType<? extends Event> getType() {
return type; return type;
}; };
public LocalDateTime getInstant() { /**
return instant; * Returns the time, when the event was created.
* @return
*/
public LocalDateTime getCreateTime() {
return createTime;
} }
public Object getOriginator() {
return originator; /**
} * Recreates the event with the given instance as the new source. The
* current source is stored in the previous event.
public Event recreate(Object newOrigin) { * @param newSource The new source
return new Event(this, newOrigin); * @return a new event instance, where <code>this</code> is stored as previous event
*/
public Event copyFor(Object newSource) {
Event newEvent = (Event) this.clone();
newEvent.previous = this;
newEvent.source = newSource;
return newEvent;
} }
/**
* Returns the previous event or <code>null</code>, if this is a root event.
* @return the previous event or <code>null</code>, if it does not exist
*/
public Event getPreviousEvent() { public Event getPreviousEvent() {
return previous; return previous;
} }
/**
* Returns <code>true</code>, if the event has a previous event.
* @return <code>true</code>, if this has a previous event, otherwise <code>false</code>
*/
public boolean hasPreviousEvent() { public boolean hasPreviousEvent() {
return previous!=null; return previous!=null;
} }
@Override
protected Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
// this should not happen
throw new RuntimeException("Event is not clonable");
}
}
} }

View File

@ -19,10 +19,12 @@ package org.apache.archiva.repository.events;
* under the License. * under the License.
*/ */
/** import java.util.EventListener;
* A listener that accepts repository events.
*/
public interface RepositoryEventListener<T extends Event> {
void raise(T event); /**
* A listener that accepts events.
*/
public interface EventHandler<T extends Event> extends EventListener {
void handle(T event);
} }

View File

@ -0,0 +1,79 @@
package org.apache.archiva.repository.events;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class EventManager implements EventSource {
private static final Logger log = LoggerFactory.getLogger(EventManager.class);
private final ConcurrentHashMap<EventType<? extends Event>, Set<EventHandler>> handlerMap = new ConcurrentHashMap<>();
private final Object source;
public EventManager(Object source) {
if (source==null) {
throw new IllegalArgumentException("The source may not be null");
}
this.source = source;
}
@Override
public <T extends Event> void registerEventHandler(EventType<T> type, EventHandler<? super T> eventHandler) {
Set<EventHandler> handlers = handlerMap.computeIfAbsent(type, t -> new LinkedHashSet<>());
if (!handlers.contains(eventHandler)) {
handlers.add(eventHandler);
}
}
@Override
public <T extends Event> void unregisterEventHandler(EventType<T> type, EventHandler<? super T> eventHandler) {
if (handlerMap.containsKey(type)) {
handlerMap.get(type).remove(eventHandler);
}
}
public void fireEvent(Event fireEvent) {
final EventType<? extends Event> type = fireEvent.getType();
Event event;
if (fireEvent.getSource()!=source) {
event = fireEvent.copyFor(source);
} else {
event = fireEvent;
}
for (EventType<? extends Event> handlerType : handlerMap.keySet()) {
if (EventType.isInstanceOf(type, handlerType)) {
for (EventHandler handler : handlerMap.get(handlerType)) {
try {
handler.handle(event);
} catch (Exception e) {
// We catch all errors from handlers
log.error("An error occured during event handling: {}", e.getMessage(), e);
}
}
}
}
}
}

View File

@ -19,18 +19,15 @@ package org.apache.archiva.repository.events;
* under the License. * under the License.
*/ */
import java.util.Set;
/** /**
* A repository event handler raises events to its registered listeners. * A repository event source raises events to its registered listeners.
* Listeners may register for all events that are raised or only to a subset of events. * Listeners register to event types that are structured hierarchical.
* *
*/ */
public interface RepositoryEventSource { public interface EventSource {
<T extends Event> void register(EventType<T> type, RepositoryEventListener<? super T> listener); <T extends Event> void registerEventHandler(EventType<T> type, EventHandler<? super T> eventHandler);
<T extends Event> void unregister(EventType<T> type, RepositoryEventListener<? super T> listener); <T extends Event> void unregisterEventHandler(EventType<T> type, EventHandler<? super T> eventHandler);
void clearListeners();
} }

View File

@ -19,17 +19,59 @@ package org.apache.archiva.repository.events;
* under the License. * under the License.
*/ */
import java.util.ArrayList; import java.io.InvalidObjectException;
import java.util.List; import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.*;
public class EventType<T extends Event> { /**
* Event types define a hierarchical structure of events. Each event is bound to a certain event type.
* All event types have a super type, only the root event type {@link EventType#ROOT} has no super type.
*
* Event types should be stored as static fields on the events itself.
*
* @param <T> The type class parameter allows to define the types in a type safe way and represents a event class,
* where the type is associated to.
*/
public class EventType<T extends Event> implements Serializable {
public static final EventType<Event> ROOT = new EventType<>();
private final String name; private final String name;
private final EventType<? super T> superType; private final EventType<? super T> superType;
private WeakHashMap<EventType<? extends T>, Void> subTypes;
/**
* Creates a type with the given name and the root type as parent.
* @param name the name of the new type
*/
public EventType(String name) {
this.superType = ROOT;
this.name = name;
}
/**
* Creates a event type instance with the given super type and name.
*
* @param superType The super type or <code>null</code>, if this is the root type.
* @param name
*/
public EventType(EventType<? super T> superType, String name) { public EventType(EventType<? super T> superType, String name) {
if (superType==null) {
throw new NullPointerException("Super Type may not be null");
}
this.name = name; this.name = name;
this.superType = superType; this.superType = superType;
superType.register(this);
}
/**
* Creates the root type
*/
private EventType() {
this.name="ROOT";
this.superType=null;
} }
public String name() { public String name() {
@ -40,6 +82,19 @@ public class EventType<T extends Event> {
return superType; return superType;
} }
private void register(EventType<? extends T> subType) {
if (subTypes == null) {
subTypes = new WeakHashMap<>();
}
for (EventType<? extends T> t : subTypes.keySet()) {
if (((t.name == null && subType.name == null) || (t.name != null && t.name.equals(subType.name)))) {
throw new IllegalArgumentException("EventType \"" + subType + "\""
+ "with parent \"" + subType.getSuperType()+"\" already exists");
}
}
subTypes.put(subType, null);
}
public static List<EventType<?>> fetchSuperTypes(EventType<?> type) { public static List<EventType<?>> fetchSuperTypes(EventType<?> type) {
List<EventType<?>> typeList = new ArrayList<>(); List<EventType<?>> typeList = new ArrayList<>();
@ -61,4 +116,51 @@ public class EventType<T extends Event> {
} }
return false; return false;
} }
private Object writeReplace() throws ObjectStreamException {
Deque<String> path = new LinkedList<String>();
EventType<?> t = this;
while (t != ROOT) {
path.addFirst(t.name);
t = t.superType;
}
return new EventTypeSerialization(new ArrayList<>(path));
}
static class EventTypeSerialization implements Serializable {
private static final long serialVersionUID = 1841649460281865547L;
private List<String> path;
public EventTypeSerialization(List<String> path) {
this.path = path;
}
private Object readResolve() throws ObjectStreamException {
EventType t = ROOT;
for (int i = 0; i < path.size(); ++i) {
String p = path.get(i);
if (t.subTypes != null) {
EventType<?> s = findSubType(t.subTypes.keySet(), p);
if (s == null) {
throw new InvalidObjectException("Cannot find event type \"" + p + "\" (of " + t + ")");
}
t = s;
} else {
throw new InvalidObjectException("Cannot find event type \"" + p + "\" (of " + t + ")");
}
}
return t;
}
private EventType<?> findSubType(Set<EventType> subTypes, String name) {
for (EventType t : subTypes) {
if (((t.name == null && name == null) || (t.name != null && t.name.equals(name)))) {
return t;
}
}
return null;
}
}
} }

View File

@ -1,44 +0,0 @@
package org.apache.archiva.repository.events;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import org.apache.archiva.repository.Repository;
import java.net.URI;
public class IndexCreationEvent extends RepositoryValueEvent<URI> {
public static EventType<IndexCreationEvent> ANY = new EventType<>(RepositoryValueEvent.ANY, "REPOSITORY.VALUE.INDEX");
public static EventType<IndexCreationEvent> INDEX_URI_CHANGED = new EventType<>(ANY, "REPOSITORY.VALUE.INDEX.URI_CHANGED");
public static EventType<IndexCreationEvent> PACKED_INDEX_URI_CHANGED = new EventType<>(ANY, "REPOSITORY.VALUE.INDEX.PACKED_URI_CHANGED");
IndexCreationEvent(EventType<? extends IndexCreationEvent> type, Object origin, Repository repo, URI oldValue, URI value) {
super(type, origin, repo, oldValue, value);
}
public static final <O> IndexCreationEvent indexUriChange(O origin, Repository repo, URI oldValue, URI newValue) {
return new IndexCreationEvent(INDEX_URI_CHANGED, origin, repo, oldValue, newValue);
}
public static final <O> IndexCreationEvent packedIndexUriChange(O origin, Repository repo, URI oldValue, URI newValue) {
return new IndexCreationEvent(PACKED_INDEX_URI_CHANGED, origin, repo, oldValue, newValue);
}
}

View File

@ -21,8 +21,17 @@ package org.apache.archiva.repository.events;
import org.apache.archiva.repository.Repository; import org.apache.archiva.repository.Repository;
/**
* Raises events about the repository lifecycle. The following events are raised:
* <ul>
* <li>REGISTERED: a repository has been registered by the repository registry</li>
* <li>UNREGISTERED: a repository has been removed by the repository registry</li>
* <li>UPDATED: A repository attribute was updated</li>
* </ul>
*/
public class LifecycleEvent extends RepositoryEvent { public class LifecycleEvent extends RepositoryEvent {
private static final long serialVersionUID = -2520982087439428714L;
public static EventType<LifecycleEvent> ANY = new EventType<>(RepositoryEvent.ANY, "REPOSITORY.LIFECYCLE"); public static EventType<LifecycleEvent> ANY = new EventType<>(RepositoryEvent.ANY, "REPOSITORY.LIFECYCLE");
public static EventType<LifecycleEvent> REGISTERED = new EventType<>(ANY, "REPOSITORY.LIFECYCLE.REGISTERED"); public static EventType<LifecycleEvent> REGISTERED = new EventType<>(ANY, "REPOSITORY.LIFECYCLE.REGISTERED");
public static EventType<LifecycleEvent> UNREGISTERED = new EventType<>(ANY, "REPOSITORY.LIFECYCLE.UNREGISTERED"); public static EventType<LifecycleEvent> UNREGISTERED = new EventType<>(ANY, "REPOSITORY.LIFECYCLE.UNREGISTERED");

View File

@ -21,9 +21,15 @@ package org.apache.archiva.repository.events;
import org.apache.archiva.repository.Repository; import org.apache.archiva.repository.Repository;
/**
* A repository event is specific to a repository and holds a reference to the repository that
* is related to this event.
*/
public class RepositoryEvent extends Event { public class RepositoryEvent extends Event {
public static final EventType<RepositoryEvent> ANY = new EventType<>(Event.ANY, "REPOSITORY.UPDATED"); private static final long serialVersionUID = 4676673476606414834L;
public static final EventType<RepositoryEvent> ANY = new EventType<>(Event.ANY, "REPOSITORY");
private final Repository repository; private final Repository repository;

View File

@ -0,0 +1,49 @@
package org.apache.archiva.repository.events;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import org.apache.archiva.repository.Repository;
import java.net.URI;
/**
* These events are thrown, when index information has changed.
*/
public class RepositoryIndexEvent extends RepositoryValueEvent<URI> {
private static final long serialVersionUID = -7801989699524776524L;
public static EventType<RepositoryIndexEvent> ANY = new EventType<>(RepositoryValueEvent.ANY, "REPOSITORY.VALUE.INDEX");
public static EventType<RepositoryIndexEvent> INDEX_URI_CHANGED = new EventType<>(ANY, "REPOSITORY.VALUE.INDEX.URI_CHANGED");
public static EventType<RepositoryIndexEvent> PACKED_INDEX_URI_CHANGED = new EventType<>(ANY, "REPOSITORY.VALUE.INDEX.PACKED_URI_CHANGED");
RepositoryIndexEvent(EventType<? extends RepositoryIndexEvent> type, Object origin, Repository repo, URI oldValue, URI value) {
super(type, origin, repo, oldValue, value, "index.uri");
}
public static final <O> RepositoryIndexEvent indexUriChange(O origin, Repository repo, URI oldValue, URI newValue) {
return new RepositoryIndexEvent(INDEX_URI_CHANGED, origin, repo, oldValue, newValue);
}
public static final <O> RepositoryIndexEvent packedIndexUriChange(O origin, Repository repo, URI oldValue, URI newValue) {
return new RepositoryIndexEvent(PACKED_INDEX_URI_CHANGED, origin, repo, oldValue, newValue);
}
}

View File

@ -19,11 +19,29 @@ package org.apache.archiva.repository.events;
* under the License. * under the License.
*/ */
/**
* Repository registry events are raised by the repository registry itself.
*/
public class RepositoryRegistryEvent extends Event { public class RepositoryRegistryEvent extends Event {
public static EventType<RepositoryRegistryEvent> ANY = new EventType(Event.ANY, "REGISTRY"); private static final long serialVersionUID = -4740127827269612094L;
/**
* All repository registry events
*/
public static EventType<RepositoryRegistryEvent> ANY = new EventType(EventType.ROOT, "REGISTRY");
/**
* When the registry has reloaded the registry data from the configuration
*/
public static EventType<RepositoryRegistryEvent> RELOADED = new EventType(ANY, "REGISTRY.RELOADED"); public static EventType<RepositoryRegistryEvent> RELOADED = new EventType(ANY, "REGISTRY.RELOADED");
/**
* When the registry was destroyed. Repository instances may still be referenced, but are not updated.
*/
public static EventType<RepositoryRegistryEvent> DESTROYED = new EventType(ANY, "REGISTRY.DESTROYED"); public static EventType<RepositoryRegistryEvent> DESTROYED = new EventType(ANY, "REGISTRY.DESTROYED");
/**
* When the registry was initialized
*/
public static EventType<RepositoryRegistryEvent> INITIALIZED = new EventType(ANY, "REGISTRY.INITIALIZED");
public RepositoryRegistryEvent(EventType<? extends RepositoryRegistryEvent> type, Object origin) { public RepositoryRegistryEvent(EventType<? extends RepositoryRegistryEvent> type, Object origin) {
super(type, origin); super(type, origin);

View File

@ -22,21 +22,27 @@ package org.apache.archiva.repository.events;
import org.apache.archiva.repository.Repository; import org.apache.archiva.repository.Repository;
/** /**
* Repository event. Repository events are used for providing information about repository changes. * Repository value events are used for providing information about repository attribute changes.
* The value event gives information of the attribute value before and after the change.
* *
* @param <V> * @param <V> The type of the changed attribute
*/ */
public class RepositoryValueEvent<V> extends RepositoryEvent { public class RepositoryValueEvent<V> extends RepositoryEvent {
public static final EventType<RepositoryValueEvent<?>> ANY = new EventType(RepositoryEvent.ANY, "REPOSITORY.VALUE.UPDATED"); private static final long serialVersionUID = 4176597620699304794L;
public static final EventType<RepositoryValueEvent<?>> ANY = new EventType(RepositoryEvent.ANY, "REPOSITORY.VALUE");
final V value; final V value;
final V oldValue; final V oldValue;
final String attributeName;
public RepositoryValueEvent(EventType<? extends RepositoryValueEvent<V>> type, Object origin, Repository repo, V oldValue, V value) { public RepositoryValueEvent(EventType<? extends RepositoryValueEvent<V>> type, Object origin, Repository repo, V oldValue, V value,
String attributeName) {
super(type, origin, repo); super(type, origin, repo);
this.value = value; this.value = value;
this.oldValue = oldValue; this.oldValue = oldValue;
this.attributeName = attributeName;
} }
public V getValue() { public V getValue() {
@ -47,4 +53,8 @@ public class RepositoryValueEvent<V> extends RepositoryEvent {
return oldValue; return oldValue;
} }
public String getAttributeName() {
return attributeName;
}
} }

View File

@ -20,35 +20,35 @@ package org.apache.archiva.repository.features;
*/ */
import org.apache.archiva.repository.events.Event; import org.apache.archiva.repository.events.Event;
import org.apache.archiva.repository.events.RepositoryEventListener; import org.apache.archiva.repository.events.EventHandler;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
public class AbstractFeature { public class AbstractFeature {
private List<RepositoryEventListener> listener = new ArrayList<>(); private List<EventHandler> listener = new ArrayList<>();
AbstractFeature() { AbstractFeature() {
} }
AbstractFeature(RepositoryEventListener listener) { AbstractFeature(EventHandler listener) {
this.listener.add(listener); this.listener.add(listener);
} }
AbstractFeature(Collection<RepositoryEventListener> listeners) { AbstractFeature(Collection<EventHandler> listeners) {
this.listener.addAll(listeners); this.listener.addAll(listeners);
} }
public void addListener(RepositoryEventListener listener) { public void addListener(EventHandler listener) {
if (!this.listener.contains(listener)) { if (!this.listener.contains(listener)) {
this.listener.add(listener); this.listener.add(listener);
} }
this.listener.add(listener); this.listener.add(listener);
} }
public void removeListener(RepositoryEventListener listener) { public void removeListener(EventHandler listener) {
this.listener.remove(listener); this.listener.remove(listener);
} }
@ -57,8 +57,8 @@ public class AbstractFeature {
} }
public void pushEvent(Event event) { public void pushEvent(Event event) {
for(RepositoryEventListener listr : listener) { for(EventHandler listr : listener) {
listr.raise(event); listr.handle(event);
} }
} }

View File

@ -21,8 +21,8 @@ package org.apache.archiva.repository.features;
import org.apache.archiva.repository.Repository; import org.apache.archiva.repository.Repository;
import org.apache.archiva.repository.events.IndexCreationEvent; import org.apache.archiva.repository.events.RepositoryIndexEvent;
import org.apache.archiva.repository.events.RepositoryEventListener; import org.apache.archiva.repository.events.EventHandler;
import org.apache.archiva.repository.storage.StorageAsset; import org.apache.archiva.repository.storage.StorageAsset;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -44,7 +44,7 @@ import static org.apache.archiva.indexer.ArchivaIndexManager.DEFAULT_PACKED_INDE
* A index may have a remote and a local representation. The remote representation is used for downloading and * A index may have a remote and a local representation. The remote representation is used for downloading and
* updating the local representation. * updating the local representation.
* *
* The feature is throwing a {@link IndexCreationEvent}, if the URI of the index has been changed. * The feature is throwing a {@link RepositoryIndexEvent}, if the URI of the index has been changed.
* *
*/ */
public class IndexCreationFeature extends AbstractFeature implements RepositoryFeature<IndexCreationFeature>{ public class IndexCreationFeature extends AbstractFeature implements RepositoryFeature<IndexCreationFeature>{
@ -62,7 +62,7 @@ public class IndexCreationFeature extends AbstractFeature implements RepositoryF
private Repository repo; private Repository repo;
public IndexCreationFeature(Repository repository, RepositoryEventListener listener) { public IndexCreationFeature(Repository repository, EventHandler listener) {
super(listener); super(listener);
this.repo = repository; this.repo = repository;
try { try {
@ -129,7 +129,7 @@ public class IndexCreationFeature extends AbstractFeature implements RepositoryF
if ((this.indexPath==null && indexPath!=null) || !this.indexPath.equals(indexPath)) { if ((this.indexPath==null && indexPath!=null) || !this.indexPath.equals(indexPath)) {
URI oldVal = this.indexPath; URI oldVal = this.indexPath;
this.indexPath = indexPath; this.indexPath = indexPath;
pushEvent(IndexCreationEvent.indexUriChange(this, repo, oldVal, this.indexPath)); pushEvent(RepositoryIndexEvent.indexUriChange(this, repo, oldVal, this.indexPath));
} }
} }
@ -173,14 +173,14 @@ public class IndexCreationFeature extends AbstractFeature implements RepositoryF
/** /**
* Sets the path (relative or absolute) of the packed index. * Sets the path (relative or absolute) of the packed index.
* *
* Throws a {@link IndexCreationEvent.Index#PACKED_INDEX_URI_CHANGE}, if the value changes. * Throws a {@link RepositoryIndexEvent.Index#PACKED_INDEX_URI_CHANGE}, if the value changes.
* *
* @param packedIndexPath the new path uri for the packed index * @param packedIndexPath the new path uri for the packed index
*/ */
public void setPackedIndexPath(URI packedIndexPath) { public void setPackedIndexPath(URI packedIndexPath) {
URI oldVal = this.packedIndexPath; URI oldVal = this.packedIndexPath;
this.packedIndexPath = packedIndexPath; this.packedIndexPath = packedIndexPath;
pushEvent(IndexCreationEvent.packedIndexUriChange(this, repo, oldVal, this.packedIndexPath)); pushEvent(RepositoryIndexEvent.packedIndexUriChange(this, repo, oldVal, this.packedIndexPath));
} }
/** /**

View File

@ -56,7 +56,7 @@ import java.util.function.Consumer;
* No features are provided. Capabilities and features must be implemented by concrete classes. * No features are provided. Capabilities and features must be implemented by concrete classes.
* *
*/ */
public abstract class AbstractRepository implements EditableRepository, RepositoryEventListener<RepositoryEvent> public abstract class AbstractRepository implements EditableRepository, EventHandler<RepositoryEvent>
{ {
@ -80,8 +80,7 @@ public abstract class AbstractRepository implements EditableRepository, Reposito
private String layout = "default"; private String layout = "default";
public static final CronDefinition CRON_DEFINITION = CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ); public static final CronDefinition CRON_DEFINITION = CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ);
private Map<EventType<? extends RepositoryEvent>, List<RepositoryEventListener<? extends RepositoryEvent>>> listenerTypeMap = new HashMap<>(); private final EventManager eventManager;
Map<Class<? extends RepositoryFeature<?>>, RepositoryFeature<?>> featureMap = new HashMap<>( ); Map<Class<? extends RepositoryFeature<?>>, RepositoryFeature<?>> featureMap = new HashMap<>( );
@ -95,6 +94,7 @@ public abstract class AbstractRepository implements EditableRepository, Reposito
this.storage = repositoryStorage; this.storage = repositoryStorage;
this.location = repositoryStorage.getLocation(); this.location = repositoryStorage.getLocation();
this.openStatus.compareAndSet(false, true); this.openStatus.compareAndSet(false, true);
this.eventManager = new EventManager(this);
} }
public AbstractRepository(Locale primaryLocale, RepositoryType type, String id, String name, RepositoryStorage repositoryStorage) { public AbstractRepository(Locale primaryLocale, RepositoryType type, String id, String name, RepositoryStorage repositoryStorage) {
@ -105,6 +105,7 @@ public abstract class AbstractRepository implements EditableRepository, Reposito
this.storage = repositoryStorage; this.storage = repositoryStorage;
this.location = repositoryStorage.getLocation(); this.location = repositoryStorage.getLocation();
this.openStatus.compareAndSet(false, true); this.openStatus.compareAndSet(false, true);
this.eventManager = new EventManager(this);
} }
protected void setPrimaryLocale(Locale locale) { protected void setPrimaryLocale(Locale locale) {
@ -324,8 +325,8 @@ public abstract class AbstractRepository implements EditableRepository, Reposito
sf.getStagingRepository().close(); sf.getStagingRepository().close();
} }
} }
clearListeners();
} }
} }
@Override @Override
@ -334,56 +335,22 @@ public abstract class AbstractRepository implements EditableRepository, Reposito
} }
@Override @Override
public void raise(RepositoryEvent event) { public void handle(RepositoryEvent event) {
final EventType<? extends Event> currentType = event.getType(); // We just rethrow the events
for (EventType<? extends RepositoryEvent> type : listenerTypeMap.keySet()) { eventManager.fireEvent(event);
if (EventType.isInstanceOf(currentType, type)) {
callListeners(event, listenerTypeMap.get(type));
}
}
}
private void callListeners(RepositoryEvent event, List<RepositoryEventListener<? extends RepositoryEvent>> evtListeners) {
for(RepositoryEventListener listener : evtListeners) {
try {
listener.raise(event.recreate(this));
} catch (Throwable e) {
log.error("Could not raise event {} on listener {}: {}", event, listener, e.getMessage());
}
}
} }
@Override @Override
public <T extends Event> void register(EventType<T> eventType, RepositoryEventListener<? super T> listener) { public <T extends Event> void registerEventHandler(EventType<T> eventType, EventHandler<? super T> eventHandler) {
if (!EventType.isInstanceOf(eventType, RepositoryEvent.ANY)) { if (!EventType.isInstanceOf(eventType, RepositoryEvent.ANY)) {
throw new IllegalArgumentException("Can only register RepositoryEvent Handlers"); throw new IllegalArgumentException("Can only register RepositoryEvent Handlers");
} }
final RepositoryEventListener<? extends RepositoryEvent> myListener = (RepositoryEventListener<? extends RepositoryEvent>) listener; eventManager.registerEventHandler(eventType, eventHandler);
final EventType<? extends RepositoryEvent> type = (EventType<? extends RepositoryEvent>) eventType;
List<RepositoryEventListener<? extends RepositoryEvent>> listeners;
if (listenerTypeMap.containsKey(type)) {
listeners = listenerTypeMap.get(type);
} else {
listeners = new ArrayList<>();
listenerTypeMap.put(type, listeners);
}
if (!listeners.contains(listener)) {
listeners.add(myListener);
}
} }
@Override @Override
public <T extends Event> void unregister(EventType<T> type, RepositoryEventListener<? super T> listener) { public <T extends Event> void unregisterEventHandler(EventType<T> type, EventHandler<? super T> eventHandler) {
for (List<RepositoryEventListener<? extends RepositoryEvent>> listeners : listenerTypeMap.values()) { eventManager.unregisterEventHandler(type, eventHandler);
listeners.remove(listener);
}
}
@Override
public void clearListeners() {
this.listenerTypeMap.clear();
} }
@Override @Override

View File

@ -23,6 +23,7 @@ import org.apache.archiva.configuration.*;
import org.apache.archiva.indexer.*; import org.apache.archiva.indexer.*;
import org.apache.archiva.redback.components.registry.RegistryException; import org.apache.archiva.redback.components.registry.RegistryException;
import org.apache.archiva.repository.events.*; import org.apache.archiva.repository.events.*;
import org.apache.archiva.repository.events.EventHandler;
import org.apache.archiva.repository.features.IndexCreationFeature; import org.apache.archiva.repository.features.IndexCreationFeature;
import org.apache.archiva.repository.features.StagingRepositoryFeature; import org.apache.archiva.repository.features.StagingRepositoryFeature;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -53,7 +54,7 @@ import static org.apache.archiva.indexer.ArchivaIndexManager.DEFAULT_INDEX_PATH;
* @since 3.0 * @since 3.0
*/ */
@Service("repositoryRegistry") @Service("repositoryRegistry")
public class RepositoryRegistry implements ConfigurationListener, RepositoryEventSource, RepositoryEventListener<Event> { public class RepositoryRegistry implements ConfigurationListener, EventSource, EventHandler<Event> {
private static final Logger log = LoggerFactory.getLogger(RepositoryRegistry.class); private static final Logger log = LoggerFactory.getLogger(RepositoryRegistry.class);
@ -73,7 +74,7 @@ public class RepositoryRegistry implements ConfigurationListener, RepositoryEven
@Named("repositoryContentFactory#default") @Named("repositoryContentFactory#default")
RepositoryContentFactory repositoryContentFactory; RepositoryContentFactory repositoryContentFactory;
private Map<EventType<? extends Event>, List<RepositoryEventListener<? extends Event>>> typeListenerMap = new HashMap<>(); private final EventManager eventManager;
private Map<String, ManagedRepository> managedRepositories = new HashMap<>(); private Map<String, ManagedRepository> managedRepositories = new HashMap<>();
@ -89,6 +90,10 @@ public class RepositoryRegistry implements ConfigurationListener, RepositoryEven
private volatile boolean ignoreConfigEvents = false; private volatile boolean ignoreConfigEvents = false;
public RepositoryRegistry() {
this.eventManager = new EventManager(this);
}
public void setArchivaConfiguration(ArchivaConfiguration archivaConfiguration) { public void setArchivaConfiguration(ArchivaConfiguration archivaConfiguration) {
this.archivaConfiguration = archivaConfiguration; this.archivaConfiguration = archivaConfiguration;
} }
@ -181,7 +186,7 @@ public class RepositoryRegistry implements ConfigurationListener, RepositoryEven
private ManagedRepository createNewManagedRepository(RepositoryProvider provider, ManagedRepositoryConfiguration cfg) throws RepositoryException { private ManagedRepository createNewManagedRepository(RepositoryProvider provider, ManagedRepositoryConfiguration cfg) throws RepositoryException {
log.debug("Creating repo {}", cfg.getId()); log.debug("Creating repo {}", cfg.getId());
ManagedRepository repo = provider.createManagedInstance(cfg); ManagedRepository repo = provider.createManagedInstance(cfg);
repo.register(RepositoryEvent.ANY, this); repo.registerEventHandler(RepositoryEvent.ANY, this);
updateRepositoryReferences(provider, repo, cfg, null); updateRepositoryReferences(provider, repo, cfg, null);
return repo; return repo;
@ -221,7 +226,7 @@ public class RepositoryRegistry implements ConfigurationListener, RepositoryEven
createIndexingContext(editableRepo); createIndexingContext(editableRepo);
} }
} }
repo.register(RepositoryEvent.ANY, this); repo.registerEventHandler(RepositoryEvent.ANY, this);
} }
public ArchivaIndexManager getIndexManager(RepositoryType type) { public ArchivaIndexManager getIndexManager(RepositoryType type) {
@ -296,7 +301,7 @@ public class RepositoryRegistry implements ConfigurationListener, RepositoryEven
createIndexingContext(editableRepo); createIndexingContext(editableRepo);
} }
} }
repo.register(RepositoryEvent.ANY, this); repo.registerEventHandler(RepositoryEvent.ANY, this);
} }
private Map<String, RepositoryGroup> getRepositorGroupsFromConfig() { private Map<String, RepositoryGroup> getRepositorGroupsFromConfig() {
@ -331,7 +336,7 @@ public class RepositoryRegistry implements ConfigurationListener, RepositoryEven
private RepositoryGroup createNewRepositoryGroup(RepositoryProvider provider, RepositoryGroupConfiguration config) throws RepositoryException { private RepositoryGroup createNewRepositoryGroup(RepositoryProvider provider, RepositoryGroupConfiguration config) throws RepositoryException {
RepositoryGroup repositoryGroup = provider.createRepositoryGroup(config); RepositoryGroup repositoryGroup = provider.createRepositoryGroup(config);
repositoryGroup.register(RepositoryEvent.ANY, this); repositoryGroup.registerEventHandler(RepositoryEvent.ANY, this);
updateRepositoryReferences(provider, repositoryGroup, config); updateRepositoryReferences(provider, repositoryGroup, config);
return repositoryGroup; return repositoryGroup;
} }
@ -1171,7 +1176,7 @@ public class RepositoryRegistry implements ConfigurationListener, RepositoryEven
ManagedRepositoryConfiguration cfg = provider.getManagedConfiguration(repo); ManagedRepositoryConfiguration cfg = provider.getManagedConfiguration(repo);
cfg.setId(newId); cfg.setId(newId);
ManagedRepository cloned = provider.createManagedInstance(cfg); ManagedRepository cloned = provider.createManagedInstance(cfg);
cloned.register(RepositoryEvent.ANY, this); cloned.registerEventHandler(RepositoryEvent.ANY, this);
return cloned; return cloned;
} }
@ -1200,7 +1205,7 @@ public class RepositoryRegistry implements ConfigurationListener, RepositoryEven
RemoteRepositoryConfiguration cfg = provider.getRemoteConfiguration(repo); RemoteRepositoryConfiguration cfg = provider.getRemoteConfiguration(repo);
cfg.setId(newId); cfg.setId(newId);
RemoteRepository cloned = provider.createRemoteInstance(cfg); RemoteRepository cloned = provider.createRemoteInstance(cfg);
cloned.register(RepositoryEvent.ANY, this); cloned.registerEventHandler(RepositoryEvent.ANY, this);
return cloned; return cloned;
} }
@ -1215,47 +1220,32 @@ public class RepositoryRegistry implements ConfigurationListener, RepositoryEven
@Override @Override
public <T extends Event> void register(EventType<T> type, RepositoryEventListener<? super T> listener) { public <T extends Event> void registerEventHandler(EventType<T> type, EventHandler<? super T> eventHandler) {
List<RepositoryEventListener<?>> listeners; eventManager.registerEventHandler(type, eventHandler);
if (typeListenerMap.containsKey(type)) {
listeners = typeListenerMap.get(type);
} else {
listeners = new ArrayList<>();
typeListenerMap.put(type, listeners);
}
if (!listeners.contains(listener)) {
listeners.add(listener);
}
} }
@Override @Override
public <T extends Event> void unregister(EventType<T> type, RepositoryEventListener<? super T> listener) { public <T extends Event> void unregisterEventHandler(EventType<T> type, EventHandler<? super T> eventHandler) {
for (List<RepositoryEventListener<?>> listeners : typeListenerMap.values()) { eventManager.unregisterEventHandler(type, eventHandler);
listeners.remove(listener);
}
} }
@Override
public void clearListeners() {
this.typeListenerMap.clear();
}
@Override @Override
public void raise(Event event) { public void handle(Event event) {
// To avoid event cycles: // To avoid event cycles:
if (sameOriginator(event)) { if (sameOriginator(event)) {
return; return;
} }
if (event instanceof IndexCreationEvent) { if (event instanceof RepositoryIndexEvent) {
handleIndexCreationEvent((IndexCreationEvent) event); handleIndexCreationEvent((RepositoryIndexEvent) event);
} }
// We propagate all events to our listeners, but with context of repository registry // We propagate all events to our listeners, but with context of repository registry
pushEvent(event.recreate(this)); pushEvent(event);
} }
private void handleIndexCreationEvent(IndexCreationEvent event) { private void handleIndexCreationEvent(RepositoryIndexEvent event) {
IndexCreationEvent idxEvent = event; RepositoryIndexEvent idxEvent = event;
if (managedRepositories.containsKey(idxEvent.getRepository().getId()) || if (managedRepositories.containsKey(idxEvent.getRepository().getId()) ||
remoteRepositories.containsKey(idxEvent.getRepository().getId())) { remoteRepositories.containsKey(idxEvent.getRepository().getId())) {
EditableRepository repo = (EditableRepository) idxEvent.getRepository(); EditableRepository repo = (EditableRepository) idxEvent.getRepository();
@ -1276,7 +1266,7 @@ public class RepositoryRegistry implements ConfigurationListener, RepositoryEven
} }
private boolean sameOriginator(Event event) { private boolean sameOriginator(Event event) {
if (event.getOriginator() == this) { if (event.getSource() == this) {
return true; return true;
} else if (event.hasPreviousEvent()) { } else if (event.hasPreviousEvent()) {
return sameOriginator(event.getPreviousEvent()); return sameOriginator(event.getPreviousEvent());
@ -1286,19 +1276,9 @@ public class RepositoryRegistry implements ConfigurationListener, RepositoryEven
} }
private void pushEvent(Event event) { private void pushEvent(Event event) {
final EventType<? extends Event> currentType = event.getType(); eventManager.fireEvent(event);
for (EventType<? extends Event> type : typeListenerMap.keySet()) {
if (EventType.isInstanceOf(currentType, type)) {
callListeners(event, typeListenerMap.get(type));
}
}
} }
private void callListeners(Event event, List<RepositoryEventListener<? extends Event>> listeners) {
for (RepositoryEventListener listener : listeners) {
listener.raise(event);
}
}
} }

View File

@ -261,7 +261,7 @@ public class RepositoryProviderMock implements RepositoryProvider
} }
@Override @Override
public void raise(Event event) { public void handle(Event event) {
} }
} }

View File

@ -281,7 +281,7 @@ public class RepositoryProviderMock implements RepositoryProvider
} }
@Override @Override
public void raise(Event event) { public void handle(Event event) {
} }
} }

View File

@ -509,7 +509,7 @@ public class MavenRepositoryProvider implements RepositoryProvider {
} }
@Override @Override
public void raise(Event event) { public void handle(Event event) {
// //
} }