Java tutorial
/*! * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software * Foundation. * * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * Copyright (c) 2017 Pentaho Corporation.. All rights reserved. */ package org.pentaho.mantle.client.commands; import com.google.gwt.thirdparty.guava.common.annotations.VisibleForTesting; import com.google.gwt.user.client.Cookies; import com.google.gwt.user.client.Timer; import org.pentaho.gwt.widgets.client.dialogs.SessionExpiredDialog; /** * Shows a session expired dialog in a top frame. * Won't work on the screens missing the mantle application. */ public class SessionExpiredCommand extends AbstractCommand { private static final String ZERO = "0"; //10 seconds by default private Integer pollingInterval = 10000; private static final String SESSION_EXPIRY = "session-expiry"; private static final String SERVER_TIME = "server-time"; private static final String CLIENT_TIME_OFFSET = "client-time-offset"; private static Timer timer; @Override protected void performOperation() { this.performOperation(true); } @Override protected void performOperation(boolean feedback) { //Reset and reinitialize timer once per page load if (timer != null) { timer.cancel(); timer = null; } //Calculate and set client/server time desynchronization offset once per page load setClientTimeOffset(); performCheck(); } /** * A timer loop */ private void performCheck() { final int nextCheckShift = getNextCheckShift(); if (nextCheckShift < 0) { new SessionExpiredDialog().center(); } else { timer = new Timer() { @Override public void run() { performCheck(); } }; timer.schedule(nextCheckShift); } } public Integer getPollingInterval() { return pollingInterval; } public void setPollingInterval(final Integer pollingInterval) { this.pollingInterval = pollingInterval; } /** * If the session is expired returns a negative value. * If the session is not expired returns a time left before expiration. * If the cookie is not set returns a default polling interval. * * @return time shift for the next check */ @VisibleForTesting protected int getNextCheckShift() { final String sessionExpiry = getCookie(SESSION_EXPIRY); final String clientTimeOffset = getCookie(CLIENT_TIME_OFFSET); //A cookie is not set if (sessionExpiry != null && clientTimeOffset != null) { try { final long timeLeft = Long.parseLong(sessionExpiry) - getClientTime() + Long.parseLong(clientTimeOffset); if (timeLeft <= 0) { //Session is expired return -1; //do not overflow } else if (timeLeft < Integer.MAX_VALUE) { //do not overflow //Not expired return (int) (timeLeft); } } catch (NumberFormatException e) { //wrong value in a cookie } } //No cookie - use a default interval return getPollingInterval(); } @VisibleForTesting protected long getClientTime() { return System.currentTimeMillis(); } /** * Don't be fooled with a System.currentTimeMillis() - in GWT it's a client side time. To eliminate a possible client * clock desynchronization effect we need to calculate an offset between client and server time. * Also there always will be a small positive offset equal to a time between the page load nad servlet invocation. * <p> * In case of any unpredicted situation the offset is set to 0. */ @VisibleForTesting protected void setClientTimeOffset() { final String serverTime = getCookie(SERVER_TIME); if (serverTime != null) { try { //Could be negative final long timeOffset = getClientTime() - Long.parseLong(serverTime); setCookie(CLIENT_TIME_OFFSET, String.valueOf(timeOffset)); } catch (NumberFormatException e) { setCookie(CLIENT_TIME_OFFSET, ZERO); } } else { setCookie(CLIENT_TIME_OFFSET, ZERO); } } @VisibleForTesting protected String getCookie(final String name) { return Cookies.getCookie(name); } @VisibleForTesting protected void setCookie(final String name, final String value) { Cookies.setCookie(name, value); } }