Tuesday, July 26, 2011

Re: SimpleEventBus : why such a non-predictive behavior implementation ?

No body concerned ?

On 25 juil, 10:50, "david.herv...@gmail.com" <david.herv...@gmail.com>
wrote:
> Hi,
>
> I'm facing a problem when using the simple implementation of the
> EventBus.
>
> // register widget B to be notified when WidgetA trigger an event
> register handler of WidgetB on WidgetA.EventType
>
> // dispatch (firingDepth is incremented)
> WidgetA.fireEvent
>
> // my widget is really called !!! that's good news
> WidgetB.onWidgetAEvent
>
> // on the WidgetA.EventType reception is decided to create a widget C
> create widgetC
>
> // this widget register himself to be notified on widgetB events ->
> here the widget is registered in the deferredDeltas map (enqueueing)
> register handler of widgetC on WidgetB.EventType
>
> // widget B fired an event which is never trapped by the widget C
> because the handler of Widget C is in the deferredDeltas AND
> firingDepth is not 0
> WidgetB.fireEvent
>
> I'm doubtful because I was expected Widget C to receive event from
> Widget B. A work around is to encapsulate the WidgetB.fireEvent into a
> DeferredCommand but it's not really a solution.
>
> An other solution is to reconsider the usage of firingDepth, I don't
> really know why it is used (actually I know, but avoid concurrency
> modification that way leads to the upper that strange behavior).
> In simple implementation (thread safe) will be to get rid of the usage
> of this firingDepth/deferredDeltas and that getHandlerList return a
> copy of the handlers to go through and that's it:
> We insert directly the handler when they request for registration and
> we fire on the current map of handlers
>
> Below is a possible implementation of what I think is a better
> implementation (behaviorally speaking) :
>
> package com.google.web.bindery.event.shared;
>
> import java.util.ArrayList;
> import java.util.Collections;
> import java.util.HashMap;
> import java.util.HashSet;
> import java.util.List;
> import java.util.ListIterator;
> import java.util.Map;
> import java.util.Set;
>
> import com.google.web.bindery.event.shared.Event.Type;
>
> public class MySimpleEventBus extends EventBus {
>
>     private final boolean isReverseOrder;
>
>     /**
>      * Map of event type to map of event source to list of their
> handlers.
>      */
>     private final Map<Event.Type<?>, Map<Object, List<?>>> map =
>         new HashMap<Event.Type<?>, Map<Object, List<?>>>();
>
>     public MySimpleEventBus() {
>       this(false);
>     }
>
>     /**
>      * Allows creation of an instance that fires its handlers in the
> reverse of
>      * the order in which they were added, although filtered handlers
> all fire
>      * before unfiltered handlers.
>      * <p>
>      *
>      * @deprecated This is a legacy feature, required by GWT's old
> HandlerManager.
>      *             Reverse order is not honored for handlers tied to a
> specific
>      *             event source (via {@link #addHandlerToSource}.
>      */
>     @Deprecated
>     protected MySimpleEventBus(boolean fireInReverseOrder) {
>       isReverseOrder = fireInReverseOrder;
>     }
>
>     @Override
>     public <H> HandlerRegistration addHandler(Type<H> type, H handler)
> {
>       return doAdd(type, null, handler);
>     }
>
>     @Override
>     public <H> HandlerRegistration addHandlerToSource(final
> Event.Type<H> type, final Object source,
>         final H handler) {
>       if (source == null) {
>         throw new NullPointerException("Cannot add a handler with a
> null source");
>       }
>
>       return doAdd(type, source, handler);
>     }
>
>     @Override
>     public void fireEvent(Event<?> event) {
>       doFire(event, null);
>     }
>
>     @Override
>     public void fireEventFromSource(Event<?> event, Object source) {
>       if (source == null) {
>         throw new NullPointerException("Cannot fire from a null
> source");
>       }
>       doFire(event, source);
>     }
>
>     /**
>      * @deprecated required by legacy features in GWT's old
> HandlerManager
>      */
>     @Deprecated
>     protected <H> void doRemove(Event.Type<H> type, Object source, H
> handler) {
>         doRemoveNow(type, source, handler);
>     }
>
>     /**
>      * @deprecated required by legacy features in GWT's old
> HandlerManager
>      */
>     @Deprecated
>     protected <H> H getHandler(Event.Type<H> type, int index) {
>       assert index < getHandlerCount(type) : "handlers for " +
> type.getClass() + " have size: "
>           + getHandlerCount(type) + " so do not have a handler at
> index: " + index;
>
>       List<H> l = getHandlerList(type, null);
>       return l.get(index);
>     }
>
>     /**
>      * @deprecated required by legacy features in GWT's old
> HandlerManager
>      */
>     @Deprecated
>     protected int getHandlerCount(Event.Type<?> eventKey) {
>       return getHandlerList(eventKey, null).size();
>     }
>
>     /**
>      * @deprecated required by legacy features in GWT's old
> HandlerManager
>      */
>     @Deprecated
>     protected boolean isEventHandled(Event.Type<?> eventKey) {
>       return map.containsKey(eventKey);
>     }
>
>     private <H> HandlerRegistration doAdd(final Event.Type<H> type,
> final Object source,
>         final H handler) {
>       if (type == null) {
>         throw new NullPointerException("Cannot add a handler with a
> null type");
>       }
>       if (handler == null) {
>         throw new NullPointerException("Cannot add a null handler");
>       }
>
>       doAddNow(type, source, handler);
>
>       return new HandlerRegistration() {
>         public void removeHandler() {
>           doRemove(type, source, handler);
>         }
>       };
>     }
>
>     private <H> void doAddNow(Event.Type<H> type, Object source, H
> handler) {
>       List<H> l = ensureHandlerList(type, source);
>       l.add(handler);
>     }
>
>     private <H> void doFire(Event<H> event, Object source) {
>       if (event == null) {
>         throw new NullPointerException("Cannot fire null event");
>       }
>       try {
>
>         if (source != null) {
>           event.setSource(source);
>         }
>
>         List<H> handlers = getDispatchList(event.getAssociatedType(),
> source);
>         Set<Throwable> causes = null;
>
>         ListIterator<H> it =
>             isReverseOrder ? handlers.listIterator(handlers.size()) :
> handlers.listIterator();
>         while (isReverseOrder ? it.hasPrevious() : it.hasNext()) {
>           H handler = isReverseOrder ? it.previous() : it.next();
>
>           try {
>             event.dispatch(handler);
>           } catch (Throwable e) {
>             if (causes == null) {
>               causes = new HashSet<Throwable>();
>             }
>             causes.add(e);
>           }
>         }
>
>         if (causes != null) {
>           throw new UmbrellaException(causes);
>         }
>       } finally {
>         // no more to do
>       }
>     }
>
>     private <H> void doRemoveNow(Event.Type<H> type, Object source, H
> handler) {
>       List<H> l = getHandlerList(type, source);
>
>       boolean removed = l.remove(handler);
>       assert removed : "redundant remove call";
>       if (removed && l.isEmpty()) {
>         prune(type, source);
>       }
>     }
>
>     private <H> List<H> ensureHandlerList(Event.Type<H> type, Object
> source) {
>       Map<Object, List<?>> sourceMap = map.get(type);
>       if (sourceMap == null) {
>         sourceMap = new HashMap<Object, List<?>>();
>         map.put(type, sourceMap);
>       }
>
>       // safe, we control the puts.
>       @SuppressWarnings("unchecked")
>       List<H> handlers = (List<H>) sourceMap.get(source);
>       if (handlers == null) {
>         handlers = new ArrayList<H>();
>         sourceMap.put(source, handlers);
>       }
>
>       return handlers;
>     }
>
>    /**
>     * Return a copy of handlers to dispatch event to
>     */
>     private <H> List<H> getDispatchList(Event.Type<H> type, Object
> source) {
>       List<H> directHandlers = getHandlerList(type, source);
>       if (source == null) {
>         return new ArrayList<H>(directHandlers);
>       }
>
>       List<H> globalHandlers = getHandlerList(type, null);
>
>       List<H> rtn = new ArrayList<H>(directHandlers);
>       rtn.addAll(globalHandlers);
>       return rtn;
>     }
>
>     private <H> List<H> getHandlerList(Event.Type<H> type, Object
> source) {
>       Map<Object, List<?>> sourceMap = map.get(type);
>       if (sourceMap == null) {
>         return Collections.emptyList();
>       }
>
>       // safe, we control the puts.
>       @SuppressWarnings("unchecked")
>       List<H> handlers = (List<H>) sourceMap.get(source);
>       if (handlers == null) {
>         return Collections.emptyList();
>       }
>
>       return handlers;
>     }
>
>     private void prune(Event.Type<?> type, Object source) {
>       Map<Object, List<?>> sourceMap = map.get(type);
>
>       List<?> pruned = sourceMap.remove(source);
>
>       assert pruned != null : "Can't prune what wasn't there";
>       assert pruned.isEmpty() : "Pruned unempty list!";
>
>       if (sourceMap.isEmpty()) {
>         map.remove(type);
>       }
>     }
>
>   }

--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
To post to this group, send email to google-web-toolkit@googlegroups.com.
To unsubscribe from this group, send email to google-web-toolkit+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.

No comments:

Post a Comment