From c60ca65f8f941fe3d80317747f5dc4f41c0e70d6 Mon Sep 17 00:00:00 2001
From: Marc Englund
Date: Fri, 23 Jan 2009 09:48:33 +0000
Subject: Added a communication error system-message that is written to the
client when the initial page is rendered. If any UIDL request fails, the
message is shown. Fixes [2485]
svn changeset:6624/svn branch:trunk
---
src/com/itmill/toolkit/Application.java | 59 +++++++++++++++++-----
.../gwt/client/ApplicationConfiguration.java | 20 ++++++++
.../terminal/gwt/client/ApplicationConnection.java | 44 +++++++++++++---
.../terminal/gwt/server/ApplicationServlet.java | 53 +++++++++++++++++--
4 files changed, 155 insertions(+), 21 deletions(-)
(limited to 'src/com')
diff --git a/src/com/itmill/toolkit/Application.java b/src/com/itmill/toolkit/Application.java
index fa4f5e9a9d..866a9ced51 100644
--- a/src/com/itmill/toolkit/Application.java
+++ b/src/com/itmill/toolkit/Application.java
@@ -1195,6 +1195,11 @@ public abstract class Application implements URIHandler, Terminal.ErrorListener
protected String sessionExpiredCaption = "Session Expired";
protected String sessionExpiredMessage = "Take note of any unsaved data, and click here to continue.";
+ protected String communicationErrorURL = null;
+ protected boolean communicationErrorNotificationEnabled = true;
+ protected String communicationErrorCaption = "Communication problem";
+ protected String communicationErrorMessage = "Take note of any unsaved data, and click here to continue.";
+
protected String internalErrorURL = null;
protected boolean internalErrorNotificationEnabled = true;
protected String internalErrorCaption = "Internal Error";
@@ -1242,6 +1247,36 @@ public abstract class Application implements URIHandler, Terminal.ErrorListener
: null);
}
+ /**
+ * @return the URL to load on null for restart
+ */
+ public String getCommunicationErrorURL() {
+ return communicationErrorURL;
+ }
+
+ /**
+ * @return true = notification enabled, false = notification disabled
+ */
+ public boolean isCommunicationErrorNotificationEnabled() {
+ return communicationErrorNotificationEnabled;
+ }
+
+ /**
+ * @return the notification caption, or null for no caption
+ */
+ public String getCommunicationErrorCaption() {
+ return (communicationErrorNotificationEnabled ? communicationErrorCaption
+ : null);
+ }
+
+ /**
+ * @return the notification message, or null for no message
+ */
+ public String getCommunicationErrorMessage() {
+ return (communicationErrorNotificationEnabled ? communicationErrorMessage
+ : null);
+ }
+
/**
* @return the URL to load on null for restart
*/
@@ -1313,26 +1348,26 @@ public abstract class Application implements URIHandler, Terminal.ErrorListener
*
*
* The default behavior is to show a notification, and restart the
- * application the the user clicks the message.
- * Instead of restarting the application, you can set a specific URL that
- * the user is taken to.
- * Setting both caption and message to null will restart the application (or
- * go to the specified URL) without displaying a notification.
- * set*NotificationEnabled(false) will achieve the same thing.
+ * application the the user clicks the message.
Instead of restarting
+ * the application, you can set a specific URL that the user is taken
+ * to.
Setting both caption and message to null will restart the
+ * application (or go to the specified URL) without displaying a
+ * notification. set*NotificationEnabled(false) will achieve the same thing.
*
*
* The situations are:
*
Session expired: the user session has expired, usually due to
* inactivity.
+ * Communication error: the client failed to contact the server, or the
+ * server returned and invalid response.
* Internal error: unhandled critical server error (e.g out of memory,
* database crash)
* Out of sync: the client is not in sync with the server. E.g the user
- * opens two windows showing the same application, and makes changes in one
- * of the windows - the other window is no longer in sync, and (for
- * instance) pressing a button that is no longer present in the UI will
- * cause a out-of-sync -situation. You might want to disable the
- * notification if silently ignoring a action (e.g button press) is not a
- * problem in your application.
+ * opens two windows showing the same application, but the application does
+ * not support this and uses the same Window instance. When the user makes
+ * changes in one of the windows - the other window is no longer in sync,
+ * and (for instance) pressing a button that is no longer present in the UI
+ * will cause a out-of-sync -situation.
*
*/
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ApplicationConfiguration.java b/src/com/itmill/toolkit/terminal/gwt/client/ApplicationConfiguration.java
index 3fe4015b9d..919ab0807c 100644
--- a/src/com/itmill/toolkit/terminal/gwt/client/ApplicationConfiguration.java
+++ b/src/com/itmill/toolkit/terminal/gwt/client/ApplicationConfiguration.java
@@ -14,6 +14,9 @@ public class ApplicationConfiguration {
private String appUri;
private JavaScriptObject versionInfo;
private String windowName;
+ private String communicationErrorCaption;
+ private String communicationErrorMessage;
+ private String communicationErrorUrl;
private static ArrayList unstartedApplications = new ArrayList();
private static ArrayList runningApplications = new ArrayList();
@@ -50,6 +53,18 @@ public class ApplicationConfiguration {
return versionInfo;
}
+ public String getCommunicationErrorCaption() {
+ return communicationErrorCaption;
+ }
+
+ public String getCommunicationErrorMessage() {
+ return communicationErrorMessage;
+ }
+
+ public String getCommunicationErrorUrl() {
+ return communicationErrorUrl;
+ }
+
private native void loadFromDOM()
/*-{
@@ -69,6 +84,11 @@ public class ApplicationConfiguration {
if(jsobj.versionInfo) {
this.@com.itmill.toolkit.terminal.gwt.client.ApplicationConfiguration::versionInfo = jsobj.versionInfo;
}
+ if(jsobj.comErrMsg) {
+ this.@com.itmill.toolkit.terminal.gwt.client.ApplicationConfiguration::communicationErrorCaption = jsobj.comErrMsg.caption;
+ this.@com.itmill.toolkit.terminal.gwt.client.ApplicationConfiguration::communicationErrorMessage = jsobj.comErrMsg.message;
+ this.@com.itmill.toolkit.terminal.gwt.client.ApplicationConfiguration::communicationErrorUrl = jsobj.comErrMsg.url;
+ }
} else {
$wnd.alert("Toolkit app failed to initialize: " + this.id);
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ApplicationConnection.java b/src/com/itmill/toolkit/terminal/gwt/client/ApplicationConnection.java
index e9f4f1597b..d8dd3a5895 100755
--- a/src/com/itmill/toolkit/terminal/gwt/client/ApplicationConnection.java
+++ b/src/com/itmill/toolkit/terminal/gwt/client/ApplicationConnection.java
@@ -328,12 +328,13 @@ public class ApplicationConnection {
if (!forceSync) {
final RequestBuilder rb = new RequestBuilder(RequestBuilder.POST,
uri);
+ // TODO enable timeout
+ // rb.setTimeoutMillis(timeoutMillis);
rb.setHeader("Content-Type", "text/plain;charset=utf-8");
try {
rb.sendRequest(requestData, new RequestCallback() {
public void onError(Request request, Throwable exception) {
- // TODO Better reporting to user
- console.error("Got error");
+ showCommunicationError(exception.getMessage());
endRequest();
if (!applicationRunning) {
// start failed, let's try to start the next app
@@ -343,6 +344,16 @@ public class ApplicationConnection {
public void onResponseReceived(Request request,
Response response) {
+ console.log("Server visit took "
+ + String.valueOf((new Date()).getTime()
+ - requestStartTime.getTime()) + "ms");
+
+ switch (response.getStatusCode()) {
+ case 0:
+ showCommunicationError("Invalid status code 0 (server down?)");
+ return;
+ // TODO could add more cases
+ }
if ("init".equals(uidl_security_key)) {
// Read security key
String key = response
@@ -351,9 +362,6 @@ public class ApplicationConnection {
uidl_security_key = key;
}
}
- console.log("Server visit took "
- + String.valueOf((new Date()).getTime()
- - requestStartTime.getTime()) + "ms");
if (applicationRunning) {
handleReceivedJSONMessage(response);
} else {
@@ -405,6 +413,30 @@ public class ApplicationConnection {
}
}
+ /**
+ * Shows the communication error notification. The 'details' only go to the
+ * console for now.
+ *
+ * @param details
+ * Optional details for debugging.
+ */
+ private void showCommunicationError(String details) {
+ console.error("Communication error: " + details);
+ String html = "";
+ if (configuration.getCommunicationErrorCaption() != null) {
+ html += "" + configuration.getCommunicationErrorCaption()
+ + "
";
+ }
+ if (configuration.getCommunicationErrorMessage() != null) {
+ html += "" + configuration.getCommunicationErrorMessage()
+ + "
";
+ }
+ INotification n = new INotification(1000 * 60 * 45);
+ n.addEventListener(new NotificationRedirect(configuration
+ .getCommunicationErrorUrl()));
+ n.show(html, INotification.CENTERED_TOP, INotification.STYLE_SYSTEM);
+ }
+
private native void syncSendForce(JavaScriptObject xmlHttpRequest,
String uri, String requestData)
/*-{
@@ -551,7 +583,7 @@ public class ApplicationConnection {
json = JSONParser.parse(jsonText);
} catch (final com.google.gwt.json.client.JSONException e) {
endRequest();
- console.log(e.getMessage() + " - Original JSON-text:");
+ showCommunicationError(e.getMessage() + " - Original JSON-text:");
console.log(jsonText);
return;
}
diff --git a/src/com/itmill/toolkit/terminal/gwt/server/ApplicationServlet.java b/src/com/itmill/toolkit/terminal/gwt/server/ApplicationServlet.java
index d442b1ed17..471ef2877e 100644
--- a/src/com/itmill/toolkit/terminal/gwt/server/ApplicationServlet.java
+++ b/src/com/itmill/toolkit/terminal/gwt/server/ApplicationServlet.java
@@ -784,7 +784,8 @@ public class ApplicationServlet extends HttpServlet {
*/
private void writeAjaxPage(HttpServletRequest request,
HttpServletResponse response, Window window, String themeName,
- Application application) throws IOException, MalformedURLException {
+ Application application) throws IOException, MalformedURLException,
+ ServletException {
// e.g portlets only want a html fragment
boolean fragment = (request.getAttribute(REQUEST_FRAGMENT) != null);
@@ -885,6 +886,15 @@ public class ApplicationServlet extends HttpServlet {
// but indicates that it should not be used in CSS and such:
appId = appId + appId.hashCode();
+ // Get system messages
+ Application.SystemMessages systemMessages = null;
+ try {
+ systemMessages = getSystemMessages();
+ } catch (SystemMessageException e) {
+ // failing to get the system messages is always a problem
+ throw new ServletException("CommunicationError!", e);
+ }
+
if (isGecko17(request)) {
// special start page for gecko 1.7 versions. Firefox 1.0 is not
// supported, but the hack is make it possible to use linux and
@@ -923,7 +933,25 @@ public class ApplicationServlet extends HttpServlet {
page.write(VERSION);
page.write("\",applicationVersion:\"");
page.write(application.getVersion());
- page.write("\"}");
+ page.write("\"},");
+ if (systemMessages != null) {
+ // Write the CommunicationError -message to client
+ String caption = systemMessages.getCommunicationErrorCaption();
+ if (caption != null) {
+ caption = "\"" + caption + "\"";
+ }
+ String message = systemMessages.getCommunicationErrorMessage();
+ if (message != null) {
+ message = "\"" + message + "\"";
+ }
+ String url = systemMessages.getCommunicationErrorURL();
+ if (url != null) {
+ url = "\"" + url + "\"";
+ }
+ page.write("\"comErrMsg\": {" + "\"caption\":" + caption + ","
+ + "\"message\" : " + message + "," + "\"url\" : " + url
+ + "}");
+ }
page.write("};\n//]]>\n\n");
if (themeName != null) {
@@ -978,7 +1006,26 @@ public class ApplicationServlet extends HttpServlet {
page.write(VERSION);
page.write("\",applicationVersion:\"");
page.write(application.getVersion());
- page.write("\"}");
+ page.write("\"},");
+ if (systemMessages != null) {
+ // Write the CommunicationError -message to client
+ String caption = systemMessages.getCommunicationErrorCaption();
+ if (caption != null) {
+ caption = "\"" + caption + "\"";
+ }
+ String message = systemMessages.getCommunicationErrorMessage();
+ if (message != null) {
+ message = "\"" + message + "\"";
+ }
+ String url = systemMessages.getCommunicationErrorURL();
+ if (url != null) {
+ url = "\"" + url + "\"";
+ }
+
+ page.write("\"comErrMsg\": {" + "\"caption\":" + caption + ","
+ + "\"message\" : " + message + "," + "\"url\" : " + url
+ + "}");
+ }
page.write("};\n//]]>\n\n");
if (themeName != null) {
--
cgit v1.2.3