Add armor for exceptions thrown by Activity#onCancel
Review at http://gwt-code-reviews.appspot.com/1446816
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10272 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/activity/shared/ActivityManager.java b/user/src/com/google/gwt/activity/shared/ActivityManager.java
index 45f41b5..8cb9a33 100644
--- a/user/src/com/google/gwt/activity/shared/ActivityManager.java
+++ b/user/src/com/google/gwt/activity/shared/ActivityManager.java
@@ -95,13 +95,12 @@
* be minimized by decent caching. Perenially slow activities might mitigate
* this by providing a widget immediately, with some kind of "loading"
* treatment.
- *
- * @see com.google.gwt.place.shared.PlaceChangeEvent.Handler#onPlaceChange(PlaceChangeEvent)
*/
public void onPlaceChange(PlaceChangeEvent event) {
Activity nextActivity = getNextActivity(event);
Throwable caughtOnStop = null;
+ Throwable caughtOnCancel = null;
Throwable caughtOnStart = null;
if (nextActivity == null) {
@@ -115,7 +114,7 @@
if (startingNext) {
// The place changed again before the new current activity showed its
// widget
- currentActivity.onCancel();
+ caughtOnCancel = tryStopOrCancel(false);
currentActivity = NULL_ACTIVITY;
startingNext = false;
} else if (!currentActivity.equals(NULL_ACTIVITY)) {
@@ -126,46 +125,26 @@
* them accidentally firing as a side effect of its tear down
*/
stopperedEventBus.removeHandlers();
-
- try {
- currentActivity.onStop();
- } catch (Throwable t) {
- caughtOnStop = t;
- } finally {
- /*
- * And kill them off again in case it was naughty and added new ones
- * during onstop
- */
- stopperedEventBus.removeHandlers();
- }
+ caughtOnStop = tryStopOrCancel(true);
}
currentActivity = nextActivity;
if (currentActivity.equals(NULL_ACTIVITY)) {
showWidget(null);
- return;
+ } else {
+ startingNext = true;
+ caughtOnStart = tryStart();
}
-
- startingNext = true;
-
- /*
- * Now start the thing. Wrap the actual display with a per-call instance
- * that protects the display from canceled or stopped activities, and which
- * maintains our startingNext state.
- */
- try {
- currentActivity.start(new ProtectedDisplay(currentActivity),
- stopperedEventBus);
- } catch (Throwable t) {
- caughtOnStart = t;
- }
-
- if (caughtOnStart != null || caughtOnStop != null) {
+
+ if (caughtOnStart != null || caughtOnCancel != null || caughtOnStop != null) {
Set<Throwable> causes = new LinkedHashSet<Throwable>();
if (caughtOnStop != null) {
causes.add(caughtOnStop);
}
+ if (caughtOnCancel != null) {
+ causes.add(caughtOnCancel);
+ }
if (caughtOnStart != null) {
causes.add(caughtOnStart);
}
@@ -180,9 +159,7 @@
* @see com.google.gwt.place.shared.PlaceChangeRequestEvent.Handler#onPlaceChangeRequest(PlaceChangeRequestEvent)
*/
public void onPlaceChangeRequest(PlaceChangeRequestEvent event) {
- if (!currentActivity.equals(NULL_ACTIVITY)) {
- event.setWarning(currentActivity.mayStop());
- }
+ event.setWarning(currentActivity.mayStop());
}
/**
@@ -204,6 +181,41 @@
}
}
+ public Throwable tryStart() {
+ Throwable caughtOnStart = null;
+ try {
+ /* Wrap the actual display with a per-call instance
+ * that protects the display from canceled or stopped activities, and which
+ * maintains our startingNext state.
+ */
+ currentActivity.start(new ProtectedDisplay(currentActivity),
+ stopperedEventBus);
+ } catch (Throwable t) {
+ caughtOnStart = t;
+ }
+ return caughtOnStart;
+ }
+
+ public Throwable tryStopOrCancel(boolean stop) {
+ Throwable caughtOnStop = null;
+ try {
+ if (stop) {
+ currentActivity.onStop();
+ } else {
+ currentActivity.onCancel();
+ }
+ } catch (Throwable t) {
+ caughtOnStop = t;
+ } finally {
+ /*
+ * Kill off the handlers again in case it was naughty and added new ones
+ * during onstop or oncancel
+ */
+ stopperedEventBus.removeHandlers();
+ }
+ return caughtOnStop;
+ }
+
private Activity getNextActivity(PlaceChangeEvent event) {
if (display == null) {
/*
diff --git a/user/test/com/google/gwt/activity/shared/ActivityManagerTest.java b/user/test/com/google/gwt/activity/shared/ActivityManagerTest.java
index ece9341..62a4af8 100644
--- a/user/test/com/google/gwt/activity/shared/ActivityManagerTest.java
+++ b/user/test/com/google/gwt/activity/shared/ActivityManagerTest.java
@@ -305,18 +305,18 @@
assertEquals(0, eventBus.getCount(PlaceChangeRequestEvent.TYPE));
}
- public void testExceptionsOnStopAndStart() {
- activity1 = new SyncActivity(null) {
+ public void testExceptionsOnStartAndCancel() {
+ activity1 = new AsyncActivity(null) {
@Override
public void start(AcceptsOneWidget panel, EventBus eventBus) {
super.start(panel, eventBus);
bus.addHandler(Event.TYPE, new Handler());
}
@Override
- public void onStop() {
- super.onStop();
+ public void onCancel() {
+ super.onCancel();
bus.addHandler(Event.TYPE, new Handler());
- throw new UnsupportedOperationException("Auto-generated method stub");
+ throw new UnsupportedOperationException("Exception on cancel");
}
};
@@ -324,7 +324,7 @@
@Override
public void start(AcceptsOneWidget panel, EventBus eventBus) {
super.start(panel, eventBus);
- throw new UnsupportedOperationException("Auto-generated method stub");
+ throw new UnsupportedOperationException("Exception on start");
}
};
@@ -340,9 +340,56 @@
fail("Expected exception");
} catch (UmbrellaException e) {
- // HandlerManager throws this one
+ // EventBus throws this one
assertEquals(1, e.getCauses().size());
+ // And this is the one thrown by ActivityManager
+ UmbrellaException nested = (UmbrellaException) e.getCause();
+ assertEquals(2, nested.getCauses().size());
+ }
+ assertTrue(activity1.canceled);
+ assertNotNull(activity2.display);
+ assertEquals(0, eventBus.getCount(Event.TYPE));
+ }
+
+ public void testExceptionsOnStopAndStart() {
+ activity1 = new SyncActivity(null) {
+ @Override
+ public void start(AcceptsOneWidget panel, EventBus eventBus) {
+ super.start(panel, eventBus);
+ bus.addHandler(Event.TYPE, new Handler());
+ }
+ @Override
+ public void onStop() {
+ super.onStop();
+ bus.addHandler(Event.TYPE, new Handler());
+ throw new UnsupportedOperationException("Exception on stop");
+ }
+ };
+
+ activity2 = new SyncActivity(null) {
+ @Override
+ public void start(AcceptsOneWidget panel, EventBus eventBus) {
+ super.start(panel, eventBus);
+ throw new UnsupportedOperationException("Exception on start");
+ }
+ };
+
+ manager.setDisplay(realDisplay);
+
+ try {
+ PlaceChangeEvent event = new PlaceChangeEvent(place1);
+ eventBus.fireEvent(event);
+ assertEquals(1, eventBus.getCount(Event.TYPE));
+
+ event = new PlaceChangeEvent(place2);
+ eventBus.fireEvent(event);
+
+ fail("Expected exception");
+ } catch (UmbrellaException e) {
+ // EventBus throws this one
+ assertEquals(1, e.getCauses().size());
+ // And this is the one thrown by ActivityManager
UmbrellaException nested = (UmbrellaException) e.getCause();
assertEquals(2, nested.getCauses().size());
}