From 04100c62ac45550f12f8c631fb83140a0af0a48b Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Sat, 25 Apr 2015 16:02:20 +0300 Subject: Allow configuration of reconnect dialog parameters (#11733) Change-Id: Ibf60ef8cdd21204e8ccfbb0a7d93cf88c4d8468a --- .../ReconnectingCommunicationProblemHandler.java | 58 +++++---- .../vaadin/ui/ReconnectDialogConfiguration.java | 142 +++++++++++++++++++++ server/src/com/vaadin/ui/UI.java | 12 ++ shared/src/com/vaadin/shared/ui/ui/UIState.java | 9 ++ .../tests/application/CommErrorEmulatorUI.java | 110 ++++++++++++++-- 5 files changed, 296 insertions(+), 35 deletions(-) create mode 100644 server/src/com/vaadin/ui/ReconnectDialogConfiguration.java diff --git a/client/src/com/vaadin/client/communication/ReconnectingCommunicationProblemHandler.java b/client/src/com/vaadin/client/communication/ReconnectingCommunicationProblemHandler.java index 558cce0252..7f09c502d8 100644 --- a/client/src/com/vaadin/client/communication/ReconnectingCommunicationProblemHandler.java +++ b/client/src/com/vaadin/client/communication/ReconnectingCommunicationProblemHandler.java @@ -23,9 +23,9 @@ import com.google.gwt.http.client.Response; import com.google.gwt.regexp.shared.MatchResult; import com.google.gwt.regexp.shared.RegExp; import com.google.gwt.user.client.Timer; -import com.google.gwt.user.client.ui.PopupPanel.PositionCallback; import com.vaadin.client.ApplicationConnection; import com.vaadin.client.WidgetUtil; +import com.vaadin.shared.ui.ui.UIState.ReconnectDialogConfigurationState; import elemental.json.JsonObject; @@ -44,6 +44,8 @@ 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; @@ -110,31 +112,24 @@ public class ReconnectingCommunicationProblemHandler implements reconnectAttempt++; reconnectionCause = type; if (!reconnectDialog.isAttached()) { - reconnectDialog.setStyleName("active", true); + reconnectDialog.setStyleName(STYLE_RECONNECTING, true); reconnectDialog.setOwner(getConnection().getUIConnector() .getWidget()); - reconnectDialog.setPopupPositionAndShow(new PositionCallback() { - @Override - public void setPosition(int offsetWidth, int offsetHeight) { - reconnectDialog.setPopupPosition(0, 0); - } - }); + reconnectDialog.show(); } if (payload != null) { getConnection().getServerCommunicationHandler().endRequest(); } - if (reconnectAttempt >= getMaxReconnectAttempts()) { - reconnectDialog.setText("Server connection lost. Gave up after " - + reconnectAttempt + " attempts."); - reconnectDialog.setStyleName("active", false); + if (reconnectAttempt >= getConfiguration().reconnectAttempts) { + // Max attempts reached + reconnectDialog.setText(getDialogTextGaveUp(reconnectAttempt)); + reconnectDialog.setStyleName(STYLE_RECONNECTING, false); getConnection().setApplicationRunning(false); } else { - reconnectDialog - .setText("Server connection lost, trying to reconnect... Attempt " - + reconnectAttempt); + reconnectDialog.setText(getDialogText(reconnectAttempt)); // Here and not in timer to avoid TB for getting in between if (payload != null) { @@ -157,26 +152,37 @@ public class ReconnectingCommunicationProblemHandler implements getConnection().getHeartbeat().send(); } } - }.schedule(getReconnectInterval()); + }.schedule(getConfiguration().reconnectInterval); } } /** - * @since - * @return + * Gets the text to show in the reconnect dialog after giving up (reconnect + * limit reached) + * + * @param reconnectAttempt + * The number of the current reconnection attempt + * @return The text to show in the reconnect dialog after giving up */ - private int getMaxReconnectAttempts() { - // FIXME Parameter - return 15; + protected String getDialogTextGaveUp(int reconnectAttempt) { + return getConfiguration().dialogTextGaveUp.replace("{0}", + reconnectAttempt + ""); } /** - * @since - * @return + * Gets the text to show in the reconnect dialog + * + * @param reconnectAttempt + * The number of the current reconnection attempt + * @return The text to show in the reconnect dialog */ - private int getReconnectInterval() { - // FIXME Parameter - return 5000; + protected String getDialogText(int reconnectAttempt) { + return getConfiguration().dialogText.replace("{0}", reconnectAttempt + + ""); + } + + private ReconnectDialogConfigurationState getConfiguration() { + return connection.getUIConnector().getState().reconnectDialog; } @Override diff --git a/server/src/com/vaadin/ui/ReconnectDialogConfiguration.java b/server/src/com/vaadin/ui/ReconnectDialogConfiguration.java new file mode 100644 index 0000000000..9c40b27da8 --- /dev/null +++ b/server/src/com/vaadin/ui/ReconnectDialogConfiguration.java @@ -0,0 +1,142 @@ +/* + * 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.ui; + +import java.io.Serializable; + +/** + * Provides method for configuring the reconnect dialog. + * + * @since 7.6 + * @author Vaadin Ltd + */ +public interface ReconnectDialogConfiguration extends Serializable { + /** + * Gets the text to show in the reconnect dialog when trying to re-establish + * the server connection + * + * @return the text to show in the reconnect dialog + */ + public String getDialogText(); + + /** + * Sets the text to show in the reconnect dialog when trying to re-establish + * the server connection + * + * @param dialogText + * the text to show in the reconnect dialog + */ + public void setDialogText(String dialogText); + + /** + * Gets the text to show in the reconnect dialog after giving up trying to + * reconnect ({@link #getReconnectAttempts()} reached) + * + * @return the text to show in the reconnect dialog after giving up + */ + public String getDialogTextGaveUp(); + + /** + * Sets the text to show in the reconnect dialog after giving up trying to + * reconnect ({@link #getReconnectAttempts()} reached) + * + * @param dialogText + * the text to show in the reconnect dialog after giving up + */ + public void setDialogTextGaveUp(String dialogTextGaveUp); + + /** + * Gets the number of times to try to reconnect to the server before giving + * up + * + * @return the number of times to try to reconnect + */ + public int getReconnectAttempts(); + + /** + * Sets the number of times to try to reconnect to the server before giving + * up + * + * @param reconnectAttempts + * the number of times to try to reconnect + */ + public void setReconnectAttempts(int reconnectAttempts); + + /** + * Gets the interval (in milliseconds) between reconnect attempts + * + * @return the interval (in ms) between reconnect attempts + */ + public int getReconnectInterval(); + + /** + * Sets the interval (in milliseconds) between reconnect attempts + * + * @param reconnectInterval + * the interval (in ms) between reconnect attempts + */ + public void setReconnectInterval(int reconnectInterval); +} + +class ReconnectDialogConfigurationImpl implements ReconnectDialogConfiguration { + private UI ui; + + public ReconnectDialogConfigurationImpl(UI ui) { + this.ui = ui; + } + + @Override + public String getDialogText() { + return ui.getState(false).reconnectDialog.dialogText; + } + + @Override + public void setDialogText(String dialogText) { + ui.getState().reconnectDialog.dialogText = dialogText; + } + + @Override + public String getDialogTextGaveUp() { + return ui.getState(false).reconnectDialog.dialogTextGaveUp; + } + + @Override + public void setDialogTextGaveUp(String dialogTextGaveUp) { + ui.getState().reconnectDialog.dialogTextGaveUp = dialogTextGaveUp; + } + + @Override + public int getReconnectAttempts() { + return ui.getState(false).reconnectDialog.reconnectAttempts; + } + + @Override + public void setReconnectAttempts(int reconnectAttempts) { + ui.getState().reconnectDialog.reconnectAttempts = reconnectAttempts; + } + + @Override + public int getReconnectInterval() { + return ui.getState(false).reconnectDialog.reconnectInterval; + } + + @Override + public void setReconnectInterval(int reconnectInterval) { + ui.getState().reconnectDialog.reconnectInterval = reconnectInterval; + } + +} diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index 28f18a6b92..1e27856af3 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -255,6 +255,8 @@ public abstract class UI extends AbstractSingleComponentContainer implements this); private PushConfiguration pushConfiguration = new PushConfigurationImpl( this); + private ReconnectDialogConfiguration reconnectDialogConfiguration = new ReconnectDialogConfigurationImpl( + this); private NotificationConfiguration notificationConfiguration = new NotificationConfigurationImpl( this); @@ -1645,6 +1647,16 @@ public abstract class UI extends AbstractSingleComponentContainer implements return pushConfiguration; } + /** + * Retrieves the object used for configuring the reconnect dialog. + * + * @since 7.6 + * @return The instance used for reconnect dialog configuration + */ + public ReconnectDialogConfiguration getReconnectDialogConfiguration() { + return reconnectDialogConfiguration; + } + /** * Get the label that is added to the container element, where tooltip, * notification and dialogs are added to. diff --git a/shared/src/com/vaadin/shared/ui/ui/UIState.java b/shared/src/com/vaadin/shared/ui/ui/UIState.java index 6f7a531eb6..1a2e1e4f46 100644 --- a/shared/src/com/vaadin/shared/ui/ui/UIState.java +++ b/shared/src/com/vaadin/shared/ui/ui/UIState.java @@ -72,6 +72,7 @@ public class UIState extends TabIndexState { * @since 7.3 */ public String theme; + public ReconnectDialogConfigurationState reconnectDialog = new ReconnectDialogConfigurationState(); { primaryStyleName = "v-ui"; // Default is 1 for legacy reasons @@ -123,6 +124,14 @@ public class UIState extends TabIndexState { } } + public static class ReconnectDialogConfigurationState implements + Serializable { + public String dialogText = "Server connection lost, trying to reconnect..."; + public String dialogTextGaveUp = "Server connection lost."; + public int reconnectAttempts = 10000; + public int reconnectInterval = 5000; + } + public static class LocaleServiceState implements Serializable { public List localeData = new ArrayList(); } diff --git a/uitest/src/com/vaadin/tests/application/CommErrorEmulatorUI.java b/uitest/src/com/vaadin/tests/application/CommErrorEmulatorUI.java index 58002ce32f..6b1e13cd5c 100644 --- a/uitest/src/com/vaadin/tests/application/CommErrorEmulatorUI.java +++ b/uitest/src/com/vaadin/tests/application/CommErrorEmulatorUI.java @@ -30,7 +30,9 @@ import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.Component; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; +import com.vaadin.ui.Panel; import com.vaadin.ui.TextField; +import com.vaadin.ui.VerticalLayout; /** * @@ -76,31 +78,121 @@ public class CommErrorEmulatorUI extends AbstractTestUIWithLog { } else { log("Using XHR"); } + getLayout().setSpacing(true); + addComponent(createConfigPanel()); + addComponent(createServerConfigPanel()); - addComponent(createTemporaryResponseCodeSetters("UIDL", uidlResponse)); - addComponent(createTemporaryResponseCodeSetters("Heartbeat", + addComponent(new Button("Say hello", new ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + log("Hello"); + } + })); + } + + /** + * @since + * @return + */ + private Component createServerConfigPanel() { + Panel p = new Panel("Server config (NOTE: affects all users)"); + VerticalLayout vl = new VerticalLayout(); + vl.setSpacing(true); + vl.setMargin(true); + p.setContent(vl); + vl.addComponent(createTemporaryResponseCodeSetters("UIDL", uidlResponse)); + vl.addComponent(createTemporaryResponseCodeSetters("Heartbeat", heartbeatResponse)); - addComponent(new Button("Do it", new ClickListener() { + vl.addComponent(new Button("Activate", new ClickListener() { @Override public void buttonClick(ClickEvent event) { if (uidlResponse.code != null && uidlResponse.code != 200) { getServlet().setUIDLResponseCode(uidlResponse.code, uidlResponse.time); + log("Responding with " + uidlResponse.code + + " to UIDL requests for " + uidlResponse.time + + "s"); } if (heartbeatResponse.code != null && heartbeatResponse.code != 200) { getServlet().setHeartbeatResponseCode( heartbeatResponse.code, heartbeatResponse.time); + log("Responding with " + heartbeatResponse.code + + " to heartbeat requests for " + + heartbeatResponse.time + "s"); } } })); - addComponent(new Button("Say hello", new ClickListener() { - @Override - public void buttonClick(ClickEvent event) { - log("Hello"); - } - })); + return p; + } + + private Component createConfigPanel() { + Panel p = new Panel("Reconnect dialog configuration"); + p.setSizeUndefined(); + final TextField reconnectDialogMessage = new TextField( + "Reconnect message"); + reconnectDialogMessage.setWidth("50em"); + reconnectDialogMessage.setValue(getState().reconnectDialog.dialogText); + reconnectDialogMessage + .addValueChangeListener(new ValueChangeListener() { + @Override + public void valueChange(ValueChangeEvent event) { + getState().reconnectDialog.dialogText = reconnectDialogMessage + .getValue(); + } + }); + + final TextField reconnectDialogGaveUpMessage = new TextField( + "Reconnect gave up message"); + reconnectDialogGaveUpMessage.setWidth("50em"); + + reconnectDialogGaveUpMessage + .setValue(getState().reconnectDialog.dialogTextGaveUp); + reconnectDialogGaveUpMessage + .addValueChangeListener(new ValueChangeListener() { + @Override + public void valueChange(ValueChangeEvent event) { + getState().reconnectDialog.dialogTextGaveUp = reconnectDialogGaveUpMessage + .getValue(); + } + }); + final TextField reconnectDialogReconnectAttempts = new TextField( + "Reconnect attempts"); + reconnectDialogReconnectAttempts.setConverter(Integer.class); + reconnectDialogReconnectAttempts + .setConvertedValue(getState().reconnectDialog.reconnectAttempts); + reconnectDialogReconnectAttempts + .addValueChangeListener(new ValueChangeListener() { + @Override + public void valueChange(ValueChangeEvent event) { + getState().reconnectDialog.reconnectAttempts = (Integer) reconnectDialogReconnectAttempts + .getConvertedValue(); + } + }); + final TextField reconnectDialogReconnectInterval = new TextField( + "Reconnect interval (ms)"); + reconnectDialogReconnectInterval.setConverter(Integer.class); + reconnectDialogReconnectInterval + .setConvertedValue(getState().reconnectDialog.reconnectInterval); + reconnectDialogReconnectInterval + .addValueChangeListener(new ValueChangeListener() { + @Override + public void valueChange(ValueChangeEvent event) { + getState().reconnectDialog.reconnectInterval = (Integer) reconnectDialogReconnectInterval + .getConvertedValue(); + } + }); + + VerticalLayout vl = new VerticalLayout(); + vl.setMargin(true); + vl.setSpacing(true); + p.setContent(vl); + vl.addComponents(reconnectDialogMessage, reconnectDialogGaveUpMessage, + reconnectDialogReconnectAttempts, + reconnectDialogReconnectInterval); + return p; } private Component createTemporaryResponseCodeSetters(String type, -- cgit v1.2.3