Skip to content

Commit

Permalink
Added new data structures for observers and observer resolution.
Browse files Browse the repository at this point in the history
git-svn-id: http://anonsvn.jboss.org/repos/weld/ri/trunk@172 1c488680-804c-0410-94cd-c6b725194a0e
  • Loading branch information
drallen committed Oct 27, 2008
1 parent 00221a0 commit fda1a4d
Show file tree
Hide file tree
Showing 12 changed files with 503 additions and 143 deletions.
117 changes: 62 additions & 55 deletions webbeans-ri/src/main/java/org/jboss/webbeans/event/EventBus.java
@@ -1,8 +1,7 @@
package org.jboss.webbeans.event;

import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Collection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
Expand All @@ -20,106 +19,114 @@
* The event bus is where observers are registered and events are fired.
*
* @author David Allen
*
*
*/
public class EventBus
{
private final Map<Integer, Set<Observer<?>>> registeredObservers;
private final TransactionManager tm;
private String tmName = "java:/TransactionManager";
private final Map<Class<?>, ArrayList<EventObserver<?>>> registeredObservers;
private final TransactionManager tm;
private String tmName = "java:/TransactionManager";

/**
* Initializes a new instance of the EventBus. This includes looking up the
* Initializes a new instance of the EventBus. This includes looking up the
* transaction manager which is needed to defer events till the end of a
* transaction.
* TODO Should be able to configure JNDI name of transaction manager
* transaction. TODO Should be able to configure JNDI name of transaction
* manager
*
*/
public EventBus()
{
registeredObservers = new HashMap<Integer, Set<Observer<?>>>();
registeredObservers = new HashMap<Class<?>, ArrayList<EventObserver<?>>>();
tm = JNDI.lookup(tmName, TransactionManager.class);
}

/**
* Adds an observer to the event bus so that it receives event notifications. The
* event information is already encapsulated as part of the observer.
* @param o The observer that should receive events
* Adds an observer to the event bus so that it receives event notifications.
* The event information is already encapsulated as part of the observer.
*
* @param o
* The observer that should receive events
*/
public void addObserver(Observer<?> o)
public <T> void addObserver(Observer<T> o, Class<T> eventType,
Annotation... bindings)
{
int key = 1 /*TODO generateKey(o.getEventType(), o.get)*/;
Set<Observer<?>> l = registeredObservers.get(key);
ArrayList<EventObserver<?>> l = registeredObservers.get(eventType);
if (l == null)
l = new HashSet<Observer<?>>();
l.add(o);
registeredObservers.put(key, l);
{
l = new ArrayList<EventObserver<?>>();
registeredObservers.put(eventType, l);
}
EventObserver<T> eventObserver = new EventObserver<T>(o, eventType, bindings);
if (!l.contains(eventObserver))
l.add(eventObserver);
}

/**
* Defers delivery of an event till the end of the currently active transaction.
* Defers delivery of an event till the end of the currently active
* transaction.
*
* @param container The WebBeans container
* @param event The event object to deliver
* @param o The observer to receive the event
* @param container
* The WebBeans container
* @param event
* The event object to deliver
* @param o
* The observer to receive the event
* @throws SystemException
* @throws IllegalStateException
* @throws RollbackException
*/
public void deferEvent(Object event, Observer<Object> o) throws SystemException, IllegalStateException, RollbackException
public void deferEvent(Object event, Observer<Object> o)
throws SystemException, IllegalStateException, RollbackException
{
if (tm != null) {
if (tm != null)
{
// Get the current transaction associated with the thread
Transaction t = tm.getTransaction();
if (t != null)
t.registerSynchronization(new DeferredEventNotification<Object>(event, o));
t.registerSynchronization(new DeferredEventNotification<Object>(
event, o));
}
}

/**
* Resolves the list of observers to be notified for a given event and
* optional event bindings.
* @param event The event object
* @param bindings Optional event bindings
*
* @param event
* The event object
* @param bindings
* Optional event bindings
* @return A set of Observers
*/
@SuppressWarnings("unchecked")
public <T> Set<Observer<T>> getObservers(T event, Annotation... bindings)
{
Set<Observer<T>> results = new HashSet<Observer<T>>();
for (Observer<?> observer : registeredObservers.get(generateKey(event.getClass(), Arrays.asList(bindings))))
for (EventObserver<?> observer : registeredObservers.get(event.getClass()))
{
results.add((Observer<T>) observer);
// TODO Verify bindings match before adding
results.add((Observer<T>) observer.getObserver());
}
return results;
}

/**
* Removes an observer from the event bus.
* @param o The observer to remove
*/
public void removeObserver(Observer<?> o)
{
// TODO fix
// Set<Observer<?>> l = registeredObservers.get(generateKey(o.getEventType(), o.getEventBindingTypes()));
//if (l != null) {
// l.remove(o);
//}
}

/**
* Creates a key that can be used in a map for an observer that is notified of
* events of a specific type with optional event bindings.
* @param eventType The class of the event being observed
* @param eventBindings An optional set of event bindings
* @return
*
* @param observer
* The observer to remove
*/
public int generateKey(Class<?> eventType, Collection<Annotation> eventBindings)
public <T> void removeObserver(Observer<T> observer, Class<T> eventType)
{
// Produce the sum of the hash codes for the event type and the set of
// event bindings.
int key = eventType.hashCode();
if (eventBindings != null)
key += eventBindings.hashCode();
return key;
ArrayList<EventObserver<?>> observers = registeredObservers.get(eventType);
for (int i = 0; i < observers.size(); i++)
{
EventObserver<?> eventObserver = observers.get(i);
if (eventObserver.getObserver().equals(observer))
{
observers.remove(i);
break;
}
}
}
}
59 changes: 51 additions & 8 deletions webbeans-ri/src/main/java/org/jboss/webbeans/event/EventImpl.java
@@ -1,6 +1,9 @@
package org.jboss.webbeans.event;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
Expand All @@ -11,6 +14,7 @@
import javax.webbeans.DuplicateBindingTypeException;
import javax.webbeans.Event;
import javax.webbeans.Observer;
import javax.webbeans.TypeLiteral;
import javax.webbeans.manager.Manager;

/**
Expand All @@ -24,21 +28,26 @@
public class EventImpl<T> implements Event<T>
{
private Collection<? extends Annotation> eventBindings;
private Class<T> eventType;

// The current WB manager
@Current
protected Manager webBeansManager;

/**
* Used to set the event bindings for this type of event after it is constructed
* with the default constructor.
* @param eventBindings Annotations that are bindings for the event
* Used to set the event bindings for this type of event after it is
* constructed with the default constructor.
*
* @param eventBindings
* Annotations that are bindings for the event
*/
public void setEventBindings(Annotation... eventBindings)
{
this.eventBindings = Arrays.asList(eventBindings);
Set<Annotation> newEventBindings = new HashSet<Annotation>();
addAnnotationBindings(newEventBindings, eventBindings);
this.eventBindings = newEventBindings;
}

/*
* (non-Javadoc)
*
Expand All @@ -60,10 +69,31 @@ public void fire(T event, Annotation... bindings)
.fireEvent(event, eventBindings.toArray(new Annotation[0]));
}

public void observe(Observer<T> observe, Annotation... bindings)
public void observe(Observer<T> observer, Annotation... bindings)
{
// TODO Auto-generated method stub

// Register the observer with the web beans manager
Class<T> eventArgumentClazz = null;
try
{
// TODO Fix me: Reflection can only get type variables, not the arguments used elsewhere
Field eventTypeField = this.getClass().getDeclaredField("eventType");
ParameterizedType genericType = (ParameterizedType) eventTypeField.getGenericType();
Type[] eventTypeArguments = genericType.getActualTypeArguments();
eventArgumentClazz = (Class<T>) eventTypeArguments[0];
} catch (SecurityException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchFieldException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}

Set<Annotation> eventBindings = new HashSet<Annotation>();
eventBindings.addAll(this.getBindingTypes());
addAnnotationBindings(eventBindings, bindings);
webBeansManager.addObserver(observer, eventArgumentClazz, bindings);
}

/**
Expand All @@ -72,16 +102,29 @@ public void observe(Observer<T> observe, Annotation... bindings)
* thrown.
*
* @param bindingsSet
* The set of annotation binding objects
* @param bindings
* An array of annotation bindings to add to the set
* @throws DuplicateBindingTypeException
* if any of bindings are duplicates
* @throws IllegalArgumentException
* if any annotation is not a binding type
*/
private void addAnnotationBindings(Set<Annotation> bindingsSet,
Annotation[] bindings)
{
if (bindings != null)
{
Set<Class<? extends Annotation>> bindingTypes = new HashSet<Class<? extends Annotation>>();
// Add the bindings types that are already in the set being added to. This will
// provide detection of duplicates across construction and later invocations.
for (Annotation annotation : bindingsSet)
{
bindingTypes.add(annotation.annotationType());
}

// Now go through the new annotations being added to make sure these are binding
// types and are not duplicates
for (Annotation annotation : bindings)
{
// Check that the binding type is indeed a binding type
Expand Down

0 comments on commit fda1a4d

Please sign in to comment.