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