All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.web.bindery.event.shared.SimpleEventBus Maven / Gradle / Ivy

There is a newer version: 2.10.0
Show newest version
/*
 * Copyright 2011 Google Inc.
 * 
 * Licensed 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 com.google.web.bindery.event.shared;

import com.google.web.bindery.event.shared.Event.Type;

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;

/**
 * Basic implementation of {@link EventBus}.
 */
public class SimpleEventBus extends EventBus {
  private interface Command {
    void execute();
  }

  private final boolean isReverseOrder;

  private int firingDepth = 0;

  /**
   * Add and remove operations received during dispatch.
   */
  private List deferredDeltas;

  /**
   * Map of event type to map of event source to list of their handlers.
   */
  private final Map, Map>> map =
      new HashMap, Map>>();

  public SimpleEventBus() {
    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.
   * 

* * @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 SimpleEventBus(boolean fireInReverseOrder) { isReverseOrder = fireInReverseOrder; } @Override public HandlerRegistration addHandler(Type type, H handler) { return doAdd(type, null, handler); } @Override public HandlerRegistration addHandlerToSource(final Event.Type 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 void doRemove(Event.Type type, Object source, H handler) { if (firingDepth > 0) { enqueueRemove(type, source, handler); } else { doRemoveNow(type, source, handler); } } /** * @deprecated required by legacy features in GWT's old HandlerManager */ @Deprecated protected H getHandler(Event.Type 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 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 void defer(Command command) { if (deferredDeltas == null) { deferredDeltas = new ArrayList(); } deferredDeltas.add(command); } private HandlerRegistration doAdd(final Event.Type 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"); } if (firingDepth > 0) { enqueueAdd(type, source, handler); } else { doAddNow(type, source, handler); } return new HandlerRegistration() { public void removeHandler() { doRemove(type, source, handler); } }; } private void doAddNow(Event.Type type, Object source, H handler) { List l = ensureHandlerList(type, source); l.add(handler); } private void doFire(Event event, Object source) { if (event == null) { throw new NullPointerException("Cannot fire null event"); } try { firingDepth++; if (source != null) { event.setSource(source); } List handlers = getDispatchList(event.getAssociatedType(), source); Set causes = null; ListIterator 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(); } causes.add(e); } } if (causes != null) { throw new UmbrellaException(causes); } } finally { firingDepth--; if (firingDepth == 0) { handleQueuedAddsAndRemoves(); } } } private void doRemoveNow(Event.Type type, Object source, H handler) { List l = getHandlerList(type, source); boolean removed = l.remove(handler); assert removed : "redundant remove call"; if (removed && l.isEmpty()) { prune(type, source); } } private void enqueueAdd(final Event.Type type, final Object source, final H handler) { defer(new Command() { public void execute() { doAddNow(type, source, handler); } }); } private void enqueueRemove(final Event.Type type, final Object source, final H handler) { defer(new Command() { public void execute() { doRemoveNow(type, source, handler); } }); } private List ensureHandlerList(Event.Type type, Object source) { Map> sourceMap = map.get(type); if (sourceMap == null) { sourceMap = new HashMap>(); map.put(type, sourceMap); } // safe, we control the puts. @SuppressWarnings("unchecked") List handlers = (List) sourceMap.get(source); if (handlers == null) { handlers = new ArrayList(); sourceMap.put(source, handlers); } return handlers; } private List getDispatchList(Event.Type type, Object source) { List directHandlers = getHandlerList(type, source); if (source == null) { return directHandlers; } List globalHandlers = getHandlerList(type, null); List rtn = new ArrayList(directHandlers); rtn.addAll(globalHandlers); return rtn; } private List getHandlerList(Event.Type type, Object source) { Map> sourceMap = map.get(type); if (sourceMap == null) { return Collections.emptyList(); } // safe, we control the puts. @SuppressWarnings("unchecked") List handlers = (List) sourceMap.get(source); if (handlers == null) { return Collections.emptyList(); } return handlers; } private void handleQueuedAddsAndRemoves() { if (deferredDeltas != null) { try { for (Command c : deferredDeltas) { c.execute(); } } finally { deferredDeltas = null; } } } private void prune(Event.Type type, Object source) { Map> 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); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy