Author: dblevins
Date: Sun Mar 23 13:02:58 2014
New Revision: 1580499

URL: http://svn.apache.org/r1580499
Log:
TOMEE-1148, TOMEE-1149 TOMEE-1150 : Basically an @Observes rerwite

Added:
    
tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/observer/EventSpeedTest.java
   (with props)
    
tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/observer/InvalidObserversTest.java
   (with props)
    
tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/observer/ObserverFeaturesTest.java
   (with props)
    
tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/observer/ObserverListTest.java
   (with props)
    
tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/observer/Util.java
   (with props)
Removed:
    
tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/loader/EventTest.java
    
tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/observer/ObserverManagerTest.java
Modified:
    
tomee/tomee/trunk/container/openejb-loader/src/main/java/org/apache/openejb/observer/ObserverManager.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=1580499&r1=1580498&r2=1580499&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
 Sun Mar 23 13:02:58 2014
@@ -19,7 +19,6 @@ package org.apache.openejb.observer;
 import org.apache.openejb.observer.event.AfterEvent;
 import org.apache.openejb.observer.event.BeforeEvent;
 import org.apache.openejb.observer.event.ObserverAdded;
-import org.apache.openejb.observer.event.ObserverFailed;
 import org.apache.openejb.observer.event.ObserverRemoved;
 
 import java.lang.annotation.Annotation;
@@ -28,77 +27,127 @@ 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.HashMap;
+import java.lang.reflect.WildcardType;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-import java.util.logging.Level;
-import java.util.logging.Logger;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 
 public class ObserverManager {
-    private final List<Observer> observers = new ArrayList<Observer>();
+    private final Set<Observer> observers = new LinkedHashSet<Observer>();
+    private final Map<Class, Invocation> methods = new 
ConcurrentHashMap<Class, Invocation>();
 
     public boolean addObserver(Object observer) {
         if (observer == null) throw new IllegalArgumentException("observer 
cannot be null");
 
-        final Observer obs;
         try {
-            obs = new Observer(observer);
+            if (observers.add(new Observer(observer))) {
+                methods.clear();
+                fireEvent(new ObserverAdded(observer));
+                return true;
+            } else {
+                return false;
+            }
         } catch (NotAnObserverException naoe) {
             return false;
         }
+    }
 
-        final boolean added = observers.add(obs);
-        if (added) {
-            // Observers can observe they have been added and are active
-            doFire(new ObserverAdded(observer), true);
+    public boolean removeObserver(final Object observer) {
+        if (observer == null) {
+            throw new IllegalArgumentException("listener cannot be null");
+        }
+        try {
+            if (observers.remove(new Observer(observer))) {
+                methods.clear();
+                fireEvent(new ObserverRemoved(observer));
+                return true;
+            } else {
+                return false;
+            }
+        } catch (NotAnObserverException naoe) {
+            return false;
         }
-        return added;
     }
 
-    public boolean removeObserver(Object observer) {
-        if (observer == null) throw new IllegalArgumentException("observer 
cannot be null");
+    public <E> E fireEvent(E event) {
+        if (event == null) {
+            throw new IllegalArgumentException("event cannot be null");
+        }
+
+        final Class<?> type = event.getClass();
+
+        final Invocation invocation = getInvocation(type);
+
+        invocation.invoke(event);
+
+        return event;
+    }
 
-        final boolean removed = observers.remove(new Observer(observer));
-        if (removed) {
-            // Observers can observe they are to be removed
-            doFire(new ObserverRemoved(observer), true);
+    private Invocation getInvocation(Class<?> type) {
+        {
+            final Invocation invocation = methods.get(type);
+            if (invocation != null) {
+                return invocation;
+            }
         }
-        return removed;
+
+        final Invocation invocation = buildInvocation(type);
+        methods.put(type, invocation);
+        return invocation;
     }
 
-    public <T> T fireEvent(final T event) {
-        if (event == null) throw new IllegalArgumentException("event cannot be 
null");
+    private static enum Phase {
+        BEFORE,
+        INVOKE,
+        AFTER
+    }
 
-        doFire(new BeforeEventImpl<T>(event), true);
-        doFire(event, false);
-        doFire(new AfterEventImpl<T>(event), true);
-        return event;
+    private Invocation buildInvocation(final Class<?> type) {
+        final Invocation before = buildInvocation(Phase.BEFORE, type);
+        final Invocation after = buildInvocation(Phase.AFTER, type);
+        final Invocation invoke = buildInvocation(Phase.INVOKE, type);
+
+        if (IGNORE == before && IGNORE == after) {
+
+            return invoke;
+
+        } else {
+
+            return new BeforeAndAfterInvocationSet(before, invoke, after);
+        }
     }
 
-    private void doFire(final Object event, final boolean internal) {
-        final List<Invocation> invocations = new LinkedList<Invocation>();
+    private Invocation buildInvocation(final Phase phase, final Class<?> type) 
{
+
+        final InvocationList list = new InvocationList();
+
         for (final Observer observer : observers) {
-            final Invocation i = observer.toInvocation(event, internal);
-            if (i != null) {
-                invocations.add(i);
+
+            final Invocation method = observer.get(phase, type);
+
+            if (method != null && method != IGNORE) {
+
+                list.add(method);
+
             }
         }
 
-        for (final Invocation invocation : invocations) {
-            try {
-                invocation.proceed();
-            } catch (final Throwable t) {
-                if (!(event instanceof ObserverFailed) && 
!AfterEventImpl.class.isInstance(event)) {
-                    fireEvent(new ObserverFailed(invocation.observer, event, 
t));
-                }
-                if (t instanceof InvocationTargetException && t.getCause() != 
null) {
-                    
Logger.getLogger(ObserverManager.class.getName()).log(Level.SEVERE, "error 
invoking " + invocation.observer, t.getCause());
-                } else {
-                    
Logger.getLogger(ObserverManager.class.getName()).log(Level.SEVERE, "error 
invoking " + invocation.observer, t);
-                }
-            }
+        if (list.getInvocations().size() == 0) {
+
+            return IGNORE;
+
+        } else if (list.getInvocations().size() == 1) {
+
+            return list.getInvocations().get(0);
+
+        } else {
+
+            return list;
         }
     }
 
@@ -106,19 +155,24 @@ public class ObserverManager {
      * @version $Rev$ $Date$
      */
     public static class Observer {
-        private final Map<Type, Method> methods = new HashMap<Type, Method>();
+
+        private final Map<Class, Invocation> before = new 
ConcurrentHashMap<Class, Invocation>();
+        private final Map<Class, Invocation> methods = new 
ConcurrentHashMap<Class, Invocation>();
+        private final Map<Class, Invocation> after = new 
ConcurrentHashMap<Class, Invocation>();
         private final Object observer;
-        private final Class<?> observerClass;
-        private final Method defaultMethod;
 
-        public Observer(Object observer) {
-            if (observer == null) throw new IllegalArgumentException("observer 
cannot be null");
+        public Observer(final Object observer) {
+            if (observer == null) {
+                throw new IllegalArgumentException("observer cannot be null");
+            }
+
+            final Set<Method> methods = new HashSet<Method>();
+            methods.addAll(Arrays.asList(observer.getClass().getMethods()));
+            
methods.addAll(Arrays.asList(observer.getClass().getDeclaredMethods()));
 
             this.observer = observer;
-            this.observerClass = observer.getClass();
-            for (final Method method : observer.getClass().getMethods()) {
-                final Observes annotation = isObserver(method);
-                if (annotation == null) {
+            for (final Method method : methods) {
+                if (!isObserver(method)) {
                     continue;
                 }
 
@@ -130,102 +184,147 @@ public class ObserverManager {
                     throw new IllegalArgumentException("@Observes method must 
not be abstract: " + method.toString());
                 }
 
+                if (Modifier.isStatic(method.getModifiers())) {
+                    throw new IllegalArgumentException("@Observes method must 
not be static: " + method.toString());
+                }
+
                 if (!Modifier.isPublic(method.getModifiers())) {
                     throw new IllegalArgumentException("@Observes method must 
be public: " + method.toString());
                 }
 
-                final Type type = method.getGenericParameterTypes()[0];
-                final Class<?> raw = method.getParameterTypes()[0];
+                final Class<?> type = method.getParameterTypes()[0];
 
-                if (raw.isAnnotation()) {
-                    throw new IllegalArgumentException("@Observes method 
parameter must be a concrete class (not an annotation): " + method.toString());
-                }
+                if (AfterEvent.class.equals(type)) {
 
-                if (Modifier.isAbstract(raw.getModifiers()) && raw == type) {
-                    throw new IllegalArgumentException("@Observes method 
parameter must be a concrete class (not an abstract class): " + 
method.toString());
-                }
+                    final Class parameterClass = getParameterClass(method);
+                    this.after.put(parameterClass, new AfterInvocation(method, 
observer));
 
-                if (raw.isInterface() && raw == type) {
-                    throw new IllegalArgumentException("@Observes method 
parameter must be a concrete class (not an interface): " + method.toString());
-                }
+                } else if (BeforeEvent.class.equals(type)) {
 
-                if (raw.isArray()) {
-                    throw new IllegalArgumentException("@Observes method 
parameter must be a concrete class (not an array): " + method.toString());
-                }
+                    final Class parameterClass = getParameterClass(method);
+                    this.before.put(parameterClass, new 
BeforeInvocation(method, observer));
 
-                if (raw.isPrimitive()) {
-                    throw new IllegalArgumentException("@Observes method 
parameter must be a concrete class (not a primitive): " + method.toString());
-                }
+                } else {
 
-                methods.put(type, method);
-            }
+                    validate(method, type);
+                    this.methods.put(type, new MethodInvocation(method, 
observer));
 
-            defaultMethod = methods.get(Object.class);
+                }
+            }
 
-            if (methods.size() == 0) {
+            if (methods.size() == 0 && after.size() == 0 && before.size() == 
0) {
                 throw new NotAnObserverException("Object has no @Observes 
methods. For example: public void observe(@Observes RetryConditionAdded 
event){...}");
             }
         }
 
-        public Invocation toInvocation(final Object event, final boolean 
internal) {
-            if (event == null) throw new IllegalArgumentException("event 
cannot be null");
+        private Class getParameterClass(final Method method) {
+
+            final Type[] genericParameterTypes = 
method.getGenericParameterTypes();
 
-            final Class eventType = event.getClass();
-            final Method method = methods.get(eventType);
+            final Type generic = genericParameterTypes[0];
 
-            if (method != null) {
-                return new Invocation(this, method, event);
+            if (!(generic instanceof ParameterizedType)) {
+                final Class<?> event = method.getParameterTypes()[0];
+                throw new IllegalArgumentException("@Observes " + 
event.getSimpleName() + " missing generic type: " + method.toString());
             }
 
-            if (AfterEventImpl.class.isInstance(event)) {
-                final Type[] types = new Type[] 
{AfterEventImpl.class.cast(event).getEvent().getClass()};
-                final Type raw = AfterEvent.class;
-                final Type type = new ParameterizedTypeImpl(types, raw) ;
-                for (final Map.Entry<Type, Method> m : methods.entrySet()) {
-                    if (m.getKey().equals(type)) {
-                        return new Invocation(this, m.getValue(), event);
-                    }
-                }
-            } else if (BeforeEventImpl.class.isInstance(event)) {
-                final Type[] types = new Type[] { 
BeforeEventImpl.class.cast(event).getEvent().getClass() };
-                final Type raw = BeforeEvent.class;
-                final Type type = new ParameterizedTypeImpl(types, raw) ;
-                for (final Map.Entry<Type, Method> m : methods.entrySet()) {
-                    if (m.getKey().equals(type)) {
-                        return new Invocation(this, m.getValue(), event);
-                    }
-                }
+            final ParameterizedType parameterized = 
ParameterizedType.class.cast(generic);
+
+            final Type type = parameterized.getActualTypeArguments()[0];
+
+            final Class clazz;
+
+            if (type instanceof Class) {
+
+                clazz = Class.class.cast(type);
+
+            } else if (type instanceof WildcardType) {
+
+                clazz = Object.class;
+
+            } else {
+
+                final Class<?> event = method.getParameterTypes()[0];
+                throw new IllegalArgumentException("@Observes " + 
event.getSimpleName() + " unsupported generic type: " + 
type.getClass().getSimpleName() + "  " + method.toString());
+            }
+
+            validate(method, clazz);
+
+            return clazz;
+        }
+
+        private void validate(final Method method, final Class<?> type) {
+            if (type.isAnnotation()) {
+                throw new IllegalArgumentException("@Observes method parameter 
must be a concrete class (not an annotation): " + method.toString());
+            }
+
+            if (type.isInterface()) {
+                throw new IllegalArgumentException("@Observes method parameter 
must be a concrete class (not an interface): " + method.toString());
+            }
+
+            if (type.isArray()) {
+                throw new IllegalArgumentException("@Observes method parameter 
must be a concrete class (not an array): " + method.toString());
             }
 
-            if (internal) {
-                return null;
+            if (type.isPrimitive()) {
+                throw new IllegalArgumentException("@Observes method parameter 
must be a concrete class (not a primitive): " + method.toString());
             }
+        }
 
-            if (defaultMethod != null) {
-                return new Invocation(this, defaultMethod, event);
+        private Map<Class, Invocation> map(final Phase event) {
+            switch (event) {
+                case AFTER:
+                    return after;
+                case BEFORE:
+                    return before;
+                case INVOKE:
+                    return methods;
+                default:
+                    throw new IllegalStateException("Unknown Event style " + 
event);
             }
-            return null;
         }
 
-        public Class<?> getObserverClass() {
-            return observerClass;
+        public Invocation get(final Phase event, final Class eventType) {
+            return get(map(event), eventType);
+        }
+
+        public Invocation getAfter(final Class eventType) {
+            return get(after, eventType);
         }
 
-        private Observes isObserver(Method method) {
+        public Invocation getBefore(final Class eventType) {
+            return get(before, eventType);
+        }
+
+        private Invocation get(final Map<Class, Invocation> map, final Class 
eventType) {
+            if (eventType == null) return IGNORE;
+
+            final Invocation method = map.get(eventType);
+
+            if (method != null) return method;
+
+            return get(map, eventType.getSuperclass());
+        }
+
+        private boolean isObserver(final Method method) {
             for (final Annotation[] annotations : 
method.getParameterAnnotations()) {
                 for (final Annotation annotation : annotations) {
                     if (annotation.annotationType().equals(Observes.class)) {
-                        return Observes.class.cast(annotation);
+                        return true;
                     }
                 }
             }
-            return null;
+            return false;
         }
 
         @Override
-        public boolean equals(Object o) {
-            if (this == o) return true;
-            if (o == null || getClass() != o.getClass()) return false;
+        public boolean equals(final Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
 
             final Observer observer1 = (Observer) o;
 
@@ -236,92 +335,133 @@ public class ObserverManager {
         public int hashCode() {
             return observer.hashCode();
         }
+    }
+
+    public static interface Invocation {
+
+        public void invoke(Object event);
+    }
+
+
+    private static final Invocation IGNORE = new Invocation() {
+        @Override
+        public void invoke(Object event) {
+        }
 
         @Override
         public String toString() {
-            return "Observer{" +
-                    "class=" + observer.getClass().getName() +
-                    '}';
+            return "IGNORE";
         }
-    }
+    };
 
-    private static class Invocation {
-        private final Observer observer;
+
+    public static class MethodInvocation implements Invocation {
         private final Method method;
-        private final Object event;
+        private final Object observer;
 
-        private Invocation(final Observer observer, final Method method, final 
Object event) {
-            this.observer = observer;
+        public MethodInvocation(Method method, Object observer) {
             this.method = method;
-            this.event = event;
+            this.observer = observer;
         }
 
-        private void proceed() throws InvocationTargetException, 
IllegalAccessException {
-            method.invoke(observer.observer, event);
+        @Override
+        public void invoke(final Object event) {
+            try {
+                method.invoke(observer, event);
+            } catch (InvocationTargetException e) {
+                final Throwable t = e.getTargetException() == null ? e : 
e.getTargetException();
+
+//                if (e.getTargetException() != null) {
+//                    logger.log(Level.WARNING, "Observer method invocation 
failed", t);
+//                }
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
         }
 
         @Override
         public String toString() {
-            return "Invocation{" +
-                    "observer=" + observer +
-                    ", method=" + method +
-                    ", event=" + event +
-                    '}';
+            return method.toString();
         }
     }
 
-    private static class NotAnObserverException extends RuntimeException {
-        public NotAnObserverException(final String s) {
-            super(s);
+    private static class AfterInvocation extends MethodInvocation {
+
+        private AfterInvocation(Method method, Object observer) {
+            super(method, observer);
+        }
+
+        @Override
+        public void invoke(final Object event) {
+            super.invoke(new AfterEvent() {
+                @Override
+                public Object getEvent() {
+                    return event;
+                }
+            });
         }
     }
 
-    private static class AfterEventImpl<T> implements AfterEvent<T> {
-        private final T event;
+    private static class BeforeInvocation extends MethodInvocation {
 
-        public AfterEventImpl(final T event) {
-            this.event = event;
+        private BeforeInvocation(Method method, Object observer) {
+            super(method, observer);
         }
 
-        public T getEvent() {
-            return event;
+        @Override
+        public void invoke(final Object event) {
+            super.invoke(new BeforeEvent() {
+                @Override
+                public Object getEvent() {
+                    return event;
+                }
+            });
         }
     }
 
-    private static class BeforeEventImpl<T> implements BeforeEvent<T> {
-        private final T event;
+    private static class BeforeAndAfterInvocationSet implements Invocation {
 
-        public BeforeEventImpl(final T event) {
-            this.event = event;
+        private final Invocation before;
+        private final Invocation invoke;
+        private final Invocation after;
+
+        private BeforeAndAfterInvocationSet(Invocation before, Invocation 
invoke, Invocation after) {
+            this.before = before;
+            this.invoke = invoke;
+            this.after = after;
         }
 
-        public T getEvent() {
-            return event;
+        @Override
+        public void invoke(Object event) {
+            before.invoke(event);
+            invoke.invoke(event);
+            after.invoke(event);
         }
     }
 
-    private static class ParameterizedTypeImpl implements ParameterizedType {
-        private final Type[] types;
-        private final Type raw;
+    public static class InvocationList implements Invocation {
+
+        private final List<Invocation> invocations = new 
LinkedList<Invocation>();
 
-        private ParameterizedTypeImpl(final Type[] types, final Type raw) {
-            this.types = types;
-            this.raw = raw;
+        public boolean add(Invocation invocation) {
+            return invocations.add(invocation);
         }
 
-        @Override
-        public Type[] getActualTypeArguments() {
-            return types;
+        public List<Invocation> getInvocations() {
+            return invocations;
         }
 
         @Override
-        public Type getRawType() {
-            return raw;
+        public void invoke(Object event) {
+            for (Invocation invocation : invocations) {
+                invocation.invoke(event);
+            }
         }
+    }
 
-        @Override
-        public Type getOwnerType() {
-            return null;
+    public static class NotAnObserverException extends 
IllegalArgumentException {
+        public NotAnObserverException(String s) {
+            super(s);
         }
     }
 }

Added: 
tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/observer/EventSpeedTest.java
URL: 
http://svn.apache.org/viewvc/tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/observer/EventSpeedTest.java?rev=1580499&view=auto
==============================================================================
--- 
tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/observer/EventSpeedTest.java
 (added)
+++ 
tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/observer/EventSpeedTest.java
 Sun Mar 23 13:02:58 2014
@@ -0,0 +1,172 @@
+/*
+ * 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;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.concurrent.TimeUnit;
+
+public class EventSpeedTest extends Assert {
+
+    private static final String format = "%10s %5s %5s %3.0f%%";
+
+    @Test
+    public void test() throws Exception {
+
+        final long start = System.nanoTime();
+        long events = 0;
+
+        System.out.println(String.format(format, "Events", "Obsvs", "Avg", 
0d));
+        Stats previous = null;
+        for (int i = 1; i < (64 / 4 + 1); i *= 2) {
+            final Stats stats = time(i);
+
+            events += stats.getEvents();
+
+            System.out.println(stats.compare(previous));
+            previous = stats;
+        }
+
+        final long elapsed = System.nanoTime() - start;
+        final long seconds = TimeUnit.NANOSECONDS.toSeconds(elapsed);
+        System.out.printf("%n  %s million events in %s seconds%n", events / 
1000000, seconds);
+
+        assertTrue(seconds < 60);
+    }
+
+    private Stats time(int observerCount) {
+        final ObserverManager observers = new ObserverManager();
+        for (int i = observerCount; i > 0; i--) {
+            observers.addObserver(new One());
+            observers.addObserver(new Two());
+            observers.addObserver(new Three());
+            observers.addObserver(new Four());
+        }
+
+        final long start = System.nanoTime();
+        final int max = 5000000;
+        for (int i = max; i > 0; i--) {
+            observers.fireEvent("");
+            observers.fireEvent(i);
+        }
+        final long total = System.nanoTime() - start;
+
+        return new Stats(total, max * 2, observerCount * 4);
+    }
+
+    public static class Stats {
+        private final long total;
+        private final long events;
+        private final long observers;
+
+        public Stats(long total, long events, long observers) {
+            this.total = total;
+            this.events = events;
+            this.observers = observers;
+        }
+
+        public long eventAverage() {
+            return total / events;
+        }
+
+        public long observerAverage() {
+            return total / observers;
+        }
+
+        public long getTotal() {
+            return total;
+        }
+
+        public long getEvents() {
+            return events;
+        }
+
+        public long getObservers() {
+            return observers;
+        }
+
+        @Override
+        public String toString() {
+            return String.format("%10s %10s %10s %10s", events, observers, 
eventAverage(), observerAverage());
+        }
+
+        public String compare(Stats previous) {
+            final double change = change(previous);
+
+            return String.format(format, events, observers, eventAverage(), 
change);
+        }
+
+        private double change(Stats previous) {
+            if (previous == null) return 0;
+            final double thisAverage = this.eventAverage();
+            final double thatAverage = previous.eventAverage();
+            return (thisAverage / thatAverage * 100) - 100;
+        }
+    }
+
+    public static class One {
+        public void observe(@Observes Object event) {
+        }
+
+        public void observe(@Observes Color event) {
+        }
+
+        public void observe(@Observes Green event) {
+        }
+
+        public void observe(@Observes Emerald event) {
+        }
+
+        public void observe(@Observes Integer event) {
+        }
+    }
+
+    public static class Two {
+        public void observe(@Observes Color event) {
+        }
+
+        public void observe(@Observes Green event) {
+        }
+    }
+
+    public static class Three {
+        public void observe(@Observes Green event) {
+        }
+
+        public void observe(@Observes Emerald event) {
+        }
+
+        public void observe(@Observes Integer event) {
+        }
+    }
+
+    public static class Four {
+        public void observe(@Observes Object event) {
+//            System.out.println(event);
+        }
+    }
+
+    public static class Color {
+    }
+
+    public static class Green extends Color {
+    }
+
+    public static class Emerald extends Green {
+    }
+}

Propchange: 
tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/observer/EventSpeedTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/observer/InvalidObserversTest.java
URL: 
http://svn.apache.org/viewvc/tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/observer/InvalidObserversTest.java?rev=1580499&view=auto
==============================================================================
--- 
tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/observer/InvalidObserversTest.java
 (added)
+++ 
tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/observer/InvalidObserversTest.java
 Sun Mar 23 13:02:58 2014
@@ -0,0 +1,141 @@
+/*
+ * 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;
+
+import org.apache.openejb.observer.event.AfterEvent;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.Serializable;
+import java.net.URI;
+
+public class InvalidObserversTest extends Assert {
+
+
+    @Test
+    public void noObserverMethods() {
+        final ObserverManager observers = new ObserverManager();
+        observers.addObserver(new Object() { });
+    }
+
+    @Test
+    public void methodIsStatic() {
+        a(new StaticMethod());
+    }
+
+    public static class StaticMethod {
+        public static void observe(final @Observes URI event1) {
+        }
+    }
+
+    @Test
+    public void methodIsPrivate() {
+        a(new Object() {
+            private void observe(final @Observes URI event) {
+            }
+        });
+    }
+
+    @Test
+    public void methodIsProtected() {
+        a(new Object() {
+            protected void observe(final @Observes URI event) {
+            }
+        });
+    }
+
+    @Test
+    public void methodIsDefaultScoped() {
+        a(new Object() {
+            void observe(final @Observes URI event) {
+            }
+        });
+    }
+
+    @Test
+    public void tooManyParameters() {
+        a(new Object() {
+            public void observe(final @Observes URI event1, final @Observes 
Class event2) {
+            }
+        });
+    }
+
+    @Test
+    public void parameterIsInterface() {
+        a(new Object() {
+            public void observe(final @Observes Serializable serializable) {
+            }
+        });
+    }
+
+    @Test
+    public void parameterIsPrimitive() {
+        a(new Object() {
+            public void observe(final @Observes int param) {
+            }
+        });
+    }
+
+    @Test
+    public void parameterIsArray() {
+        a(new Object() {
+            public void observe(final @Observes URI[] param) {
+            }
+        });
+    }
+
+    @Test
+    public void missingTypeParameter() {
+        a(new Object() {
+
+            public void observe(final @Observes AfterEvent afterEvent) {
+            }
+
+        });
+    }
+
+    @Test
+    public <T> void typeParameterIsType() {
+        a(new Object() {
+
+            public void observe(final @Observes AfterEvent<T> afterEvent) {
+            }
+
+        });
+    }
+
+    @Test
+    public void typeParameterIsInterface() {
+        a(new Object() {
+
+            public void observe(final @Observes AfterEvent<Serializable> 
afterEvent) {
+            }
+
+        });
+    }
+
+    private void a(final Object observer) {
+        try {
+            final ObserverManager observers = new ObserverManager();
+            observers.addObserver(observer);
+            fail("Expected IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // pass
+        }
+    }
+
+}

Propchange: 
tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/observer/InvalidObserversTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/observer/ObserverFeaturesTest.java
URL: 
http://svn.apache.org/viewvc/tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/observer/ObserverFeaturesTest.java?rev=1580499&view=auto
==============================================================================
--- 
tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/observer/ObserverFeaturesTest.java
 (added)
+++ 
tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/observer/ObserverFeaturesTest.java
 Sun Mar 23 13:02:58 2014
@@ -0,0 +1,313 @@
+/*
+ * 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;
+
+import org.apache.openejb.observer.event.AfterEvent;
+import org.apache.openejb.observer.event.BeforeEvent;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+public class ObserverFeaturesTest {
+
+
+    @Test
+    public void observeAll() {
+        a(new Object() {
+            public void observe(final @Observes Object event) {
+                pass();
+            }
+        }, new Date());
+    }
+
+    @Test
+    public void noFalsePositive() {
+        a(new Object() {
+            public void observe(final @Observes Integer event) {
+                fail();
+            }
+
+            public void observe(final @Observes Date event) {
+                pass();
+            }
+        }, new Date());
+    }
+
+    @Test
+    public void inheritance() {
+        a(new Object() {
+            public void observe(final @Observes Number event) {
+                pass();
+            }
+        }, 42);
+    }
+
+    @Test
+    public void overloaded() {
+        a(new Object() {
+            public void number(final @Observes Number event) {
+                fail();
+            }
+
+            public void integer(final @Observes Integer event) {
+                pass();
+            }
+        }, 42);
+    }
+
+    @Test
+    @Assert({ "before", "observe" })
+    public void beforeEvent() {
+        a(new Object() {
+            public void before(final @Observes BeforeEvent<Integer> event) {
+                invoked();
+            }
+
+            public void observe(final @Observes Integer event) {
+                invoked();
+            }
+        }, 42);
+    }
+
+    @Test
+    @Assert({ "observe", "after" })
+    public void afterEvent() {
+        a(new Object() {
+            public void after(final @Observes AfterEvent<Integer> event) {
+                invoked();
+            }
+
+            public void observe(final @Observes Integer event) {
+                invoked();
+            }
+        }, 42);
+    }
+
+
+    @Test
+    @Assert({ "before", "after" })
+    public void beforeInvokeAfter() {
+        a(new Object() {
+            public void after(final @Observes AfterEvent<Integer> event) {
+                invoked();
+            }
+
+            public void before(final @Observes BeforeEvent<Integer> event) {
+                invoked();
+            }
+        }, 42);
+    }
+
+    @Test
+    public void noFalseBeforePositive() {
+        a(new Object() {
+            public void integer(final @Observes BeforeEvent<Integer> event) {
+                pass();
+            }
+
+            public void date(final @Observes BeforeEvent<Date> event) {
+                fail();
+            }
+        }, 42);
+    }
+
+    @Test
+    @Assert("integer")
+    public void noFalseAfterPositive() {
+        a(new Object() {
+            public void integer(final @Observes AfterEvent<Integer> event) {
+                invoked();
+            }
+
+            public void date(final @Observes AfterEvent<Date> event) {
+                invoked();
+            }
+        }, 42);
+    }
+
+    @Test
+    public void beforeInheritance() {
+        a(new Object() {
+            public void number(final @Observes AfterEvent<Number> event) {
+                pass();
+            }
+        }, 42);
+    }
+
+    @Test
+    public void beforeObject() {
+        a(new Object() {
+            public void integer(final @Observes AfterEvent<Object> event) {
+                pass();
+            }
+        }, 42);
+    }
+
+    @Test
+    public void beforeInheritanceOverloaded() {
+        a(new Object() {
+            public void integer(final @Observes AfterEvent<Integer> event) {
+                pass();
+            }
+
+            public void number(final @Observes AfterEvent<Number> event) {
+                fail();
+            }
+        }, 42);
+    }
+
+    @Test
+    public void afterInheritance() {
+        a(new Object() {
+            public void number(final @Observes AfterEvent<Number> event) {
+                pass();
+            }
+        }, 42);
+    }
+
+    @Test
+    public void afterObject() {
+        a(new Object() {
+            public void integer(final @Observes AfterEvent<Object> event) {
+                pass();
+            }
+        }, 42);
+    }
+
+    @Test
+    public void afterInheritanceOverloaded() {
+        a(new Object() {
+            public void integer(final @Observes AfterEvent<Integer> event) {
+                pass();
+            }
+
+            public void number(final @Observes AfterEvent<Number> event) {
+                fail();
+            }
+        }, 42);
+    }
+
+
+    @Test
+    @Assert({ "number", "afterInteger", "beforeDate", "object", "afterObject", 
"object", "afterObject" })
+    public void sequence() {
+        a(new Object() {
+            public void object(final @Observes Object event) {
+                invoked();
+            }
+
+            public void number(final @Observes Number event) {
+                invoked();
+            }
+
+            public void afterInteger(final @Observes AfterEvent<Integer> 
event) {
+                invoked();
+            }
+
+            public void afterObject(final @Observes AfterEvent<Object> event) {
+                invoked();
+            }
+
+            public void beforeDate(final @Observes BeforeEvent<Date> event) {
+                invoked();
+            }
+        }, 42, new Date(), URI.create("foo:bar"));
+    }
+
+
+    private List<Boolean> conditions = new ArrayList<Boolean>();
+    private List<String> invocations = new ArrayList<String>();
+
+    @Before
+    public void init() {
+        conditions.clear();
+    }
+
+    public void pass() {
+        conditions.add(true);
+    }
+
+    public void fail() {
+        conditions.add(false);
+    }
+
+    public void invoked() {
+        final Method method = caller(2);
+        invocations.add(method.getName());
+    }
+
+    private void a(final Object observer, Object... events) {
+        final ObserverManager observers = new ObserverManager();
+        observers.addObserver(observer);
+
+        conditions.clear();
+        invocations.clear();
+
+        for (Object event : events) {
+            observers.fireEvent(event);
+        }
+
+        final Method testMethod = caller(2);
+        final Assert annotation = testMethod.getAnnotation(Assert.class);
+        if (annotation != null) {
+
+            Util.assertEvent(invocations, annotation.value());
+
+        } else {
+
+            org.junit.Assert.assertNotEquals(0, conditions.size());
+            for (Boolean condition : conditions) {
+                org.junit.Assert.assertTrue(condition);
+            }
+        }
+    }
+
+    private Method caller(final int i) {
+        try {
+            final StackTraceElement[] stackTrace = new 
Exception().fillInStackTrace().getStackTrace();
+            final String methodName = stackTrace[i].getMethodName();
+            final String className = stackTrace[i].getClassName();
+
+            final Class<?> clazz = 
this.getClass().getClassLoader().loadClass(className);
+            for (Method method : clazz.getDeclaredMethods()) {
+                if (methodName.endsWith(method.getName())) {
+                    return method;
+                }
+            }
+
+            throw new NoSuchMethodException(methodName);
+        } catch (NoSuchMethodException e) {
+            throw new RuntimeException(e);
+        } catch (ClassNotFoundException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
+    @java.lang.annotation.Target({ java.lang.annotation.ElementType.METHOD })
+    public @interface Assert {
+        String[] value();
+    }
+
+}

Propchange: 
tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/observer/ObserverFeaturesTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/observer/ObserverListTest.java
URL: 
http://svn.apache.org/viewvc/tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/observer/ObserverListTest.java?rev=1580499&view=auto
==============================================================================
--- 
tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/observer/ObserverListTest.java
 (added)
+++ 
tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/observer/ObserverListTest.java
 Sun Mar 23 13:02:58 2014
@@ -0,0 +1,87 @@
+/*
+ * 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;
+
+import org.apache.openejb.observer.event.ObserverAdded;
+import org.apache.openejb.observer.event.ObserverRemoved;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.apache.openejb.observer.Util.assertEvent;
+
+public class ObserverListTest {
+
+    @Test
+    public void noDuplicates() {
+        final ObserverManager observers = new ObserverManager();
+        final Object observer = new Object() {
+            public void observe(@Observes Object o) {
+            }
+        };
+
+        Assert.assertTrue(observers.addObserver(observer));
+        Assert.assertFalse(observers.addObserver(observer));
+        Assert.assertFalse(observers.addObserver(observer));
+        Assert.assertFalse(observers.addObserver(observer));
+
+        Assert.assertTrue(observers.removeObserver(observer));
+        Assert.assertFalse(observers.removeObserver(observer));
+        Assert.assertFalse(observers.removeObserver(observer));
+        Assert.assertFalse(observers.removeObserver(observer));
+    }
+
+    @Test
+    public void observerAddAndRemoveEvents() {
+
+        final Object observer = new Object() {
+            public void observe(@Observes Object o) {
+            }
+        };
+
+        final List<String> invoked = new ArrayList<String>();
+        final ObserverManager observers = new ObserverManager();
+        observers.addObserver(new Object() {
+            public void observe(@Observes ObserverAdded o) {
+                invoked.add(o.getClass().getSimpleName());
+                Assert.assertSame(observer, o.getObserver());
+            }
+
+            public void observe(@Observes ObserverRemoved o) {
+                invoked.add(o.getClass().getSimpleName());
+                Assert.assertSame(observer, o.getObserver());
+            }
+        });
+
+        invoked.clear();
+
+        observers.addObserver(observer);
+        observers.removeObserver(observer);
+        observers.addObserver(observer);
+        observers.removeObserver(observer);
+
+        assertEvent(invoked,
+                "ObserverAdded",
+                "ObserverRemoved",
+                "ObserverAdded",
+                "ObserverRemoved"
+        );
+    }
+
+}

Propchange: 
tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/observer/ObserverListTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/observer/Util.java
URL: 
http://svn.apache.org/viewvc/tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/observer/Util.java?rev=1580499&view=auto
==============================================================================
--- 
tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/observer/Util.java
 (added)
+++ 
tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/observer/Util.java
 Sun Mar 23 13:02:58 2014
@@ -0,0 +1,46 @@
+/*
+ * 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;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+public class Util {
+
+    public static String join(final Object... collection) {
+        return join(Arrays.asList(collection));
+    }
+
+    public static String join(final Collection<?> collection) {
+        final String delimiter = "\n";
+        if (collection.size() == 0) {
+            return "";
+        }
+        final StringBuilder sb = new StringBuilder();
+        for (final Object obj : collection) {
+            sb.append(obj).append(delimiter);
+        }
+        return sb.substring(0, sb.length() - delimiter.length());
+    }
+
+    static void assertEvent(List<String> observed, String... expected) {
+        assertEquals(join(expected), join(observed));
+    }
+}

Propchange: 
tomee/tomee/trunk/container/openejb-loader/src/test/java/org/apache/openejb/observer/Util.java
------------------------------------------------------------------------------
    svn:eol-style = native


Reply via email to