summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--WebContent/VAADIN/themes/valo/shared/_global.scss2
-rw-r--r--WebContent/VAADIN/themes/valo/shared/_reconnect-dialog.scss18
-rw-r--r--client/src/com/vaadin/client/ApplicationConnection.java4
-rw-r--r--client/src/com/vaadin/client/communication/DefaultCommunicationProblemHandler.java4
-rw-r--r--client/src/com/vaadin/client/communication/ReconnectDialog.java49
-rw-r--r--client/src/com/vaadin/client/communication/ReconnectDialog.ui.xml12
-rw-r--r--client/src/com/vaadin/client/communication/ReconnectingCommunicationProblemHandler.java181
-rw-r--r--uitest/src/com/vaadin/tests/requesthandlers/CommunicationError.java15
8 files changed, 282 insertions, 3 deletions
diff --git a/WebContent/VAADIN/themes/valo/shared/_global.scss b/WebContent/VAADIN/themes/valo/shared/_global.scss
index b4e8564119..39b5a4e7d9 100644
--- a/WebContent/VAADIN/themes/valo/shared/_global.scss
+++ b/WebContent/VAADIN/themes/valo/shared/_global.scss
@@ -2,6 +2,7 @@
@import "contextmenu";
@import "overlay";
@import "tooltip";
+@import "reconnect-dialog";
/*
@@ -374,6 +375,7 @@ $valo-shared-pathPrefix: null;
@include valo-contextmenu;
+ @include valo-reconnect-dialog;
}
diff --git a/WebContent/VAADIN/themes/valo/shared/_reconnect-dialog.scss b/WebContent/VAADIN/themes/valo/shared/_reconnect-dialog.scss
new file mode 100644
index 0000000000..94f5f8b0bd
--- /dev/null
+++ b/WebContent/VAADIN/themes/valo/shared/_reconnect-dialog.scss
@@ -0,0 +1,18 @@
+@mixin valo-reconnect-dialog {
+ .v-reconnect-dialog {
+ color: white;
+ @include valo-notification-bar-style;
+ @include valo-notification-system-style;
+ text-align: center;
+ .spinner {
+ @include valo-spinner;
+ display: inline-block;
+ margin-top: 10px;
+ visibility: hidden;
+ }
+
+ &.active .spinner {
+ visibility: visible;
+ }
+ }
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java
index b3bcbbb3ab..65afa9b08b 100644
--- a/client/src/com/vaadin/client/ApplicationConnection.java
+++ b/client/src/com/vaadin/client/ApplicationConnection.java
@@ -46,8 +46,8 @@ import com.vaadin.client.ApplicationConnection.ApplicationStoppedEvent;
import com.vaadin.client.ResourceLoader.ResourceLoadEvent;
import com.vaadin.client.ResourceLoader.ResourceLoadListener;
import com.vaadin.client.communication.CommunicationProblemHandler;
-import com.vaadin.client.communication.DefaultCommunicationProblemHandler;
import com.vaadin.client.communication.Heartbeat;
+import com.vaadin.client.communication.ReconnectingCommunicationProblemHandler;
import com.vaadin.client.communication.RpcManager;
import com.vaadin.client.communication.ServerCommunicationHandler;
import com.vaadin.client.communication.ServerMessageHandler;
@@ -366,7 +366,7 @@ public class ApplicationConnection implements HasHandlers {
serverRpcQueue = GWT.create(ServerRpcQueue.class);
serverRpcQueue.setConnection(this);
communicationProblemHandler = GWT
- .create(DefaultCommunicationProblemHandler.class);
+ .create(ReconnectingCommunicationProblemHandler.class);
communicationProblemHandler.setConnection(this);
serverMessageHandler = GWT.create(ServerMessageHandler.class);
serverMessageHandler.setConnection(this);
diff --git a/client/src/com/vaadin/client/communication/DefaultCommunicationProblemHandler.java b/client/src/com/vaadin/client/communication/DefaultCommunicationProblemHandler.java
index 8b97b0a4c7..196e1d56ea 100644
--- a/client/src/com/vaadin/client/communication/DefaultCommunicationProblemHandler.java
+++ b/client/src/com/vaadin/client/communication/DefaultCommunicationProblemHandler.java
@@ -44,6 +44,10 @@ public class DefaultCommunicationProblemHandler implements
this.connection = connection;
}
+ protected ApplicationConnection getConnection() {
+ return connection;
+ }
+
public static Logger getLogger() {
return Logger.getLogger(DefaultCommunicationProblemHandler.class
.getName());
diff --git a/client/src/com/vaadin/client/communication/ReconnectDialog.java b/client/src/com/vaadin/client/communication/ReconnectDialog.java
new file mode 100644
index 0000000000..b69f51c165
--- /dev/null
+++ b/client/src/com/vaadin/client/communication/ReconnectDialog.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2000-2014 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.communication;
+
+import com.google.gwt.core.shared.GWT;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.user.client.ui.HTMLPanel;
+import com.google.gwt.user.client.ui.Label;
+import com.vaadin.client.ui.VOverlay;
+
+/**
+ *
+ *
+ * @since 7.6
+ * @author Vaadin Ltd
+ */
+public class ReconnectDialog extends VOverlay {
+ interface MyUiBinder extends UiBinder<HTMLPanel, ReconnectDialog> {
+ }
+
+ private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);
+
+ @UiField
+ public Label label;
+
+ public ReconnectDialog() {
+ super(false, true);
+ addStyleName("v-reconnect-dialog");
+ setWidget(uiBinder.createAndBindUi(this));
+ }
+
+ public void setText(String text) {
+ label.setText(text);
+ }
+}
diff --git a/client/src/com/vaadin/client/communication/ReconnectDialog.ui.xml b/client/src/com/vaadin/client/communication/ReconnectDialog.ui.xml
new file mode 100644
index 0000000000..885588f8a5
--- /dev/null
+++ b/client/src/com/vaadin/client/communication/ReconnectDialog.ui.xml
@@ -0,0 +1,12 @@
+<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
+ xmlns:g='urn:import:com.google.gwt.user.client.ui'>
+
+ <g:HTMLPanel>
+
+ <g:Label ui:field="label" styleName="text"
+ text="Server connection lost, trying to reconnect..." />
+ <div class="spinner" />
+ </g:HTMLPanel>
+
+</ui:UiBinder>
+
diff --git a/client/src/com/vaadin/client/communication/ReconnectingCommunicationProblemHandler.java b/client/src/com/vaadin/client/communication/ReconnectingCommunicationProblemHandler.java
new file mode 100644
index 0000000000..bcdf12f2a3
--- /dev/null
+++ b/client/src/com/vaadin/client/communication/ReconnectingCommunicationProblemHandler.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2000-2014 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.communication;
+
+import com.google.gwt.core.shared.GWT;
+import com.google.gwt.http.client.Request;
+import com.google.gwt.http.client.Response;
+import com.google.gwt.user.client.Timer;
+import com.google.gwt.user.client.ui.PopupPanel.PositionCallback;
+
+import elemental.json.JsonObject;
+
+//FIXME This is just a test and should be merged with DCPH
+public class ReconnectingCommunicationProblemHandler extends
+ DefaultCommunicationProblemHandler {
+
+ private enum Type {
+ HEARTBEAT, XHR;
+ }
+
+ ReconnectDialog reconnectDialog = GWT.create(ReconnectDialog.class);
+ int reconnectAttempt = 0;
+ private Type reconnectionCause = null;;
+
+ @Override
+ public void xhrException(CommunicationProblemEvent event) {
+ handleTemporaryError(Type.XHR, event.getPayload());
+ }
+
+ @Override
+ public boolean heartbeatException(Request request, Throwable exception) {
+ handleTemporaryError(Type.HEARTBEAT, null);
+ return true;
+ }
+
+ @Override
+ public boolean heartbeatInvalidStatusCode(Request request, Response response) {
+ if (response.getStatusCode() == Response.SC_GONE) {
+ // Session expired
+ resolveTemporaryError(Type.HEARTBEAT, false);
+ return super.heartbeatInvalidStatusCode(request, response);
+ }
+
+ handleTemporaryError(Type.HEARTBEAT, null);
+ return true;
+ }
+
+ @Override
+ public void heartbeatOk() {
+ resolveTemporaryError(Type.HEARTBEAT, true);
+ }
+
+ private void handleTemporaryError(Type type, final JsonObject payload) {
+ reconnectAttempt++;
+ reconnectionCause = type;
+ if (!reconnectDialog.isAttached()) {
+ // FIXME
+ reconnectDialog.setStyleName("active", true);
+ reconnectDialog.setOwner(getConnection().getUIConnector()
+ .getWidget());
+ reconnectDialog.setPopupPositionAndShow(new PositionCallback() {
+ @Override
+ public void setPosition(int offsetWidth, int offsetHeight) {
+ // FIXME
+ reconnectDialog.setPopupPosition(0, 0);
+ }
+ });
+ }
+ if (payload != null) {
+ getConnection().getServerCommunicationHandler().endRequest();
+ }
+
+ if (reconnectAttempt >= getMaxReconnectAttempts()) {
+ // FIXME Remove
+ reconnectDialog.setText("Server connection lost. Gave up after "
+ + reconnectAttempt + " attempts.");
+ // FIXME
+ reconnectDialog.setStyleName("active", false);
+
+ getConnection().setApplicationRunning(false);
+
+ } else {
+ reconnectDialog
+ .setText("Server connection lost, trying to reconnect... Attempt "
+ + reconnectAttempt);
+
+ // Here and not in timer to avoid TB for getting in between
+ if (payload != null) {
+ // FIXME: Not like this
+ getConnection().getServerCommunicationHandler().startRequest();
+ }
+
+ // Reconnect
+ new Timer() {
+ @Override
+ public void run() {
+ if (payload != null) {
+ getLogger().info(
+ "Re-sending last message to the server...");
+ getConnection().getServerCommunicationHandler().send(
+ payload);
+ } else {
+ // Use heartbeat
+ getLogger().info(
+ "Trying to re-establish server connection...");
+ getConnection().getHeartbeat().send();
+ }
+ }
+ }.schedule(getReconnectInterval());
+ }
+ }
+
+ /**
+ * @since
+ * @return
+ */
+ private int getMaxReconnectAttempts() {
+ // FIXME Parameter
+ return 15;
+ }
+
+ /**
+ * @since
+ * @return
+ */
+ private int getReconnectInterval() {
+ // FIXME Parameter
+ return 5000;
+ }
+
+ @Override
+ public void xhrInvalidContent(CommunicationProblemEvent event) {
+ super.xhrInvalidContent(event);
+ };
+
+ @Override
+ public void xhrInvalidStatusCode(CommunicationProblemEvent event) {
+ handleTemporaryError(Type.XHR, event.getPayload());
+ }
+
+ @Override
+ public void xhrOk() {
+ resolveTemporaryError(Type.XHR, true);
+ }
+
+ private void resolveTemporaryError(Type cause, boolean success) {
+ if (reconnectionCause == null) {
+ // Not trying to reconnect
+ return;
+ }
+ if (reconnectionCause != cause) {
+ // If a heartbeat goes through while we are trying to re-send an
+ // XHR, we wait for the XHR to go through
+ return;
+ }
+
+ reconnectionCause = null;
+ if (reconnectDialog.isAttached()) {
+ reconnectDialog.hide();
+ }
+
+ if (success && reconnectAttempt != 0) {
+ getLogger().info("Re-established connection to server");
+ reconnectAttempt = 0;
+ }
+
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/requesthandlers/CommunicationError.java b/uitest/src/com/vaadin/tests/requesthandlers/CommunicationError.java
index 31ec7658ee..26f3dff1a2 100644
--- a/uitest/src/com/vaadin/tests/requesthandlers/CommunicationError.java
+++ b/uitest/src/com/vaadin/tests/requesthandlers/CommunicationError.java
@@ -15,6 +15,9 @@
*/
package com.vaadin.tests.requesthandlers;
+import java.io.IOException;
+import java.io.PrintWriter;
+
import com.vaadin.launcher.ApplicationRunnerServlet;
import com.vaadin.server.CustomizedSystemMessages;
import com.vaadin.server.SystemMessages;
@@ -69,7 +72,17 @@ public class CommunicationError extends UIProvider {
@Override
public void buttonClick(ClickEvent event) {
- VaadinService.getCurrentResponse().setStatus(400);
+ try {
+ // An unparseable response will cause
+ // communication error
+ PrintWriter writer = VaadinService
+ .getCurrentResponse().getWriter();
+ writer.write("for(;;)[{FOOBAR}]");
+ writer.flush();
+ writer.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
}
});
addComponent(button);