summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xclient/src/com/vaadin/DefaultWidgetSet.gwt.xml4
-rw-r--r--client/src/com/vaadin/client/communication/DefaultReconnectDialog.java85
-rw-r--r--client/src/com/vaadin/client/communication/DefaultReconnectDialog.ui.xml (renamed from client/src/com/vaadin/client/communication/ReconnectDialog.ui.xml)0
-rw-r--r--client/src/com/vaadin/client/communication/ReconnectDialog.java58
-rw-r--r--client/src/com/vaadin/client/communication/ReconnectingCommunicationProblemHandler.java381
-rw-r--r--client/src/com/vaadin/client/communication/ServerCommunicationHandler.java3
-rw-r--r--shared/src/com/vaadin/shared/ui/ui/UIState.java1
-rw-r--r--uitest/src/com/vaadin/tests/application/CommErrorEmulatorUI.java16
8 files changed, 438 insertions, 110 deletions
diff --git a/client/src/com/vaadin/DefaultWidgetSet.gwt.xml b/client/src/com/vaadin/DefaultWidgetSet.gwt.xml
index 01cbdc3222..03d0950126 100755
--- a/client/src/com/vaadin/DefaultWidgetSet.gwt.xml
+++ b/client/src/com/vaadin/DefaultWidgetSet.gwt.xml
@@ -26,6 +26,10 @@
class="com.vaadin.client.metadata.ConnectorBundleLoader" />
</generate-with>
+ <replace-with
+ class="com.vaadin.client.communication.DefaultReconnectDialog">
+ <when-type-is class="com.vaadin.client.communication.ReconnectDialog" />
+ </replace-with>
<!-- Since 7.2. Compile all permutations (browser support) into one Javascript
file. Speeds up compilation and does not make the Javascript significantly
diff --git a/client/src/com/vaadin/client/communication/DefaultReconnectDialog.java b/client/src/com/vaadin/client/communication/DefaultReconnectDialog.java
new file mode 100644
index 0000000000..60ecce8ae0
--- /dev/null
+++ b/client/src/com/vaadin/client/communication/DefaultReconnectDialog.java
@@ -0,0 +1,85 @@
+/*
+ * 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.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+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.ApplicationConnection;
+import com.vaadin.client.WidgetUtil;
+import com.vaadin.client.ui.VOverlay;
+
+/**
+ * The default implementation of the reconnect dialog
+ *
+ * @since 7.6
+ * @author Vaadin Ltd
+ */
+public class DefaultReconnectDialog extends VOverlay implements ReconnectDialog {
+ interface MyUiBinder extends UiBinder<HTMLPanel, DefaultReconnectDialog> {
+ }
+
+ private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);
+
+ private static final String STYLE_RECONNECTING = "active";
+
+ @UiField
+ public Label label;
+
+ private HandlerRegistration clickHandler = null;
+
+ public DefaultReconnectDialog() {
+ super(false, true);
+ addStyleName("v-reconnect-dialog");
+ setWidget(uiBinder.createAndBindUi(this));
+ }
+
+ @Override
+ public void setText(String text) {
+ label.setText(text);
+ }
+
+ @Override
+ public void setReconnecting(boolean reconnecting) {
+ setStyleName(STYLE_RECONNECTING, reconnecting);
+
+ // Click to refresh after giving up
+ if (!reconnecting) {
+ clickHandler = addDomHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ // refresh
+ WidgetUtil.redirect(null);
+ }
+ }, ClickEvent.getType());
+ } else {
+ if (clickHandler != null) {
+ clickHandler.removeHandler();
+ }
+ }
+ }
+
+ @Override
+ public void show(ApplicationConnection connection) {
+ setOwner(connection.getUIConnector().getWidget());
+ show();
+ }
+}
diff --git a/client/src/com/vaadin/client/communication/ReconnectDialog.ui.xml b/client/src/com/vaadin/client/communication/DefaultReconnectDialog.ui.xml
index 885588f8a5..885588f8a5 100644
--- a/client/src/com/vaadin/client/communication/ReconnectDialog.ui.xml
+++ b/client/src/com/vaadin/client/communication/DefaultReconnectDialog.ui.xml
diff --git a/client/src/com/vaadin/client/communication/ReconnectDialog.java b/client/src/com/vaadin/client/communication/ReconnectDialog.java
index b69f51c165..21f47ecbf6 100644
--- a/client/src/com/vaadin/client/communication/ReconnectDialog.java
+++ b/client/src/com/vaadin/client/communication/ReconnectDialog.java
@@ -15,35 +15,51 @@
*/
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;
+import com.vaadin.client.ApplicationConnection;
/**
- *
+ * Interface which must be implemented by the reconnect dialog
*
* @since 7.6
* @author Vaadin Ltd
*/
-public class ReconnectDialog extends VOverlay {
- interface MyUiBinder extends UiBinder<HTMLPanel, ReconnectDialog> {
- }
+public interface ReconnectDialog {
+
+ /**
+ * Sets the main text shown in the dialog
+ *
+ * @param text
+ * the text to show
+ */
+ void setText(String text);
- private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);
+ /**
+ * Sets the reconnecting state, which is true if we are trying to
+ * re-establish a connection with the server.
+ *
+ * @param reconnecting
+ * true if we are trying to re-establish the server connection,
+ * false if we have given up
+ */
+ void setReconnecting(boolean reconnecting);
- @UiField
- public Label label;
+ /**
+ * Checks if the reconnect dialog is visible to the user
+ *
+ * @return true if the user can see the dialog, false otherwise
+ */
+ boolean isVisible();
- public ReconnectDialog() {
- super(false, true);
- addStyleName("v-reconnect-dialog");
- setWidget(uiBinder.createAndBindUi(this));
- }
+ /**
+ * Shows the dialog to the user
+ *
+ * @param connection
+ * the application connection this is related to
+ */
+ void show(ApplicationConnection connection);
- public void setText(String text) {
- label.setText(text);
- }
+ /**
+ * Hides the dialog from the user
+ */
+ void hide();
}
diff --git a/client/src/com/vaadin/client/communication/ReconnectingCommunicationProblemHandler.java b/client/src/com/vaadin/client/communication/ReconnectingCommunicationProblemHandler.java
index 7f09c502d8..33f7395536 100644
--- a/client/src/com/vaadin/client/communication/ReconnectingCommunicationProblemHandler.java
+++ b/client/src/com/vaadin/client/communication/ReconnectingCommunicationProblemHandler.java
@@ -24,6 +24,8 @@ import com.google.gwt.regexp.shared.MatchResult;
import com.google.gwt.regexp.shared.RegExp;
import com.google.gwt.user.client.Timer;
import com.vaadin.client.ApplicationConnection;
+import com.vaadin.client.ApplicationConnection.ApplicationStoppedEvent;
+import com.vaadin.client.ApplicationConnection.ApplicationStoppedHandler;
import com.vaadin.client.WidgetUtil;
import com.vaadin.shared.ui.ui.UIState.ReconnectDialogConfigurationState;
@@ -45,21 +47,78 @@ import elemental.json.JsonObject;
public class ReconnectingCommunicationProblemHandler implements
CommunicationProblemHandler {
- private static final String STYLE_RECONNECTING = "active";
private ApplicationConnection connection;
private ReconnectDialog reconnectDialog = GWT.create(ReconnectDialog.class);
private int reconnectAttempt = 0;
private Type reconnectionCause = null;
- private enum Type {
- HEARTBEAT, MESSAGE
+ private Timer scheduledReconnect;
+ private Timer dialogShowTimer = new Timer() {
+
+ @Override
+ public void run() {
+ showDialog();
+ }
+
+ };
+
+ protected enum Type {
+ HEARTBEAT(0), PUSH(1), XHR(2);
+
+ private int priority;
+
+ private Type(int priority) {
+ this.priority = priority;
+ }
+
+ public boolean isMessage() {
+ return this == PUSH || this == XHR;
+ }
+
+ /**
+ * Checks if this type is of higher priority than the given type
+ *
+ * @param type
+ * the type to compare to
+ * @return true if this type has higher priority than the given type,
+ * false otherwise
+ */
+ public boolean isHigherPriorityThan(Type type) {
+ return priority > type.priority;
+ }
}
@Override
public void setConnection(ApplicationConnection connection) {
this.connection = connection;
+
+ connection.addHandler(ApplicationStoppedEvent.TYPE,
+ new ApplicationStoppedHandler() {
+ @Override
+ public void onApplicationStopped(
+ ApplicationStoppedEvent event) {
+ if (isReconnecting()) {
+ giveUp();
+ }
+ if (scheduledReconnect != null
+ && scheduledReconnect.isRunning()) {
+ scheduledReconnect.cancel();
+ }
+ }
+
+ });
};
+ /**
+ * Checks if we are currently trying to reconnect
+ *
+ * @return true if we have noted a problem and are trying to re-establish
+ * server connection, false otherwise
+ */
+ private boolean isReconnecting() {
+ return reconnectionCause != null;
+ }
+
private static Logger getLogger() {
return Logger.getLogger(ReconnectingCommunicationProblemHandler.class
.getName());
@@ -76,8 +135,9 @@ public class ReconnectingCommunicationProblemHandler implements
@Override
public void xhrException(CommunicationProblemEvent event) {
- getLogger().warning("xhrException");
- handleRecoverableError(Type.MESSAGE, event.getPayload());
+ debug("xhrException");
+ endRequest();
+ handleRecoverableError(Type.XHR, event.getPayload());
}
@Override
@@ -95,6 +155,10 @@ public class ReconnectingCommunicationProblemHandler implements
// Session expired
getConnection().showSessionExpiredError(null);
stopApplication();
+ } else if (response.getStatusCode() == Response.SC_NOT_FOUND) {
+ // UI closed, do nothing as the UI will react to this
+ // Should not trigger reconnect dialog as this will prevent user
+ // input
} else {
handleRecoverableError(Type.HEARTBEAT, null);
}
@@ -102,61 +166,204 @@ public class ReconnectingCommunicationProblemHandler implements
@Override
public void heartbeatOk() {
- getLogger().warning("heartbeatOk");
- resolveTemporaryError(Type.HEARTBEAT, true);
+ debug("heartbeatOk");
+ if (isReconnecting()) {
+ resolveTemporaryError(Type.HEARTBEAT);
+ }
}
- protected void handleRecoverableError(Type type, final JsonObject payload) {
- getLogger().warning("handleTemporaryError(" + type + ")");
+ private void debug(String msg) {
+ if (false) {
+ getLogger().warning(msg);
+ }
+ }
- reconnectAttempt++;
- reconnectionCause = type;
- if (!reconnectDialog.isAttached()) {
- reconnectDialog.setStyleName(STYLE_RECONNECTING, true);
- reconnectDialog.setOwner(getConnection().getUIConnector()
- .getWidget());
- reconnectDialog.show();
+ /**
+ * Called whenever an error occurs in communication which should be handled
+ * by showing the reconnect dialog and retrying communication until
+ * successful again
+ *
+ * @param type
+ * The type of failure detected
+ * @param payload
+ * The message which did not reach the server, or null if no
+ * message was involved (heartbeat or push connection failed)
+ */
+ protected void handleRecoverableError(Type type, final JsonObject payload) {
+ debug("handleTemporaryError(" + type + ")");
+ if (!connection.isApplicationRunning()) {
+ return;
}
- if (payload != null) {
- getConnection().getServerCommunicationHandler().endRequest();
+
+ if (!isReconnecting()) {
+ // First problem encounter
+ reconnectionCause = type;
+ getLogger().warning("Reconnecting because of " + type + " failure");
+ // Precaution only as there should never be a dialog at this point
+ // and no timer running
+ stopDialogTimer();
+ if (isDialogVisible()) {
+ hideDialog();
+ }
+
+ // Show dialog after grace period, still continue to try to
+ // reconnect even before it is shown
+ dialogShowTimer.schedule(getConfiguration().dialogGracePeriod);
+ } else {
+ // We are currently trying to reconnect
+ // Priority is HEARTBEAT -> PUSH -> XHR
+ // If a higher priority issues is resolved, we can assume the lower
+ // one will be also
+ if (type.isHigherPriorityThan(reconnectionCause)) {
+ getLogger().warning(
+ "Now reconnecting because of " + type + " failure");
+ reconnectionCause = type;
+ }
}
- if (reconnectAttempt >= getConfiguration().reconnectAttempts) {
- // Max attempts reached
- reconnectDialog.setText(getDialogTextGaveUp(reconnectAttempt));
- reconnectDialog.setStyleName(STYLE_RECONNECTING, false);
+ if (reconnectionCause != type) {
+ return;
+ }
- getConnection().setApplicationRunning(false);
+ reconnectAttempt++;
+ getLogger().info(
+ "Reconnect attempt " + reconnectAttempt + " for " + type);
+ if (reconnectAttempt >= getConfiguration().reconnectAttempts) {
+ // Max attempts reached, stop trying
+ giveUp();
} else {
- reconnectDialog.setText(getDialogText(reconnectAttempt));
+ updateDialog();
+ scheduleReconnect(payload);
+ }
+ }
- // Here and not in timer to avoid TB for getting in between
- if (payload != null) {
- getConnection().getServerCommunicationHandler().startRequest();
- }
+ /**
+ * Called after a problem occurred.
+ *
+ * This method is responsible for re-sending the payload to the server (if
+ * not null) or re-send a heartbeat request at some point
+ *
+ * @param payload
+ * the payload that did not reach the server, null if the problem
+ * was detected by a heartbeat
+ */
+ protected void scheduleReconnect(final JsonObject payload) {
+ // Here and not in timer to avoid TB for getting in between
+ if (payload != null) {
+ getConnection().getServerCommunicationHandler().startRequest();
+ }
- // Reconnect
- new Timer() {
+ if (reconnectAttempt == 1) {
+ // Try once immediately
+ doReconnect(payload);
+ } else {
+ scheduledReconnect = 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();
- }
+ scheduledReconnect = null;
+ doReconnect(payload);
}
- }.schedule(getConfiguration().reconnectInterval);
+ };
+ scheduledReconnect.schedule(getConfiguration().reconnectInterval);
}
}
/**
+ * Re-sends the payload to the server (if not null) or re-sends a heartbeat
+ * request immediately
+ *
+ * @param payload
+ * the payload that did not reach the server, null if the problem
+ * was detected by a heartbeat
+ */
+ protected void doReconnect(JsonObject payload) {
+ if (!connection.isApplicationRunning()) {
+ // This should not happen as nobody should call this if the
+ // application has been stopped
+ getLogger()
+ .warning(
+ "Trying to reconnect after application has been stopped. Giving up");
+ return;
+ }
+ 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();
+ }
+ }
+
+ /**
+ * Called whenever a reconnect attempt fails to allow updating of dialog
+ * contents
+ */
+ protected void updateDialog() {
+ reconnectDialog.setText(getDialogText(reconnectAttempt));
+ }
+
+ /**
+ * Called when we should give up trying to reconnect and let the user decide
+ * how to continue
+ *
+ */
+ protected void giveUp() {
+ stopDialogTimer();
+ if (!isDialogVisible()) {
+ // It SHOULD always be visible at this point, unless you have a
+ // really strange configuration (grace time longer than total
+ // reconnect time)
+ showDialog();
+ }
+ reconnectDialog.setText(getDialogTextGaveUp(reconnectAttempt));
+ reconnectDialog.setReconnecting(false);
+
+ // Stopping the application stops heartbeats and push
+ connection.setApplicationRunning(false);
+ }
+
+ /**
+ * Ensures the reconnect dialog does not popup some time from now
+ */
+ private void stopDialogTimer() {
+ if (dialogShowTimer.isRunning()) {
+ dialogShowTimer.cancel();
+ }
+ }
+
+ /**
+ * Checks if the reconnect dialog is visible to the user
+ *
+ * @return true if the user can see the dialog, false otherwise
+ */
+ protected boolean isDialogVisible() {
+ return reconnectDialog.isVisible();
+ }
+
+ /**
+ * Called when the reconnect dialog should be shown. This is typically when
+ * N seconds has passed since a problem with the connection has been
+ * detected
+ */
+ protected void showDialog() {
+ reconnectDialog.setReconnecting(true);
+ reconnectDialog.show(connection);
+
+ // We never want to show loading indicator and reconnect dialog at the
+ // same time
+ connection.getLoadingIndicator().hide();
+ }
+
+ /**
+ * Called when the reconnect dialog should be hidden.
+ */
+ protected void hideDialog() {
+ reconnectDialog.hide();
+ }
+
+ /**
* Gets the text to show in the reconnect dialog after giving up (reconnect
* limit reached)
*
@@ -187,7 +394,9 @@ public class ReconnectingCommunicationProblemHandler implements
@Override
public void xhrInvalidContent(CommunicationProblemEvent event) {
- getLogger().warning("xhrInvalidContent");
+ debug("xhrInvalidContent");
+ endRequest();
+
String responseText = event.getResponse().getText();
/*
* A servlet filter or equivalent may have intercepted the request and
@@ -214,7 +423,9 @@ public class ReconnectingCommunicationProblemHandler implements
@Override
public void xhrInvalidStatusCode(CommunicationProblemEvent event) {
- getLogger().warning("xhrInvalidStatusCode");
+ debug("xhrInvalidStatusCode");
+ endRequest();
+
Response response = event.getResponse();
int statusCode = response.getStatusCode();
getLogger().warning("Server returned " + statusCode + " for xhr");
@@ -228,22 +439,23 @@ public class ReconnectingCommunicationProblemHandler implements
// proxy between the client and the server and e.g. restart the
// server
// 5xx codes may or may not be temporary
- handleRecoverableError(Type.MESSAGE, event.getPayload());
+ handleRecoverableError(Type.XHR, event.getPayload());
}
}
+ /**
+ * @since
+ */
+ private void endRequest() {
+ getConnection().getServerCommunicationHandler().endRequest();
+ }
+
protected void handleUnauthorized(CommunicationProblemEvent event) {
/*
* Authorization has failed (401). Could be that the session has timed
* out.
*/
connection.showAuthenticationError("");
- endRequestAndStopApplication();
- }
-
- private void endRequestAndStopApplication() {
- connection.getServerCommunicationHandler().endRequest();
-
stopApplication();
}
@@ -253,10 +465,6 @@ public class ReconnectingCommunicationProblemHandler implements
connection.setApplicationRunning(false);
}
- /**
- * @since
- * @param event
- */
private void handleUnrecoverableCommunicationError(String details,
CommunicationProblemEvent event) {
Response response = event.getResponse();
@@ -266,46 +474,38 @@ public class ReconnectingCommunicationProblemHandler implements
}
connection.handleCommunicationError(details, statusCode);
- endRequestAndStopApplication();
+ stopApplication();
}
@Override
public void xhrOk() {
- getLogger().warning("xhrOk");
- resolveTemporaryError(Type.MESSAGE, true);
+ debug("xhrOk");
+ if (isReconnecting()) {
+ resolveTemporaryError(Type.XHR);
+ }
}
- private void resolveTemporaryError(Type type, boolean success) {
- getLogger().warning("resolveTemporaryError(" + type + ")");
+ private void resolveTemporaryError(Type type) {
+ debug("resolveTemporaryError(" + type + ")");
- if (reconnectionCause == null) {
- // Not trying to reconnect
- return;
- }
- if (reconnectionCause == Type.MESSAGE && type == Type.HEARTBEAT) {
- // If a heartbeat goes through while we are trying to re-send an
- // XHR, we wait for the XHR to go through to avoid removing the
- // reconnect dialog and then possible showing it again
+ if (reconnectionCause != type) {
+ // Waiting for some other problem to be resolved
return;
}
reconnectionCause = null;
- if (reconnectDialog.isAttached()) {
- reconnectDialog.hide();
- }
-
- if (success && reconnectAttempt != 0) {
- getLogger().info("Re-established connection to server");
- reconnectAttempt = 0;
- }
+ hideDialog();
+ getLogger().info("Re-established connection to server");
}
@Override
public void pushOk(PushConnection pushConnection) {
- getLogger().warning("pushOk()");
- resolveTemporaryError(Type.MESSAGE, true);
+ debug("pushOk()");
+ if (isReconnecting()) {
+ resolveTemporaryError(Type.PUSH);
+ }
}
@Override
@@ -316,28 +516,37 @@ public class ReconnectingCommunicationProblemHandler implements
@Override
public void pushNotConnected(JsonObject payload) {
- getLogger().warning("pushNotConnected()");
- handleRecoverableError(Type.MESSAGE, payload);
+ debug("pushNotConnected()");
+ endRequest();
+ handleRecoverableError(Type.PUSH, payload);
}
@Override
public void pushReconnectPending(PushConnection pushConnection) {
- getLogger().warning(
- "pushReconnectPending(" + pushConnection.getTransportType()
- + ")");
+ debug("pushReconnectPending(" + pushConnection.getTransportType() + ")");
getLogger().info("Reopening push connection");
+ if (pushConnection.isBidirectional()) {
+ // Lost connection for a connection which will tell us when the
+ // connection is available again
+ handleRecoverableError(Type.PUSH, null);
+ } else {
+ // Lost connection for a connection we do not necessarily know when
+ // it is available again (long polling behind proxy). Do nothing and
+ // show reconnect dialog if the user does something and the XHR
+ // fails
+ }
}
@Override
public void pushError(PushConnection pushConnection) {
- getLogger().warning("pushError()");
+ debug("pushError()");
connection.handleCommunicationError("Push connection using "
+ pushConnection.getTransportType() + " failed!", -1);
}
@Override
public void pushClientTimeout(PushConnection pushConnection) {
- getLogger().warning("pushClientTimeout()");
+ debug("pushClientTimeout()");
// TODO Reconnect, allowing client timeout to be set
// https://dev.vaadin.com/ticket/18429
connection
@@ -348,7 +557,7 @@ public class ReconnectingCommunicationProblemHandler implements
@Override
public void pushClosed(PushConnection pushConnection) {
- getLogger().warning("pushClosed()");
+ debug("pushClosed()");
getLogger().info("Push connection closed");
}
diff --git a/client/src/com/vaadin/client/communication/ServerCommunicationHandler.java b/client/src/com/vaadin/client/communication/ServerCommunicationHandler.java
index ba1e0497cc..fb7e5bb83b 100644
--- a/client/src/com/vaadin/client/communication/ServerCommunicationHandler.java
+++ b/client/src/com/vaadin/client/communication/ServerCommunicationHandler.java
@@ -245,8 +245,7 @@ public class ServerCommunicationHandler {
}
// After sendInvocationsToServer() there may be a new active
// request, so we must set hasActiveRequest to false before, not after,
- // the call. Active requests used to be tracked with an integer counter,
- // so setting it after used to work but not with the #8505 changes.
+ // the call.
hasActiveRequest = false;
if (connection.isApplicationRunning()) {
diff --git a/shared/src/com/vaadin/shared/ui/ui/UIState.java b/shared/src/com/vaadin/shared/ui/ui/UIState.java
index 1a2e1e4f46..0e21324cc2 100644
--- a/shared/src/com/vaadin/shared/ui/ui/UIState.java
+++ b/shared/src/com/vaadin/shared/ui/ui/UIState.java
@@ -130,6 +130,7 @@ public class UIState extends TabIndexState {
public String dialogTextGaveUp = "Server connection lost.";
public int reconnectAttempts = 10000;
public int reconnectInterval = 5000;
+ public int dialogGracePeriod = 1000;
}
public static class LocaleServiceState implements Serializable {
diff --git a/uitest/src/com/vaadin/tests/application/CommErrorEmulatorUI.java b/uitest/src/com/vaadin/tests/application/CommErrorEmulatorUI.java
index 6b1e13cd5c..9649b346b6 100644
--- a/uitest/src/com/vaadin/tests/application/CommErrorEmulatorUI.java
+++ b/uitest/src/com/vaadin/tests/application/CommErrorEmulatorUI.java
@@ -185,12 +185,26 @@ public class CommErrorEmulatorUI extends AbstractTestUIWithLog {
}
});
+ final TextField reconnectDialogGracePeriod = new TextField(
+ "Reconnect dialog grace period (ms)");
+ reconnectDialogGracePeriod.setConverter(Integer.class);
+ reconnectDialogGracePeriod
+ .setConvertedValue(getState().reconnectDialog.dialogGracePeriod);
+ reconnectDialogGracePeriod
+ .addValueChangeListener(new ValueChangeListener() {
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ getState().reconnectDialog.dialogGracePeriod = (Integer) reconnectDialogGracePeriod
+ .getConvertedValue();
+ }
+ });
+
VerticalLayout vl = new VerticalLayout();
vl.setMargin(true);
vl.setSpacing(true);
p.setContent(vl);
vl.addComponents(reconnectDialogMessage, reconnectDialogGaveUpMessage,
- reconnectDialogReconnectAttempts,
+ reconnectDialogGracePeriod, reconnectDialogReconnectAttempts,
reconnectDialogReconnectInterval);
return p;
}