From df3e10d969ec976216a3d5578420f38bbf649589 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Fri, 28 Aug 2015 15:44:54 +0300 Subject: [PATCH] Add modality configuration option for reconnect dialog (#11733) Leave the request state as open until reconnect is done and the message has been delivered. This avoids flushing the rpc queue during reconnect, which would cause two concurrent requests. Change-Id: I320ffccd49c26acd16bd70b34ba28b465d17842c --- .../CommunicationProblemHandler.java | 7 ++ .../client/communication/ReconnectDialog.java | 20 +++++ ...connectingCommunicationProblemHandler.java | 20 +++-- .../com/vaadin/client/ui/ui/UIConnector.java | 4 + .../ui/ReconnectDialogConfiguration.java | 75 +++++++++++++++++-- .../src/com/vaadin/shared/ui/ui/UIState.java | 3 +- .../application/CommErrorEmulatorUI.java | 55 +++++++++----- 7 files changed, 151 insertions(+), 33 deletions(-) diff --git a/client/src/com/vaadin/client/communication/CommunicationProblemHandler.java b/client/src/com/vaadin/client/communication/CommunicationProblemHandler.java index d47846060e..73c13864da 100644 --- a/client/src/com/vaadin/client/communication/CommunicationProblemHandler.java +++ b/client/src/com/vaadin/client/communication/CommunicationProblemHandler.java @@ -185,4 +185,11 @@ public interface CommunicationProblemHandler { */ void pushInvalidContent(PushConnection pushConnection, String message); + /** + * Called when some part of the reconnect dialog configuration has been + * changed. + * + */ + void configurationUpdated(); + } diff --git a/client/src/com/vaadin/client/communication/ReconnectDialog.java b/client/src/com/vaadin/client/communication/ReconnectDialog.java index 21f47ecbf6..5e1fe790f3 100644 --- a/client/src/com/vaadin/client/communication/ReconnectDialog.java +++ b/client/src/com/vaadin/client/communication/ReconnectDialog.java @@ -62,4 +62,24 @@ public interface ReconnectDialog { * Hides the dialog from the user */ void hide(); + + /** + * Sets the modality of the dialog. If the dialog is set to modal, it will + * prevent the usage of the application while the dialog is being shown. If + * not modal, the user can continue to use the application as normally and + * all server events will be queued until connection has been + * re-established. + * + * @param modal + * true to set the dialog to modal, false otherwise + */ + void setModal(boolean modal); + + /** + * Checks the modality of the dialog. + * + * @see #setModal(boolean) + * @return + */ + boolean isModal(); } diff --git a/client/src/com/vaadin/client/communication/ReconnectingCommunicationProblemHandler.java b/client/src/com/vaadin/client/communication/ReconnectingCommunicationProblemHandler.java index 33f7395536..ed77fc64cd 100644 --- a/client/src/com/vaadin/client/communication/ReconnectingCommunicationProblemHandler.java +++ b/client/src/com/vaadin/client/communication/ReconnectingCommunicationProblemHandler.java @@ -136,7 +136,6 @@ public class ReconnectingCommunicationProblemHandler implements @Override public void xhrException(CommunicationProblemEvent event) { debug("xhrException"); - endRequest(); handleRecoverableError(Type.XHR, event.getPayload()); } @@ -250,10 +249,9 @@ public class ReconnectingCommunicationProblemHandler implements */ protected void scheduleReconnect(final JsonObject payload) { // Here and not in timer to avoid TB for getting in between - if (payload != null) { - getConnection().getServerCommunicationHandler().startRequest(); - } + // The request is still open at this point to avoid interference, so we + // do not need to start a new one if (reconnectAttempt == 1) { // Try once immediately doReconnect(payload); @@ -310,6 +308,9 @@ public class ReconnectingCommunicationProblemHandler implements * */ protected void giveUp() { + reconnectionCause = null; + endRequest(); + stopDialogTimer(); if (!isDialogVisible()) { // It SHOULD always be visible at this point, unless you have a @@ -388,8 +389,14 @@ public class ReconnectingCommunicationProblemHandler implements + ""); } + @Override + public void configurationUpdated() { + // All other properties are fetched directly from the state when needed + reconnectDialog.setModal(getConfiguration().dialogModal); + } + private ReconnectDialogConfigurationState getConfiguration() { - return connection.getUIConnector().getState().reconnectDialog; + return connection.getUIConnector().getState().reconnectDialogConfiguration; } @Override @@ -424,7 +431,6 @@ public class ReconnectingCommunicationProblemHandler implements @Override public void xhrInvalidStatusCode(CommunicationProblemEvent event) { debug("xhrInvalidStatusCode"); - endRequest(); Response response = event.getResponse(); int statusCode = response.getStatusCode(); @@ -432,6 +438,7 @@ public class ReconnectingCommunicationProblemHandler implements if (statusCode == 401) { // Authentication/authorization failed, no need to re-try + endRequest(); handleUnauthorized(event); return; } else { @@ -517,7 +524,6 @@ public class ReconnectingCommunicationProblemHandler implements @Override public void pushNotConnected(JsonObject payload) { debug("pushNotConnected()"); - endRequest(); handleRecoverableError(Type.PUSH, payload); } diff --git a/client/src/com/vaadin/client/ui/ui/UIConnector.java b/client/src/com/vaadin/client/ui/ui/UIConnector.java index 6d708a9f14..9fe71beaa0 100644 --- a/client/src/com/vaadin/client/ui/ui/UIConnector.java +++ b/client/src/com/vaadin/client/ui/ui/UIConnector.java @@ -751,6 +751,10 @@ public class UIConnector extends AbstractSingleComponentContainerConnector getConnection().getServerCommunicationHandler().setPushEnabled( getState().pushConfiguration.mode.isEnabled()); } + if (stateChangeEvent.hasPropertyChanged("reconnectDialogConfiguration")) { + getConnection().getCommunicationProblemHandler() + .configurationUpdated(); + } if (stateChangeEvent.hasPropertyChanged("overlayContainerLabel")) { VOverlay.setOverlayContainerLabel(getConnection(), diff --git a/server/src/com/vaadin/ui/ReconnectDialogConfiguration.java b/server/src/com/vaadin/ui/ReconnectDialogConfiguration.java index 9c40b27da8..92eb1e785f 100644 --- a/server/src/com/vaadin/ui/ReconnectDialogConfiguration.java +++ b/server/src/com/vaadin/ui/ReconnectDialogConfiguration.java @@ -90,6 +90,45 @@ public interface ReconnectDialogConfiguration extends Serializable { * the interval (in ms) between reconnect attempts */ public void setReconnectInterval(int reconnectInterval); + + /** + * Gets the timeout (in milliseconds) between noticing a loss of connection + * and showing the dialog. + * + * @return the time to wait before showing a dialog + */ + public int getDialogGracePeriod(); + + /** + * Sets the timeout (in milliseconds) between noticing a loss of connection + * and showing the dialog. + * + * @param dialogGracePeriod + * the time to wait before showing a dialog + */ + public void setDialogGracePeriod(int dialogGracePeriod); + + /** + * Sets the modality of the dialog. + *

+ * If the dialog is set to modal, it will prevent the usage of the + * application while the dialog is being shown. If not modal, the user can + * continue to use the application as normally and all server events will be + * queued until connection has been re-established. + * + * @param dialogModal + * true to make the dialog modal, false otherwise + */ + public void setDialogModal(boolean dialogModal); + + /** + * Checks the modality of the dialog. + *

+ * + * @see #setDialogModal(boolean) + * @return true if the dialog is modal, false otherwise + */ + public boolean isDialogModal(); } class ReconnectDialogConfigurationImpl implements ReconnectDialogConfiguration { @@ -101,42 +140,62 @@ class ReconnectDialogConfigurationImpl implements ReconnectDialogConfiguration { @Override public String getDialogText() { - return ui.getState(false).reconnectDialog.dialogText; + return ui.getState(false).reconnectDialogConfiguration.dialogText; } @Override public void setDialogText(String dialogText) { - ui.getState().reconnectDialog.dialogText = dialogText; + ui.getState().reconnectDialogConfiguration.dialogText = dialogText; } @Override public String getDialogTextGaveUp() { - return ui.getState(false).reconnectDialog.dialogTextGaveUp; + return ui.getState(false).reconnectDialogConfiguration.dialogTextGaveUp; } @Override public void setDialogTextGaveUp(String dialogTextGaveUp) { - ui.getState().reconnectDialog.dialogTextGaveUp = dialogTextGaveUp; + ui.getState().reconnectDialogConfiguration.dialogTextGaveUp = dialogTextGaveUp; } @Override public int getReconnectAttempts() { - return ui.getState(false).reconnectDialog.reconnectAttempts; + return ui.getState(false).reconnectDialogConfiguration.reconnectAttempts; } @Override public void setReconnectAttempts(int reconnectAttempts) { - ui.getState().reconnectDialog.reconnectAttempts = reconnectAttempts; + ui.getState().reconnectDialogConfiguration.reconnectAttempts = reconnectAttempts; } @Override public int getReconnectInterval() { - return ui.getState(false).reconnectDialog.reconnectInterval; + return ui.getState(false).reconnectDialogConfiguration.reconnectInterval; } @Override public void setReconnectInterval(int reconnectInterval) { - ui.getState().reconnectDialog.reconnectInterval = reconnectInterval; + ui.getState().reconnectDialogConfiguration.reconnectInterval = reconnectInterval; + } + + @Override + public int getDialogGracePeriod() { + return ui.getState(false).reconnectDialogConfiguration.dialogGracePeriod; + } + + @Override + public void setDialogGracePeriod(int dialogGracePeriod) { + ui.getState().reconnectDialogConfiguration.dialogGracePeriod = dialogGracePeriod; + } + + @Override + public boolean isDialogModal() { + return ui.getState(false).reconnectDialogConfiguration.dialogModal; + } + + @Override + public void setDialogModal(boolean dialogModal) { + ui.getState().reconnectDialogConfiguration.dialogModal = dialogModal; } } diff --git a/shared/src/com/vaadin/shared/ui/ui/UIState.java b/shared/src/com/vaadin/shared/ui/ui/UIState.java index 6991f2b1cb..442c3a1ffb 100644 --- a/shared/src/com/vaadin/shared/ui/ui/UIState.java +++ b/shared/src/com/vaadin/shared/ui/ui/UIState.java @@ -72,7 +72,7 @@ public class UIState extends TabIndexState { * @since 7.3 */ public String theme; - public ReconnectDialogConfigurationState reconnectDialog = new ReconnectDialogConfigurationState(); + public ReconnectDialogConfigurationState reconnectDialogConfiguration = new ReconnectDialogConfigurationState(); { primaryStyleName = "v-ui"; // Default is 1 for legacy reasons @@ -132,6 +132,7 @@ public class UIState extends TabIndexState { public int reconnectAttempts = 10000; public int reconnectInterval = 5000; public int dialogGracePeriod = 1000; + public boolean dialogModal = true; } 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 6e879d2a9b..da03e78f1f 100644 --- a/uitest/src/com/vaadin/tests/application/CommErrorEmulatorUI.java +++ b/uitest/src/com/vaadin/tests/application/CommErrorEmulatorUI.java @@ -27,6 +27,7 @@ import com.vaadin.ui.Alignment; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.CheckBox; import com.vaadin.ui.Component; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; @@ -135,13 +136,14 @@ public class CommErrorEmulatorUI extends AbstractTestUIWithLog { final TextField reconnectDialogMessage = new TextField( "Reconnect message"); reconnectDialogMessage.setWidth("50em"); - reconnectDialogMessage.setValue(getState().reconnectDialog.dialogText); + reconnectDialogMessage.setValue(getReconnectDialogConfiguration() + .getDialogText()); reconnectDialogMessage .addValueChangeListener(new ValueChangeListener() { @Override public void valueChange(ValueChangeEvent event) { - getState().reconnectDialog.dialogText = reconnectDialogMessage - .getValue(); + getReconnectDialogConfiguration().setDialogText( + reconnectDialogMessage.getValue()); } }); @@ -149,40 +151,44 @@ public class CommErrorEmulatorUI extends AbstractTestUIWithLog { "Reconnect gave up message"); reconnectDialogGaveUpMessage.setWidth("50em"); - reconnectDialogGaveUpMessage - .setValue(getState().reconnectDialog.dialogTextGaveUp); + reconnectDialogGaveUpMessage.setValue(getReconnectDialogConfiguration() + .getDialogTextGaveUp()); reconnectDialogGaveUpMessage .addValueChangeListener(new ValueChangeListener() { @Override public void valueChange(ValueChangeEvent event) { - getState().reconnectDialog.dialogTextGaveUp = reconnectDialogGaveUpMessage - .getValue(); + getReconnectDialogConfiguration().setDialogTextGaveUp( + reconnectDialogGaveUpMessage.getValue()); } }); final TextField reconnectDialogReconnectAttempts = new TextField( "Reconnect attempts"); reconnectDialogReconnectAttempts.setConverter(Integer.class); reconnectDialogReconnectAttempts - .setConvertedValue(getState().reconnectDialog.reconnectAttempts); + .setConvertedValue(getReconnectDialogConfiguration() + .getReconnectAttempts()); reconnectDialogReconnectAttempts .addValueChangeListener(new ValueChangeListener() { @Override public void valueChange(ValueChangeEvent event) { - getState().reconnectDialog.reconnectAttempts = (Integer) reconnectDialogReconnectAttempts - .getConvertedValue(); + getReconnectDialogConfiguration().setReconnectAttempts( + (Integer) reconnectDialogReconnectAttempts + .getConvertedValue()); } }); final TextField reconnectDialogReconnectInterval = new TextField( "Reconnect interval (ms)"); reconnectDialogReconnectInterval.setConverter(Integer.class); reconnectDialogReconnectInterval - .setConvertedValue(getState().reconnectDialog.reconnectInterval); + .setConvertedValue(getReconnectDialogConfiguration() + .getReconnectInterval()); reconnectDialogReconnectInterval .addValueChangeListener(new ValueChangeListener() { @Override public void valueChange(ValueChangeEvent event) { - getState().reconnectDialog.reconnectInterval = (Integer) reconnectDialogReconnectInterval - .getConvertedValue(); + getReconnectDialogConfiguration().setReconnectInterval( + (Integer) reconnectDialogReconnectInterval + .getConvertedValue()); } }); @@ -190,22 +196,37 @@ public class CommErrorEmulatorUI extends AbstractTestUIWithLog { "Reconnect dialog grace period (ms)"); reconnectDialogGracePeriod.setConverter(Integer.class); reconnectDialogGracePeriod - .setConvertedValue(getState().reconnectDialog.dialogGracePeriod); + .setConvertedValue(getReconnectDialogConfiguration() + .getDialogGracePeriod()); reconnectDialogGracePeriod .addValueChangeListener(new ValueChangeListener() { @Override public void valueChange(ValueChangeEvent event) { - getState().reconnectDialog.dialogGracePeriod = (Integer) reconnectDialogGracePeriod - .getConvertedValue(); + getReconnectDialogConfiguration().setDialogGracePeriod( + (Integer) reconnectDialogGracePeriod + .getConvertedValue()); } }); + final CheckBox reconnectDialogModal = new CheckBox( + "Reconnect dialog modality"); + reconnectDialogModal.setValue(getReconnectDialogConfiguration() + .isDialogModal()); + reconnectDialogModal.addValueChangeListener(new ValueChangeListener() { + @Override + public void valueChange(ValueChangeEvent event) { + getReconnectDialogConfiguration().setDialogModal( + reconnectDialogModal.getValue()); + } + }); + VerticalLayout vl = new VerticalLayout(); vl.setMargin(true); vl.setSpacing(true); p.setContent(vl); vl.addComponents(reconnectDialogMessage, reconnectDialogGaveUpMessage, - reconnectDialogGracePeriod, reconnectDialogReconnectAttempts, + reconnectDialogGracePeriod, reconnectDialogModal, + reconnectDialogReconnectAttempts, reconnectDialogReconnectInterval); return p; } -- 2.39.5