Author: rmannibucau Date: Sat Mar 22 10:41:47 2014 New Revision: 1580190 URL: http://svn.apache.org/r1580190 Log: TOMEE-1149 AfterEvent
Added: tomee/tomee/trunk/container/openejb-loader/src/main/java/org/apache/openejb/observer/event/AfterEvent.java Modified: tomee/tomee/trunk/container/openejb-loader/src/main/java/org/apache/openejb/observer/ObserverManager.java tomee/tomee/trunk/container/openejb-loader/src/main/java/org/apache/openejb/observer/Observes.java tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/loader/EventTest.java Modified: tomee/tomee/trunk/container/openejb-loader/src/main/java/org/apache/openejb/observer/ObserverManager.java URL: http://svn.apache.org/viewvc/tomee/tomee/trunk/container/openejb-loader/src/main/java/org/apache/openejb/observer/ObserverManager.java?rev=1580190&r1=1580189&r2=1580190&view=diff ============================================================================== --- tomee/tomee/trunk/container/openejb-loader/src/main/java/org/apache/openejb/observer/ObserverManager.java (original) +++ tomee/tomee/trunk/container/openejb-loader/src/main/java/org/apache/openejb/observer/ObserverManager.java Sat Mar 22 10:41:47 2014 @@ -16,6 +16,7 @@ */ package org.apache.openejb.observer; +import org.apache.openejb.observer.event.AfterEvent; import org.apache.openejb.observer.event.ObserverAdded; import org.apache.openejb.observer.event.ObserverFailed; import org.apache.openejb.observer.event.ObserverRemoved; @@ -24,19 +25,16 @@ import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; import java.util.ArrayList; -import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.concurrent.CopyOnWriteArraySet; import java.util.logging.Level; import java.util.logging.Logger; -import static java.util.Arrays.asList; -import static java.util.Collections.sort; - public class ObserverManager { private final List<Observer> observers = new ArrayList<Observer>(); @@ -53,7 +51,7 @@ public class ObserverManager { final boolean added = observers.add(obs); if (added) { // Observers can observe they have been added and are active - fireEvent(new ObserverAdded(observer)); + doFire(new ObserverAdded(observer)); } return added; } @@ -64,14 +62,19 @@ public class ObserverManager { final boolean removed = observers.remove(new Observer(observer)); if (removed) { // Observers can observe they are to be removed - fireEvent(new ObserverRemoved(observer)); + doFire(new ObserverRemoved(observer)); } return removed; } - public void fireEvent(Object event) { + public <T> void fireEvent(final T event) { if (event == null) throw new IllegalArgumentException("event cannot be null"); + doFire(event); + doFire(new AfterEventImpl<T>(event)); + } + + private void doFire(final Object event) { final List<Invocation> invocations = new LinkedList<Invocation>(); for (final Observer observer : observers) { final Invocation i = observer.toInvocation(event); @@ -80,12 +83,11 @@ public class ObserverManager { } } - sort(invocations); for (final Invocation invocation : invocations) { try { invocation.proceed(); } catch (final Throwable t) { - if (!(event instanceof ObserverFailed)) { + if (!(event instanceof ObserverFailed) && !AfterEventImpl.class.isInstance(event)) { fireEvent(new ObserverFailed(invocation.observer, event, t)); } if (t instanceof InvocationTargetException && t.getCause() != null) { @@ -101,10 +103,10 @@ public class ObserverManager { * @version $Rev$ $Date$ */ public static class Observer { - private final Map<Class, MetaMethod> methods = new HashMap<Class, MetaMethod>(); + private final Map<Type, Method> methods = new HashMap<Type, Method>(); private final Object observer; private final Class<?> observerClass; - private final MetaMethod defaultMethod; + private final Method defaultMethod; public Observer(Object observer) { if (observer == null) throw new IllegalArgumentException("observer cannot be null"); @@ -129,29 +131,30 @@ public class ObserverManager { throw new IllegalArgumentException("@Observes method must be public: " + method.toString()); } - final Class<?> type = method.getParameterTypes()[0]; + final Type type = method.getGenericParameterTypes()[0]; + final Class<?> raw = method.getParameterTypes()[0]; - if (type.isAnnotation()) { + if (raw.isAnnotation()) { throw new IllegalArgumentException("@Observes method parameter must be a concrete class (not an annotation): " + method.toString()); } - if (Modifier.isAbstract(type.getModifiers())) { + if (Modifier.isAbstract(raw.getModifiers()) && raw == type) { throw new IllegalArgumentException("@Observes method parameter must be a concrete class (not an abstract class): " + method.toString()); } - if (type.isInterface()) { + if (raw.isInterface() && raw == type) { throw new IllegalArgumentException("@Observes method parameter must be a concrete class (not an interface): " + method.toString()); } - if (type.isArray()) { + if (raw.isArray()) { throw new IllegalArgumentException("@Observes method parameter must be a concrete class (not an array): " + method.toString()); } - if (type.isPrimitive()) { + if (raw.isPrimitive()) { throw new IllegalArgumentException("@Observes method parameter must be a concrete class (not a primitive): " + method.toString()); } - methods.put(type, new MetaMethod(method, new CopyOnWriteArraySet<Class<?>>(asList(annotation.after())))); + methods.put(type, method); } defaultMethod = methods.get(Object.class); @@ -165,7 +168,31 @@ public class ObserverManager { if (event == null) throw new IllegalArgumentException("event cannot be null"); final Class eventType = event.getClass(); - final MetaMethod method = methods.get(eventType); + final Method method = methods.get(eventType); + + if (method == null && AfterEventImpl.class.isInstance(event)) { + final Type type = new ParameterizedType() { + @Override + public Type[] getActualTypeArguments() { + return new Type[] { AfterEventImpl.class.cast(event).getEvent().getClass() }; + } + + @Override + public Type getRawType() { + return AfterEvent.class; + } + + @Override + public Type getOwnerType() { + return null; + } + }; + for (final Map.Entry<Type, Method> m : methods.entrySet()) { + if (m.getKey().equals(type)) { + return new Invocation(this, m.getValue(), event); + } + } + } if (method != null) { return new Invocation(this, method, event); @@ -213,55 +240,26 @@ public class ObserverManager { } } - private static class MetaMethod { - private final Method method; - private final Collection<Class<?>> after; - - private MetaMethod(final Method method, final Collection<Class<?>> after) { - this.method = method; - this.after = after; - } - - @Override - public String toString() { - return "MetaMethod{" + - "method=" + method + - ", after=" + after + - '}'; - } - } - - private static class Invocation implements Comparable<Invocation> { + private static class Invocation { private final Observer observer; - private final MetaMethod metaMethod; + private final Method method; private final Object event; - private Invocation(final Observer observer, final MetaMethod method, final Object event) { + private Invocation(final Observer observer, final Method method, final Object event) { this.observer = observer; - this.metaMethod = method; + this.method = method; this.event = event; } private void proceed() throws InvocationTargetException, IllegalAccessException { - metaMethod.method.invoke(observer.observer, event); - } - - @Override // only called for a single event so only consider observer.after - public int compareTo(final Invocation o) { - if (o == null) { - return 0; - } - if (metaMethod.after.contains(o.observer.observerClass)) { - return 1; - } - return -1; + method.invoke(observer.observer, event); } @Override public String toString() { return "Invocation{" + "observer=" + observer + - ", metaMethod=" + metaMethod + + ", method=" + method + ", event=" + event + '}'; } @@ -272,4 +270,16 @@ public class ObserverManager { super(s); } } + + private static class AfterEventImpl<T> implements AfterEvent<T> { + private final T event; + + public AfterEventImpl(final T event) { + this.event = event; + } + + public T getEvent() { + return event; + } + } } Modified: tomee/tomee/trunk/container/openejb-loader/src/main/java/org/apache/openejb/observer/Observes.java URL: http://svn.apache.org/viewvc/tomee/tomee/trunk/container/openejb-loader/src/main/java/org/apache/openejb/observer/Observes.java?rev=1580190&r1=1580189&r2=1580190&view=diff ============================================================================== --- tomee/tomee/trunk/container/openejb-loader/src/main/java/org/apache/openejb/observer/Observes.java (original) +++ tomee/tomee/trunk/container/openejb-loader/src/main/java/org/apache/openejb/observer/Observes.java Sat Mar 22 10:41:47 2014 @@ -30,5 +30,4 @@ import static java.lang.annotation.Reten @Retention(RUNTIME) @Documented public @interface Observes { - Class<?>[] after() default {}; } \ No newline at end of file Added: tomee/tomee/trunk/container/openejb-loader/src/main/java/org/apache/openejb/observer/event/AfterEvent.java URL: http://svn.apache.org/viewvc/tomee/tomee/trunk/container/openejb-loader/src/main/java/org/apache/openejb/observer/event/AfterEvent.java?rev=1580190&view=auto ============================================================================== --- tomee/tomee/trunk/container/openejb-loader/src/main/java/org/apache/openejb/observer/event/AfterEvent.java (added) +++ tomee/tomee/trunk/container/openejb-loader/src/main/java/org/apache/openejb/observer/event/AfterEvent.java Sat Mar 22 10:41:47 2014 @@ -0,0 +1,24 @@ +/** + * 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. + */ +package org.apache.openejb.observer.event; + +import org.apache.openejb.observer.Event; + +@Event +public interface AfterEvent<T> { + T getEvent(); +} Modified: tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/loader/EventTest.java URL: http://svn.apache.org/viewvc/tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/loader/EventTest.java?rev=1580190&r1=1580189&r2=1580190&view=diff ============================================================================== --- tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/loader/EventTest.java (original) +++ tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/loader/EventTest.java Sat Mar 22 10:41:47 2014 @@ -17,50 +17,62 @@ package org.apache.openejb.loader; import org.apache.openejb.observer.Observes; +import org.apache.openejb.observer.event.AfterEvent; import org.junit.After; import org.junit.Before; import org.junit.Test; -import java.util.concurrent.atomic.AtomicInteger; - +import static org.hamcrest.CoreMatchers.instanceOf; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; public class EventTest { @After @Before public void reset() { SystemInstance.reset(); + SimpleObserver.id = -1; } - private static final AtomicInteger ID = new AtomicInteger(0); - @Test - public void order() { + public void simple() { final SystemInstance s = SystemInstance.get(); assertEquals(-1, SimpleObserver.id); - assertEquals(-1, OrderedSimpleObserver.id); - s.addObserver(new OrderedSimpleObserver()); s.addObserver(new SimpleObserver()); s.fireEvent(new SimpleEvent()); assertEquals(1, SimpleObserver.id); - assertEquals(2, OrderedSimpleObserver.id); + } + + @Test + public void afterEvent() { + final SystemInstance s = SystemInstance.get(); + assertEquals(-1, SimpleObserver.id); + s.addObserver(new SimpleObserver()); + s.addObserver(new AfterSimpleObserver()); + final SimpleEvent event = new SimpleEvent(); + s.fireEvent(event); + assertEquals(1, SimpleObserver.id); + assertNotNull(AfterSimpleObserver.event); + assertEquals(event, AfterSimpleObserver.event.getEvent()); } public static class SimpleEvent {} - public static class SimpleObserver { - private static int id = -1; + public static class AfterSimpleObserver { + private static AfterEvent<SimpleEvent> event; - public void observe(final @Observes SimpleEvent event) { - id = ID.incrementAndGet(); + public void observe(final @Observes AfterEvent<SimpleEvent> event) { + AfterSimpleObserver.event = event; + assertThat(event.getEvent(), instanceOf(SimpleEvent.class)); } } - public static class OrderedSimpleObserver { + public static class SimpleObserver { private static int id = -1; - public void observe(final @Observes(after = SimpleObserver.class) SimpleEvent event) { - id = ID.incrementAndGet(); + public void observe(final @Observes SimpleEvent event) { + id = 1; } } }