null
.
+ */
+ private static final class DefaultUncaughtExceptionHandler implements
+ UncaughtExceptionHandler {
+ @Override
+ public void onUncaughtException(Throwable e) {
+ log("Uncaught exception escaped", e);
+ }
+ }
+
+ /**
+ * This constant is used by {@link #getPermutationStrongName} when running in
+ * Development Mode.
+ */
+ public static final String HOSTED_MODE_PERMUTATION_STRONG_NAME = "HostedMode";
+
+ /**
+ * Defaults to null
in Production Mode and an instance of
+ * {@link DefaultUncaughtExceptionHandler} in Development Mode.
+ */
+ private static UncaughtExceptionHandler uncaughtExceptionHandler = null;
+
+ /**
+ * Instantiates a class via deferred binding.
+ *
+ * + * The argument to {@link #create(Class)} must be a class literal + * because the Production Mode compiler must be able to statically determine + * the requested type at compile-time. This can be tricky because using a + * {@link Class} variable may appear to work correctly in Development Mode. + *
+ * + * @param classLiteral a class literal specifying the base class to be + * instantiated + * @return the new instance, which must be cast to the requested class + */ + public static+ * Normally this will be the same value as {@link #getModuleBaseURL}, but + * may be different when a GWT app is configured to get its static resources + * from a different server. + *
+ * + * @return if non-empty, the base URL is guaranteed to end with a slash + */ + public static String getModuleBaseForStaticFiles() { + return Impl.getModuleBaseURLForStaticFiles(); + } + + /** + * Gets the URL prefix that should be prepended to URLs that + * are intended to be module-relative, such as RPC entry points. + * + *If the URL points to an output file of the GWT compiler (such as + * a file in the public path), use {@link #getModuleBaseForStaticFiles()} + * instead.
+ * + * @return if non-empty, the base URL is guaranteed to end with a slash + */ + public static String getModuleBaseURL() { + return Impl.getModuleBaseURL(); + } + + /** + * Gets the name of the running module. + */ + public static String getModuleName() { + return Impl.getModuleName(); + } + + /** + * Returns the permutation's strong name. This can be used to distinguish + * between different permutations of the same module. In Development Mode, + * this method will return {@value #HOSTED_MODE_PERMUTATION_STRONG_NAME}. + */ + public static String getPermutationStrongName() { + if (GWT.isScript()) { + return Impl.getPermutationStrongName(); + } else { + return HOSTED_MODE_PERMUTATION_STRONG_NAME; + } + } + + /** + * @deprecated Use {@link Object#getClass()}, {@link Class#getName()} + */ + @Deprecated + public static String getTypeName(Object o) { + return (o == null) ? null : o.getClass().getName(); + } + + /** + * Returns the currently active uncaughtExceptionHandler. + * + * @return the currently active handler, or null if no handler is active. + * + * @see #reportUncaughtException(Throwable) + */ + public static UncaughtExceptionHandler getUncaughtExceptionHandler() { + return uncaughtExceptionHandler; + } + + /** + * Reports an exception caught at the "top level" to a handler set via + * {@link #setUncaughtExceptionHandler(UncaughtExceptionHandler)}. This is + * used in places where the browser calls into user code such as event + * callbacks, timers, and RPC. + *
+ * If no {@code UncaughtExceptionHandler} is set, the exception is reported
+ * to browser. Browsers usually log these exceptions to the JavaScript
+ * console.
+ */
+ public static void reportUncaughtException(Throwable e) {
+ Impl.reportUncaughtException(e);
+ }
+
+ /**
+ * Returns the empty string when running in Production Mode, but returns a
+ * unique string for each thread in Development Mode (for example, different
+ * windows accessing the dev mode server will each have a unique id, and
+ * hitting refresh without restarting dev mode will result in a new unique id
+ * for a particular window.
+ *
+ * TODO(unnurg): Remove this function once Dev Mode rewriting classes are in
+ * gwt-dev.
+ */
+ public static String getUniqueThreadId() {
+ return com.google.gwt.core.shared.GWT.getUniqueThreadId();
+ }
+
+ public static String getVersion() {
+ String version = com.google.gwt.core.shared.GWT.getVersion();
+ if (version == null) {
+ version = getVersion0();
+ }
+ return version;
+ }
+
+ /**
+ * Returns true
when running inside the normal GWT environment,
+ * either in Development Mode or Production Mode. Returns false
+ * if this code is running in a plain JVM. This might happen when running
+ * shared code on the server, or during the bootstrap sequence of a
+ * GWTTestCase test.
+ */
+ public static boolean isClient() {
+ return com.google.gwt.core.shared.GWT.isClient();
+ }
+
+ /**
+ * Returns true
when running in production mode. Returns
+ * false
when running either in development mode, or when running
+ * in a plain JVM.
+ */
+ public static boolean isProdMode() {
+ return com.google.gwt.core.shared.GWT.isProdMode();
+ }
+
+ /**
+ * Determines whether or not the running program is script or bytecode.
+ */
+ public static boolean isScript() {
+ return com.google.gwt.core.shared.GWT.isScript();
+ }
+
+ /**
+ * Logs a message to the development shell logger in Development Mode, or to
+ * the console in Super Dev Mode. Calls are optimized out in Production Mode.
+ */
+ public static void log(String message) {
+ com.google.gwt.core.shared.GWT.log(message);
+ }
+
+ /**
+ * Logs a message to the development shell logger in Development Mode, or to
+ * the console in Super Dev Mode. Calls are optimized out in Production Mode.
+ */
+ public static void log(String message, Throwable e) {
+ com.google.gwt.core.shared.GWT.log(message, e);
+ }
+
+ /**
+ * Emits a JavaScript "debugger" statement on the line that called this method.
+ * If the user has the browser's debugger open, the debugger will stop when the
+ * GWT application executes that line. There is no effect in Dev Mode or in
+ * server-side code.
+ */
+ public static void debugger() {
+ }
+
+ /**
+ * The same as {@link #runAsync(RunAsyncCallback)}, except with an extra
+ * parameter to provide a name for the call. The name parameter should be
+ * supplied with a class literal. If two GWT.runAsync calls use the same
+ * class literal, the codesplitter will put the corresponding code in
+ * the same code fragment.
+ */
+ @SuppressWarnings("unused") // parameter will be used following replacement
+ public static void runAsync(Class> name, final RunAsyncCallback callback) {
+ runAsyncImpl(callback);
+ }
+
+
+ /**
+ * Run the specified callback once the necessary code for it has been loaded.
+ */
+ public static void runAsync(final RunAsyncCallback callback) {
+ runAsyncImpl(callback);
+ }
+
+ private static void runAsyncImpl(final RunAsyncCallback callback) {
+// Scheduler.get().scheduleDeferred(new ScheduledCommand() {
+// @Override public void execute() {
+// callback.onSuccess();
+// }
+// });
+ callback.onSuccess();
+ }
+
+ /**
+ * Sets a custom uncaught exception handler. See
+ * {@link #getUncaughtExceptionHandler()} for details.
+ *
+ * @param handler the handler that should be called when an exception is
+ * about to escape to the browser, or null
to clear the
+ * handler and allow exceptions to escape.
+ */
+ public static void setUncaughtExceptionHandler(
+ UncaughtExceptionHandler handler) {
+ uncaughtExceptionHandler = handler;
+ }
+
+ /**
+ * Called via reflection in Development Mode; do not ever call this method in
+ * Production Mode.
+ */
+ static void setBridge(GWTBridge bridge) {
+ com.google.gwt.core.shared.GWT.setBridge(bridge);
+ if (bridge != null) {
+ setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler());
+ }
+ }
+
+ private static native String getVersion0() /*-{
+ return $gwt_version;
+ }-*/;
+
+ /**
+ * If enabled via <set-property name="gwt.unloadEnabled" value="true"/> invoking this method causes the module
+ * to be removed from memory and all {@link com.google.gwt.core.client.impl.Disposable} instances to be
+ * cleaned up. This method is not typically called by the GWT module itself, but exported so that another module
+ * may call it.
+ * @see com.google.gwt.core.client.GWT#exportUnloadModule()
+ */
+ private static void unloadModule() {
+ Impl.unloadModule();
+ }
+}
diff --git a/SPALibrary/src/com/google/gwt/core/client/JavaScriptException.java b/SPALibrary/src/com/google/gwt/core/client/JavaScriptException.java
index c49bae3..005bab4 100644
--- a/SPALibrary/src/com/google/gwt/core/client/JavaScriptException.java
+++ b/SPALibrary/src/com/google/gwt/core/client/JavaScriptException.java
@@ -13,7 +13,7 @@
* License for the specific language governing permissions and limitations under
* the License.
*
- * Modified for the SPA Library May 2013 to eliminate the JavascriptObject dependency
+ * Modified for SPALibrary in Mar 2014 to remove StackTraceCreator Dependancy
*/
package com.google.gwt.core.client;
@@ -46,6 +46,8 @@
*/
public final class JavaScriptException extends RuntimeException {
+ private static final Object NOT_SET = new Object();
+
private static String getExceptionDescription(Object e) {
if (e instanceof JavaScriptObject) {
return getExceptionDescription0((JavaScriptObject) e);
@@ -74,12 +76,10 @@ private static native String getExceptionName0(JavaScriptObject e) /*-{
return (e == null) ? null : e.name;
}-*/;
- private static String getExceptionProperties(Object e) {
- return "";
- // SP EDIT
+// private static String getExceptionProperties(Object e) {
// return (GWT.isScript() && e instanceof JavaScriptObject)
// ? StackTraceCreator.getProperties((JavaScriptObject) e) : "";
- }
+// }
/**
* The original description of the JavaScript exception this class wraps,
@@ -128,28 +128,40 @@ public JavaScriptException(Object e, String description) {
* thrown object, although this is not possible in all browsers.
*/
if (GWT.isScript()) {
- // StackTraceCreator.createStackTrace(this);
+ //StackTraceCreator.createStackTrace(this);
}
}
-
+
public JavaScriptException(String name, String description) {
this.message = "JavaScript " + name + " exception: " + description;
this.name = name;
this.description = description;
- this.e = null;
+ this.e = NOT_SET;
}
/**
- * Used for server-side instantiation during JUnit runs. Exceptions are
- * manually marshaled through
- * com.google.gwt.junit.client.impl.ExceptionWrapper
objects.
- *
+ * Used for testing instantiations.
+ *
* @param message the detail message
*/
protected JavaScriptException(String message) {
super(message);
this.message = this.description = message;
- this.e = null;
+ this.e = NOT_SET;
+ }
+
+ /**
+ * Returns {@code true} if a thrown object is not set for the exception.
+ */
+ public boolean isThrownSet() {
+ return e != NOT_SET;
+ }
+
+ /**
+ * Returns the original thrown object from javascript; may be {@code null}.
+ */
+ public Object getThrown() {
+ return e == NOT_SET ? null : e;
}
/**
@@ -157,24 +169,23 @@ protected JavaScriptException(String message) {
* null
.
*/
public String getDescription() {
- if (message == null) {
- init();
- }
+ ensureInit();
return description;
}
/**
* Returns the original JavaScript the exception; may be null
.
+ *
+ * @deprecated deprecated in favor for {@link #getThrown()} and {@link #isThrownSet()}
*/
+ @Deprecated
public JavaScriptObject getException() {
return (e instanceof JavaScriptObject) ? (JavaScriptObject) e : null;
}
@Override
public String getMessage() {
- if (message == null) {
- init();
- }
+ ensureInit();
return message;
}
@@ -183,16 +194,17 @@ public String getMessage() {
* null
.
*/
public String getName() {
- if (message == null) {
- init();
- }
+ ensureInit();
return name;
}
- private void init() {
- name = getExceptionName(e);
- description = description + ": " + getExceptionDescription(e);
- message = "(" + name + ") " + getExceptionProperties(e) + description;
+ private void ensureInit() {
+ if (message == null) {
+ Object exception = getThrown();
+ name = getExceptionName(exception);
+ description = description + ": " + getExceptionDescription(exception);
+ message = "(" + name + ") " + /*getExceptionProperties(exception) +*/ description;
+ }
}
-}
+}
\ No newline at end of file
diff --git a/SPALibrary/src/com/google/gwt/core/client/impl/Impl.java b/SPALibrary/src/com/google/gwt/core/client/impl/Impl.java
index 26f8d34..9cc4d7d 100644
--- a/SPALibrary/src/com/google/gwt/core/client/impl/Impl.java
+++ b/SPALibrary/src/com/google/gwt/core/client/impl/Impl.java
@@ -13,12 +13,14 @@
* License for the specific language governing permissions and limitations under
* the License.
*
- * Modified for the SPA Library May 2013 to eliminate the SchedulerImpl dependency
+ * Modified for SPALibrary in March 2014 to remove Scheduler Dependency
*/
package com.google.gwt.core.client.impl;
import com.google.gwt.core.client.Duration;
import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.GWT.UncaughtExceptionHandler;
+import com.google.gwt.core.client.JavaScriptException;
import com.google.gwt.core.client.JavaScriptObject;
/**
@@ -27,6 +29,8 @@
*/
public final class Impl {
+ public static boolean moduleUnloaded = false;
+
private static final int WATCHDOG_ENTRY_DEPTH_CHECK_INTERVAL_MS = 2000;
/**
@@ -45,6 +49,25 @@ public final class Impl {
*/
private static int watchdogEntryDepthTimerId = -1;
+ private static UnloadSupport unloadSupport = GWT.isScript() ?
+ (UnloadSupport) GWT.create(UnloadSupport.class) : new UnloadSupport();
+
+ static {
+ exportUnloadModule();
+ }
+
+ public static void clearInterval(int timerId) {
+ unloadSupport.clearInterval(timerId);
+ }
+
+ public static void clearTimeout(int timerId) {
+ unloadSupport.clearTimeout(timerId);
+ }
+
+ public static void dispose(Disposable d) {
+ unloadSupport.dispose(d);
+ }
+
/**
* This method should be used whenever GWT code is entered from a JS context
* and there is no GWT code in the same module on the call stack. Examples
@@ -59,7 +82,7 @@ public final class Impl {
* The function passed to this method will be invoked via
* Function.apply()
with the current this
value and
* the invocation arguments passed to $entry
.
- *
+ *
* @param jsFunction a JS function to invoke, which is typically a JSNI
* reference to a static Java method
* @return the value returned when jsFunction
is invoked, or
@@ -80,6 +103,10 @@ public static native JavaScriptObject entry(JavaScriptObject jsFunction) /*-{
};
}-*/;
+ public static void exportUnloadModule() {
+ unloadSupport.exportUnloadModule();
+ }
+
/**
* Gets an identity-based hash code on the passed-in Object by adding an
* expando. This method should not be used with null
or any
@@ -135,7 +162,7 @@ public static native String getModuleName() /*-{
* Returns the obfuscated name of members in the compiled output. This is a
* thin wrapper around JNameOf AST nodes and is therefore meaningless to
* implement in Development Mode.
- *
+ *
* @param jsniIdent a string literal specifying a type, field, or method. Raw
* type names may also be used to obtain the name of the type's seed
* function.
@@ -158,6 +185,57 @@ public static native String getPermutationStrongName() /*-{
return $strongName;
}-*/;
+ /**
+ * UncaughtExceptionHandler that is used by unit tests to spy on uncaught
+ * exceptions.
+ */
+ private static UncaughtExceptionHandler uncaughtExceptionHandlerForTest;
+
+ /**
+ * Set an uncaught exception handler to spy on uncaught exceptions in unit
+ * tests.
+ *
+ * Setting this method will not interfere with any exception handling logic;
+ * i.e. {@link GWT#getUncaughtExceptionHandler()} will still return null if a
+ * handler is not set via {@link GWT#setUncaughtExceptionHandler}.
+ */
+ public static void setUncaughtExceptionHandlerForTest(
+ UncaughtExceptionHandler handler) {
+ uncaughtExceptionHandlerForTest = handler;
+ }
+
+ public static void reportUncaughtException(Throwable e) {
+ if (Impl.uncaughtExceptionHandlerForTest != null) {
+ Impl.uncaughtExceptionHandlerForTest.onUncaughtException(e);
+ }
+
+ UncaughtExceptionHandler handler = GWT.getUncaughtExceptionHandler();
+ if (handler != null) {
+ if (handler == Impl.uncaughtExceptionHandlerForTest) {
+ return; // Already reported so we're done.
+ }
+ // TODO(goktug): Handler might throw an exception but catching and reporting it to browser
+ // here breaks assumptions of some existing hybrid apps that uses UCE for exception
+ // conversion. We don't have an alternative functionality (yet) and it is too risky to include
+ // the change in the release at last minute.
+ handler.onUncaughtException(e);
+ return; // Done.
+ }
+
+ // Make sure that the exception is not swallowed and let the browser handle it
+ reportToBrowser(e);
+ }
+
+ private static void reportToBrowser(Throwable e) {
+ reportToBrowser(e instanceof JavaScriptException ? ((JavaScriptException) e).getThrown() : e);
+ }
+
+ private static native void reportToBrowser(Object e) /*-{
+ $wnd.setTimeout(function () {
+ throw e;
+ }, 0);
+ }-*/;
+
/**
* Indicates if $entry
has been called.
*/
@@ -165,6 +243,10 @@ public static boolean isEntryOnStack() {
return entryDepth > 0;
}
+ public static boolean isModuleUnloaded() {
+ return moduleUnloaded;
+ }
+
/**
* Indicates if $entry
is present on the stack more than once.
*/
@@ -185,12 +267,31 @@ public static native JavaScriptObject registerEntry() /*-{
}
}-*/;
+ public static void scheduleDispose(Disposable d) {
+ unloadSupport.scheduleDispose(d);
+ }
+
+ public static int setInterval(JavaScriptObject func, int time) {
+ return unloadSupport.setInterval(func, time);
+ }
+
+ public static int setTimeout(JavaScriptObject func, int time) {
+ return unloadSupport.setTimeout(func, time);
+ }
+
+ public static void unloadModule() {
+ if (unloadSupport.isUnloadSupported()) {
+ moduleUnloaded = true;
+ unloadSupport.disposeAll();
+ }
+ }
+
private static native Object apply(Object jsFunction, Object thisObj,
- Object arguments) /*-{
+ Object args) /*-{
if (@com.google.gwt.core.client.GWT::isScript()()) {
- return jsFunction.apply(thisObj, arguments);
+ return jsFunction.apply(thisObj, args);
} else {
- var _ = jsFunction.apply(thisObj, arguments);
+ var _ = jsFunction.apply(thisObj, args);
if (_ != null) {
// Wrap for Development Mode
_ = Object(_);
@@ -215,8 +316,7 @@ private static boolean enter() {
// We want to disable some actions in the reentrant case
if (entryDepth++ == 0) {
- //SP EDIT
- // SchedulerImpl.INSTANCE.flushEntryCommands();
+ //SchedulerImpl.INSTANCE.flushEntryCommands();
return true;
}
return false;
@@ -226,7 +326,11 @@ private static boolean enter() {
* Implements {@link #entry(JavaScriptObject)}.
*/
private static Object entry0(Object jsFunction, Object thisObj,
- Object arguments) throws Throwable {
+ Object args) throws Throwable {
+ // if module is unloaded, don't run anything
+ if (unloadSupport.isUnloadSupported() && Impl.isModuleUnloaded()) {
+ return null;
+ }
boolean initialEntry = enter();
try {
@@ -242,14 +346,14 @@ private static Object entry0(Object jsFunction, Object thisObj,
* doing something useful with it.
*/
try {
- return apply(jsFunction, thisObj, arguments);
+ return apply(jsFunction, thisObj, args);
} catch (Throwable t) {
- GWT.getUncaughtExceptionHandler().onUncaughtException(t);
+ reportUncaughtException(t);
return undefined();
}
} else {
// Can't handle any exceptions, let them percolate normally
- return apply(jsFunction, thisObj, arguments);
+ return apply(jsFunction, thisObj, args);
}
/*
@@ -266,8 +370,7 @@ private static Object entry0(Object jsFunction, Object thisObj,
*/
private static void exit(boolean initialEntry) {
if (initialEntry) {
- // SP EDIT
- //SchedulerImpl.INSTANCE.flushFinallyCommands();
+ // SchedulerImpl.INSTANCE.flushFinallyCommands();
}
// Decrement after we call flush
@@ -298,7 +401,7 @@ private static native Object undefined() /*-{
}-*/;
private static native void watchdogEntryDepthCancel(int timerId) /*-{
- $wnd.clearTimeout(timerId);
+ @com.google.gwt.core.client.impl.Impl::clearTimeout(I)(timerId);
}-*/;
private static void watchdogEntryDepthRun() {
@@ -311,7 +414,7 @@ private static void watchdogEntryDepthRun() {
}
private static native int watchdogEntryDepthSchedule() /*-{
- return $wnd.setTimeout(function() {
+ return @com.google.gwt.core.client.impl.Impl::setTimeout(Lcom/google/gwt/core/client/JavaScriptObject;I)(function() {
@com.google.gwt.core.client.impl.Impl::watchdogEntryDepthRun()();
}, 10);
}-*/;
diff --git a/SPWebTest/.classpath b/SPWebTest/.classpath
index f99bd78..3a2641d 100644
--- a/SPWebTest/.classpath
+++ b/SPWebTest/.classpath
@@ -3,10 +3,10 @@