Revision: 10272
Author:   [email protected]
Date:     Fri Jun  3 08:57:30 2011
Log:      Add armor for exceptions thrown by Activity#onCancel

Review at http://gwt-code-reviews.appspot.com/1446816

http://code.google.com/p/google-web-toolkit/source/detail?r=10272

Modified:
 /trunk/user/src/com/google/gwt/activity/shared/ActivityManager.java
 /trunk/user/test/com/google/gwt/activity/shared/ActivityManagerTest.java

=======================================
--- /trunk/user/src/com/google/gwt/activity/shared/ActivityManager.java Mon Apr 18 13:47:45 2011 +++ /trunk/user/src/com/google/gwt/activity/shared/ActivityManager.java Fri Jun 3 08:57:30 2011
@@ -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;
-    }
-
-    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) {
+    } else {
+      startingNext = true;
+      caughtOnStart = tryStart();
+    }
+
+ 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());
   }

   /**
@@ -203,6 +180,41 @@
       updateHandlers(willBeActive);
     }
   }
+
+  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) {
=======================================
--- /trunk/user/test/com/google/gwt/activity/shared/ActivityManagerTest.java Mon Apr 18 16:25:25 2011 +++ /trunk/user/test/com/google/gwt/activity/shared/ActivityManagerTest.java Fri Jun 3 08:57:30 2011
@@ -305,6 +305,53 @@
     assertEquals(0, eventBus.getCount(PlaceChangeRequestEvent.TYPE));
   }

+  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 onCancel() {
+        super.onCancel();
+        bus.addHandler(Event.TYPE, new Handler());
+        throw new UnsupportedOperationException("Exception on cancel");
+      }
+    };
+
+    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());
+    }
+
+    assertTrue(activity1.canceled);
+    assertNotNull(activity2.display);
+    assertEquals(0, eventBus.getCount(Event.TYPE));
+  }
+
   public void testExceptionsOnStopAndStart() {
     activity1 = new SyncActivity(null) {
       @Override
@@ -316,7 +363,7 @@
       public void onStop() {
         super.onStop();
         bus.addHandler(Event.TYPE, new Handler());
- throw new UnsupportedOperationException("Auto-generated method stub");
+        throw new UnsupportedOperationException("Exception on stop");
       }
     };

@@ -324,7 +371,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 +387,9 @@

       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());
     }

--
http://groups.google.com/group/Google-Web-Toolkit-Contributors

Reply via email to