Author: [EMAIL PROTECTED]
Date: Wed Nov 12 21:30:25 2008
New Revision: 4045
Modified:
branches/1_6_clean_events/user/src/com/google/gwt/event/shared/HandlerManager.java
branches/1_6_clean_events/user/test/com/google/gwt/event/shared/HandlerManagerTest.java
Log:
Ensure concurrent mods happen in the right order. Required undoing
optimization in JsRegistry that would do adds immediately, as immediately
is the wrong time if a remove came first
Modified:
branches/1_6_clean_events/user/src/com/google/gwt/event/shared/HandlerManager.java
==============================================================================
---
branches/1_6_clean_events/user/src/com/google/gwt/event/shared/HandlerManager.java
(original)
+++
branches/1_6_clean_events/user/src/com/google/gwt/event/shared/HandlerManager.java
Wed Nov 12 21:30:25 2008
@@ -18,6 +18,7 @@
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.event.shared.GwtEvent.Type;
+import com.google.gwt.user.client.Command;
import java.util.ArrayList;
import java.util.HashMap;
@@ -70,7 +71,12 @@
public <H> void removeHandler(GwtEvent.Type<H> eventKey, H handler) {
ArrayList<H> l = get(eventKey);
if (l != null) {
- l.remove(handler);
+ boolean result = l.remove(handler);
+ if (!result) {
+ // The client code has a similar assert. Relying on asserts in
+ // server code is dicey
+ throw new IllegalArgumentException("Tried to remove unknown
handler");
+ }
}
}
@@ -100,7 +106,7 @@
}
public final <H extends EventHandler> void addHandler(
- HandlerManager manager, Type<H> type, H myHandler) {
+ Type<H> type, H myHandler) {
// The base is the equivalent to a c pointer into the flattened
handler
// data structure.
@@ -112,12 +118,6 @@
// flattened data structure, store the handlers in an external list
// instead.
if ((count == EXPECTED_HANDLERS) & flattened) {
- // As long as we are only adding to the end of a handler list,
should
- // not need to queue.
- if (manager.firingDepth > 0) {
- manager.enqueueAdd(type, myHandler);
- return;
- }
unflatten(base);
flattened = false;
}
@@ -172,15 +172,14 @@
EventHandler handler) {
int base = eventKey.hashCode();
- // Removing a handler is unusual, so smaller code is preferable then
+ // Removing a handler is unusual, so smaller code is preferable to
// handling both flat and dangling list of pointers.
if (isFlattened(base)) {
unflatten(base);
}
boolean result = removeHelper(base, handler);
// Hiding this behind an assertion as we'd rather not force the
compiler
- // to
- // have to include all handler.toString() instances.
+ // to have to include all handler.toString() instances.
assert result : handler + " did not exist";
}
@@ -248,10 +247,6 @@
this[base + 1][index] = handler;
}-*/;
- private native void setHandlerList(int base, JavaScriptObject
handlerList) /*-{
- this[base + 1] = handlerList;
- }-*/;
-
private native void unflatten(int base) /*-{
var handlerList = {};
var count = this[base];
@@ -287,13 +282,10 @@
// source of the event.
private final Object source;
-
- // pending queue of removes that were called during event firing.
- private List<Object> removalQueue;
-
- // pending queue of adds that were called during event firing.
- private ArrayList<Object> addQueue;
-
+
+ // Add and remove operations received during dispatch.
+ private List<Command> deferredDeltas;
+
/**
* Creates a handler manager with the given source.
*
@@ -319,24 +311,10 @@
*/
public <H extends EventHandler> HandlerRegistration addHandler(
GwtEvent.Type<H> type, final H handler) {
-
- /*
- * We used to keep the enqueue / dequeue entirely inside
HandlerManager.
- * However, we found a 30% speed improvement in handler registration if
- * JsHandlerRegistry is allowed to make its own decision about
queuing. Thus
- * the funny code path here.
- *
- * No parallel optimization was made for removing handlers, as that
rarely
- * happens anyway, and is not a significant contributer to startup
time.
- */
- if (useJs) {
- javaScriptRegistry.addHandler(this, type, handler);
+ if (firingDepth > 0) {
+ enqueueAdd(type, handler);
} else {
- if (firingDepth > 0) {
- enqueueAdd(type, handler);
- } else {
- javaRegistry.addHandler(type, handler);
- }
+ doAdd(type, handler);
}
return new DefaultHandlerRegistration(this, type, handler);
}
@@ -388,7 +366,7 @@
public <H extends EventHandler> H getHandler(GwtEvent.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;
+ + " so do not have a handler at index: " + index;
if (useJs) {
return javaScriptRegistry.getHandler(type, index);
} else {
@@ -443,6 +421,22 @@
}
}
+ private void defer(Command command) {
+ if (deferredDeltas == null) {
+ deferredDeltas = new ArrayList<Command>();
+ }
+ deferredDeltas.add(command);
+ }
+
+ private <H extends EventHandler> void doAdd(GwtEvent.Type<H> type,
+ final H handler) {
+ if (useJs) {
+ javaScriptRegistry.addHandler(type, handler);
+ } else {
+ javaRegistry.addHandler(type, handler);
+ }
+ }
+
private <H extends EventHandler> void doRemove(GwtEvent.Type<H> type,
final H handler) {
if (useJs) {
@@ -452,40 +446,34 @@
}
}
- private <H extends EventHandler> void enqueueAdd(GwtEvent.Type<H> type,
+ private <H extends EventHandler> void enqueueAdd(final GwtEvent.Type<H>
type,
final H handler) {
- if (addQueue == null) {
- addQueue = new ArrayList<Object>();
- addQueue.add(type);
- addQueue.add(handler);
- }
+ defer(new Command() {
+ public void execute() {
+ doAdd(type, handler);
+ }
+ });
}
- private <H extends EventHandler> void enqueueRemove(GwtEvent.Type<H>
type,
- final H handler) {
- if (removalQueue == null) {
- removalQueue = new ArrayList<Object>();
- removalQueue.add(type);
- removalQueue.add(handler);
- }
+ private <H extends EventHandler> void enqueueRemove(
+ final GwtEvent.Type<H> type, final H handler) {
+ defer(new Command() {
+ public void execute() {
+ doRemove(type, handler);
+ }
+ });
}
@SuppressWarnings("unchecked")
private void handleQueuedAddsAndRemoves() {
- // Do Adds first in case someone does a quick add/remove
- if (addQueue != null) {
- for (int i = 0; i < addQueue.size(); i += 2) {
- addHandler((GwtEvent.Type) addQueue.get(i),
- (EventHandler) addQueue.get(i + 1));
- }
- addQueue = null;
- }
- if (removalQueue != null) {
- for (int i = 0; i < removalQueue.size(); i += 2) {
- doRemove((GwtEvent.Type) removalQueue.get(i),
- (EventHandler) removalQueue.get(i + 1));
+ if (deferredDeltas != null) {
+ try {
+ for (Command c : deferredDeltas) {
+ c.execute();
+ }
+ } finally {
+ deferredDeltas = null;
}
- removalQueue = null;
}
}
}
Modified:
branches/1_6_clean_events/user/test/com/google/gwt/event/shared/HandlerManagerTest.java
==============================================================================
---
branches/1_6_clean_events/user/test/com/google/gwt/event/shared/HandlerManagerTest.java
(original)
+++
branches/1_6_clean_events/user/test/com/google/gwt/event/shared/HandlerManagerTest.java
Wed Nov 12 21:30:25 2008
@@ -16,6 +16,7 @@
package com.google.gwt.event.shared;
+import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.DomEvent;
import com.google.gwt.event.dom.client.MouseDownEvent;
@@ -25,7 +26,6 @@
/**
* Handler manager test.
*/
[EMAIL PROTECTED]("deprecation")
public class HandlerManagerTest extends HandlerTestBase {
public void testAddHandlers() {
@@ -34,6 +34,7 @@
addHandlers(manager);
}
+ @SuppressWarnings("deprecation")
private void addHandlers(HandlerManager manager) {
manager.addHandler(MouseDownEvent.getType(), mouse1);
manager.addHandler(MouseDownEvent.getType(), mouse2);
@@ -64,6 +65,7 @@
assertNotFired(click1, click2);
}
+ @SuppressWarnings("deprecation")
public void testRemoveHandlers() {
HandlerManager manager = new HandlerManager("bogus source");
addHandlers(manager);
@@ -172,18 +174,46 @@
manager.addHandler(MouseDownEvent.getType(), mouse1);
manager.addHandler(MouseDownEvent.getType(), mouse2);
manager.addHandler(MouseDownEvent.getType(), mouse3);
- manager.fireEvent(new MouseDownEvent() {
- });
+ manager.fireEvent(new MouseDownEvent() { });
assertFired(one, mouse1, mouse2, mouse3);
assertNotFired(two);
reset();
- manager.fireEvent(new MouseDownEvent() {
- });
+ manager.fireEvent(new MouseDownEvent() { });
assertFired(one, mouse1, mouse2, mouse3);
assertNotFired(two);
}
+
+ @SuppressWarnings("deprecation")
+ public void testConcurrentAddAfterRemoveIsNotClobbered() {
+ final HandlerManager manager = new HandlerManager("bogus source");
+
+ MouseDownHandler one = new MouseDownHandler() {
+ public void onMouseDown(MouseDownEvent event) {
+ manager.removeHandler(MouseDownEvent.getType(), mouse1);
+ manager.addHandler(MouseDownEvent.getType(), mouse1);
+ add(this);
+ }
+ };
+ manager.addHandler(MouseDownEvent.getType(), one);
+
+ if (!GWT.isScript()) {
+ try {
+ manager.fireEvent(new MouseDownEvent() { });
+ fail("Should have thrown on remove");
+ } catch (AssertionError e) { /* pass */ }
+ return;
+ }
+
+ // Web mode, no asserts, so remove will quietly succeed.
+ manager.fireEvent(new MouseDownEvent() { });
+ assertFired(one);
+ reset();
+ manager.fireEvent(new MouseDownEvent() { });
+ assertFired(one, mouse1);
+ }
+ @SuppressWarnings("deprecation")
public void testMultiFiring() {
HandlerManager manager = new HandlerManager("source1");
--~--~---------~--~----~------------~-------~--~----~
http://groups.google.com/group/Google-Web-Toolkit-Contributors
-~----------~----~----~----~------~----~------~--~---