import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.ApplicationConfiguration.ErrorMessage;
+import com.vaadin.client.ApplicationConnection.ApplicationStoppedEvent;
import com.vaadin.client.ResourceLoader.ResourceLoadEvent;
import com.vaadin.client.ResourceLoader.ResourceLoadListener;
import com.vaadin.client.communication.HasJavaScriptConnectorHelper;
+import com.vaadin.client.communication.Heartbeat;
import com.vaadin.client.communication.JavaScriptMethodInvocation;
import com.vaadin.client.communication.JsonDecoder;
import com.vaadin.client.communication.JsonEncoder;
private VLoadingIndicator loadingIndicator;
+ private Heartbeat heartbeat = GWT.create(Heartbeat.class);
+
public static class MultiStepDuration extends Duration {
private int previousStep = elapsedMillis();
getLoadingIndicator().show();
- scheduleHeartbeat();
+ heartbeat.init(this);
Window.addWindowClosingHandler(new ClosingHandler() {
@Override
* interval elapses if the interval is a positive number. Otherwise, does
* nothing.
*
- * @see #sendHeartbeat()
- * @see ApplicationConfiguration#getHeartbeatInterval()
+ * @deprecated as of 7.2, use {@link Heartbeat#schedule()} instead
*/
+ @Deprecated
protected void scheduleHeartbeat() {
- final int interval = getConfiguration().getHeartbeatInterval();
- if (interval > 0) {
- VConsole.log("Scheduling heartbeat in " + interval + " seconds");
- new Timer() {
- @Override
- public void run() {
- sendHeartbeat();
- }
- }.schedule(interval * 1000);
- }
+ heartbeat.schedule();
}
/**
* Heartbeat requests are used to inform the server that the client-side is
* still alive. If the client page is closed or the connection lost, the
* server will eventually close the inactive UI.
- * <p>
- * <b>TODO</b>: Improved error handling, like in doUidlRequest().
*
- * @see #scheduleHeartbeat()
+ * @deprecated as of 7.2, use {@link Heartbeat#send()} instead
*/
+ @Deprecated
protected void sendHeartbeat() {
- final String uri = addGetParameters(
- translateVaadinUri(ApplicationConstants.APP_PROTOCOL_PREFIX
- + ApplicationConstants.HEARTBEAT_PATH + '/'),
- UIConstants.UI_ID_PARAMETER + "="
- + getConfiguration().getUIId());
-
- final RequestBuilder rb = new RequestBuilder(RequestBuilder.POST, uri);
-
- final RequestCallback callback = new RequestCallback() {
-
- @Override
- public void onResponseReceived(Request request, Response response) {
- int status = response.getStatusCode();
- if (status == Response.SC_OK) {
- // TODO Permit retry in some error situations
- VConsole.log("Heartbeat response OK");
- scheduleHeartbeat();
- } else if (status == Response.SC_GONE) {
- showSessionExpiredError(null);
- } else {
- VConsole.error("Failed sending heartbeat to server. Error code: "
- + status);
- }
- }
-
- @Override
- public void onError(Request request, Throwable exception) {
- VConsole.error("Exception sending heartbeat: " + exception);
- }
- };
-
- rb.setCallback(callback);
-
- try {
- VConsole.log("Sending heartbeat request...");
- rb.send();
- } catch (RequestException re) {
- callback.onError(null, re);
- }
+ heartbeat.send();
}
/**
--- /dev/null
+/*
+ * Copyright 2000-2013 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 java.util.logging.Logger;
+
+import com.google.gwt.http.client.Request;
+import com.google.gwt.http.client.RequestBuilder;
+import com.google.gwt.http.client.RequestCallback;
+import com.google.gwt.http.client.RequestException;
+import com.google.gwt.http.client.Response;
+import com.google.gwt.user.client.Timer;
+import com.vaadin.client.ApplicationConnection;
+import com.vaadin.client.ApplicationConnection.ApplicationStoppedEvent;
+import com.vaadin.shared.ApplicationConstants;
+import com.vaadin.shared.ui.ui.UIConstants;
+
+/**
+ * Handles sending of heartbeats to the server and reacting to the response
+ *
+ * @since 7.2
+ * @author Vaadin Ltd
+ */
+public class Heartbeat {
+
+ private int interval = -1;
+ private Timer timer = new Timer() {
+ @Override
+ public void run() {
+ send();
+ }
+ };
+
+ private ApplicationConnection connection;
+
+ private static Logger getLogger() {
+ return Logger.getLogger(Heartbeat.class.getName());
+ }
+
+ /**
+ * Initializes the heartbeat for the given application connection
+ *
+ * @param applicationConnection
+ * the connection
+ */
+ public void init(ApplicationConnection applicationConnection) {
+ interval = applicationConnection.getConfiguration()
+ .getHeartbeatInterval();
+ setInterval(interval);
+ schedule();
+
+ applicationConnection.addHandler(
+ ApplicationConnection.ApplicationStoppedEvent.TYPE,
+ new ApplicationConnection.ApplicationStoppedHandler() {
+
+ @Override
+ public void onApplicationStopped(
+ ApplicationStoppedEvent event) {
+ setInterval(-1);
+ schedule();
+ }
+ });
+
+ }
+
+ /**
+ * Sends a heartbeat to the server
+ */
+ public void send() {
+ final String uri = ApplicationConnection.addGetParameters(
+ getConnection().translateVaadinUri(
+ ApplicationConstants.APP_PROTOCOL_PREFIX
+ + ApplicationConstants.HEARTBEAT_PATH + '/'),
+ UIConstants.UI_ID_PARAMETER + "="
+ + getConnection().getConfiguration().getUIId());
+
+ final RequestBuilder rb = new RequestBuilder(RequestBuilder.POST, uri);
+
+ final RequestCallback callback = new RequestCallback() {
+
+ @Override
+ public void onResponseReceived(Request request, Response response) {
+ int status = response.getStatusCode();
+ if (status == Response.SC_OK) {
+ // TODO Permit retry in some error situations
+ getLogger().fine("Heartbeat response OK");
+ schedule();
+ } else if (status == Response.SC_GONE) {
+ // FIXME This should really do something else like send an
+ // event
+ getConnection().showSessionExpiredError(null);
+ } else {
+ getLogger().warning(
+ "Failed sending heartbeat to server. Error code: "
+ + status);
+ }
+ }
+
+ @Override
+ public void onError(Request request, Throwable exception) {
+ getLogger().severe("Exception sending heartbeat: " + exception);
+ }
+ };
+
+ rb.setCallback(callback);
+
+ try {
+ getLogger().fine("Sending heartbeat request...");
+ rb.send();
+ } catch (RequestException re) {
+ callback.onError(null, re);
+ }
+
+ }
+
+ /**
+ * @return the interval at which heartbeat requests are sent
+ */
+ public int getInterval() {
+ return interval;
+ }
+
+ /**
+ * sets the interval at which heartbeat requests are sent
+ *
+ * @param interval
+ * the new interval
+ */
+ public void setInterval(int interval) {
+ this.interval = interval;
+ }
+
+ /**
+ * Updates the schedule of the heartbeat to match the set interval. A
+ * negative interval disables the heartbeat.
+ */
+ public void schedule() {
+ if (getInterval() > 0) {
+ getLogger()
+ .fine("Scheduling heartbeat in " + interval + " seconds");
+ timer.schedule(interval * 1000);
+ } else {
+ if (timer != null) {
+ getLogger().fine("Disabling heartbeat");
+ timer.cancel();
+ }
+ }
+
+ }
+
+ /**
+ * @return the application connection
+ */
+ protected ApplicationConnection getConnection() {
+ return connection;
+ }
+
+}