IDEMPIERE-5049 Zk Session and Desktop object not destroy immediately after logout (#994)
- Remove 5 second delay for remove of desktop after logout - added X-PING custom http header for "ping" to index.zul - added watch for disconnected desktop
This commit is contained in:
parent
07202f7b61
commit
06698688ef
|
@ -301,6 +301,14 @@ public class AtmosphereServerPush implements ServerPush {
|
|||
startClientPush(desktop.get());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return true if it is holding an atmosphere resource
|
||||
*/
|
||||
public boolean hasAtmosphereResource() {
|
||||
return this.resource.get() != null;
|
||||
}
|
||||
|
||||
private class Schedule<T extends Event> {
|
||||
private EventListener<T> task;
|
||||
private T event;
|
||||
|
|
|
@ -44,6 +44,7 @@ import org.adempiere.webui.session.SessionManager;
|
|||
import org.adempiere.webui.theme.ITheme;
|
||||
import org.adempiere.webui.theme.ThemeManager;
|
||||
import org.adempiere.webui.util.BrowserToken;
|
||||
import org.adempiere.webui.util.DesktopWatchDog;
|
||||
import org.adempiere.webui.util.UserPreference;
|
||||
import org.compiere.Adempiere;
|
||||
import org.compiere.model.MRole;
|
||||
|
@ -140,12 +141,20 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
|||
|
||||
public void onCreate()
|
||||
{
|
||||
this.getPage().setTitle(ThemeManager.getBrowserTitle());
|
||||
String ping = Executions.getCurrent().getHeader("X-PING");
|
||||
if (!Util.isEmpty(ping, true))
|
||||
{
|
||||
cleanupForPing();
|
||||
return;
|
||||
}
|
||||
|
||||
this.getPage().setTitle(ThemeManager.getBrowserTitle());
|
||||
|
||||
Executions.getCurrent().getDesktop().enableServerPush(true);
|
||||
DesktopWatchDog.addDesktop(Executions.getCurrent().getDesktop());
|
||||
|
||||
SessionManager.setSessionApplication(this);
|
||||
Session session = Executions.getCurrent().getDesktop().getSession();
|
||||
final Session session = Executions.getCurrent().getDesktop().getSession();
|
||||
|
||||
Properties ctx = Env.getCtx();
|
||||
langSession = Env.getContext(ctx, Env.LANGUAGE);
|
||||
|
@ -171,9 +180,28 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
|||
Executions.getCurrent().getDesktop().addListener(new TokenCommand());
|
||||
Executions.getCurrent().getDesktop().addListener(new ZoomCommand());
|
||||
|
||||
eventThreadEnabled = Executions.getCurrent().getDesktop().getWebApp().getConfiguration().isEventThreadEnabled();
|
||||
eventThreadEnabled = Executions.getCurrent().getDesktop().getWebApp().getConfiguration().isEventThreadEnabled();
|
||||
}
|
||||
|
||||
private void cleanupForPing() {
|
||||
final Desktop desktop = Executions.getCurrent().getDesktop();
|
||||
final WebApp wapp = desktop.getWebApp();
|
||||
final DesktopCache desktopCache = ((WebAppCtrl) wapp).getDesktopCache(desktop.getSession());
|
||||
final Session session = desktop.getSession();
|
||||
|
||||
//clear context, invalidate session
|
||||
Env.getCtx().clear();
|
||||
destroySession(session);
|
||||
desktop.setAttribute(DESKTOP_SESSION_INVALIDATED_ATTR, Boolean.TRUE);
|
||||
Adempiere.getThreadPoolExecutor().schedule(() -> {
|
||||
try {
|
||||
desktopCache.removeDesktop(desktop);
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}, 1, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
public void onOk()
|
||||
{
|
||||
}
|
||||
|
@ -386,14 +414,6 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
|||
|
||||
final WebApp wapp = desktop.getWebApp();
|
||||
final DesktopCache desktopCache = ((WebAppCtrl) wapp).getDesktopCache(desktop.getSession());
|
||||
Adempiere.getThreadPoolExecutor().schedule(() -> {
|
||||
try {
|
||||
desktopCache.removeDesktop(desktop);
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}, 5, TimeUnit.SECONDS);
|
||||
|
||||
final Session session = logout0();
|
||||
|
||||
//clear context, invalidate session
|
||||
|
@ -402,7 +422,14 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
|||
desktop.setAttribute(DESKTOP_SESSION_INVALIDATED_ATTR, Boolean.TRUE);
|
||||
|
||||
//redirect to login page
|
||||
Executions.sendRedirect("index.zul");
|
||||
Executions.sendRedirect("index.zul");
|
||||
|
||||
try {
|
||||
desktopCache.removeDesktop(desktop);
|
||||
DesktopWatchDog.removeDesktop(desktop);
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void destroySession(final Session session) {
|
||||
|
@ -414,10 +441,14 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
|
|||
session.invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform logout after user close a browser tab without first logging out
|
||||
*/
|
||||
public void logoutAfterTabDestroyed(){
|
||||
Desktop desktop = Executions.getCurrent().getDesktop();
|
||||
if (desktop.isServerPushEnabled())
|
||||
desktop.enableServerPush(false);
|
||||
DesktopWatchDog.removeDesktop(desktop);
|
||||
|
||||
Session session = logout0();
|
||||
|
||||
|
|
|
@ -63,23 +63,6 @@ public class WLogin extends AbstractUIPart
|
|||
loginWindow = (LoginWindow) loginPage.getFellow("loginWindow");
|
||||
loginWindow.init(app);
|
||||
|
||||
/* IDEMPIERE-1022 - deprecated message
|
||||
if (!AEnv.isBrowserSupported())
|
||||
{
|
||||
//TODO: localization
|
||||
String msg = "You might experience slow performance and user interface anomalies using your current browser to access the application. We recommend the use of Firefox, Google Chrome or Apple Safari.";
|
||||
browserWarningWindow = new Window();
|
||||
Div div = new Div();
|
||||
div.setStyle("font-size: 9pt");
|
||||
div.appendChild(new Text(msg));
|
||||
browserWarningWindow.appendChild(div);
|
||||
browserWarningWindow.setPosition("top,right");
|
||||
ZKUpdateUtil.setWidth(browserWarningWindow, "550px");
|
||||
browserWarningWindow.setPage(page);
|
||||
browserWarningWindow.doOverlapped();
|
||||
}
|
||||
*/
|
||||
|
||||
boolean mobile = false;
|
||||
if (Executions.getCurrent().getBrowser("mobile") !=null) {
|
||||
mobile = true;
|
||||
|
|
|
@ -84,7 +84,11 @@ public class SessionManager
|
|||
if (app != null)
|
||||
app.logout();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Perform logout after user close a browser tab without first logging out.
|
||||
* Usually this is invoke from {@link SessionContextListener} and developer shouldn't call this directly.
|
||||
*/
|
||||
public static void logoutSessionAfterBrowserDestroyed()
|
||||
{
|
||||
IWebClient app = getSessionApplication();
|
||||
|
@ -92,6 +96,10 @@ public class SessionManager
|
|||
app.logoutAfterTabDestroyed();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param user
|
||||
*/
|
||||
public static void changeRole(MUser user){
|
||||
IWebClient app = getSessionApplication();
|
||||
if (app != null)
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
/***********************************************************************
|
||||
* This file is part of iDempiere ERP Open Source *
|
||||
* http://www.idempiere.org *
|
||||
* *
|
||||
* Copyright (C) Contributors *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License *
|
||||
* as published by the Free Software Foundation; either version 2 *
|
||||
* of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* 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 General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
|
||||
* MA 02110-1301, USA. *
|
||||
* *
|
||||
* Contributors: *
|
||||
* - hengsin *
|
||||
**********************************************************************/
|
||||
package org.adempiere.webui.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.compiere.Adempiere;
|
||||
import org.zkoss.zk.ui.Desktop;
|
||||
import org.zkoss.zk.ui.Session;
|
||||
import org.zkoss.zk.ui.WebApp;
|
||||
import org.zkoss.zk.ui.sys.DesktopCache;
|
||||
import org.zkoss.zk.ui.sys.DesktopCtrl;
|
||||
import org.zkoss.zk.ui.sys.ServerPush;
|
||||
import org.zkoss.zk.ui.sys.SessionCtrl;
|
||||
import org.zkoss.zk.ui.sys.WebAppCtrl;
|
||||
|
||||
import fi.jawsy.jawwa.zk.atmosphere.AtmosphereServerPush;
|
||||
|
||||
/**
|
||||
* watch for disconnected desktop and destroy it
|
||||
* @author hengsin
|
||||
*
|
||||
*/
|
||||
public class DesktopWatchDog {
|
||||
|
||||
private final static DesktopWatchDog INSTANCE = new DesktopWatchDog();
|
||||
|
||||
private final ConcurrentLinkedDeque<DesktopEntry> desktops = new ConcurrentLinkedDeque<DesktopWatchDog.DesktopEntry>();
|
||||
|
||||
private DesktopWatchDog() {
|
||||
Adempiere.getThreadPoolExecutor().scheduleWithFixedDelay(() -> {
|
||||
doMonitoring();
|
||||
}, 60, 40, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private void doMonitoring() {
|
||||
List<Session> toDestroy = new ArrayList<Session>();
|
||||
List<Session> actives = new ArrayList<Session>();
|
||||
Iterator<DesktopEntry> iterator = desktops.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
DesktopEntry entry = iterator.next();
|
||||
if (!entry.desktop.isAlive()) {
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
if (entry.desktop.isServerPushEnabled() == false) {
|
||||
entry.noAtmosphereResourceCount++;
|
||||
}
|
||||
ServerPush spush = ((DesktopCtrl)entry.desktop).getServerPush();
|
||||
if (spush == null) {
|
||||
entry.noAtmosphereResourceCount++;
|
||||
} else if (spush instanceof AtmosphereServerPush) {
|
||||
AtmosphereServerPush asp = (AtmosphereServerPush) spush;
|
||||
if (!asp.hasAtmosphereResource())
|
||||
entry.noAtmosphereResourceCount++;
|
||||
else
|
||||
entry.noAtmosphereResourceCount=0;
|
||||
}
|
||||
if (entry.noAtmosphereResourceCount >= 3) {
|
||||
iterator.remove();
|
||||
try {
|
||||
final WebApp wapp = entry.desktop.getWebApp();
|
||||
final Session session = entry.desktop.getSession();
|
||||
final DesktopCache desktopCache = ((WebAppCtrl) wapp).getDesktopCache(session);
|
||||
desktopCache.removeDesktop(entry.desktop);
|
||||
if (!actives.contains(session) && !toDestroy.contains(session))
|
||||
toDestroy.add(session);
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
final Session session = entry.desktop.getSession();
|
||||
if (!actives.contains(session))
|
||||
actives.add(session);
|
||||
int index = toDestroy.indexOf(session);
|
||||
if (index >= 0)
|
||||
toDestroy.remove(index);
|
||||
}
|
||||
}
|
||||
if (!toDestroy.isEmpty()) {
|
||||
for(Session session : toDestroy) {
|
||||
try {
|
||||
((SessionCtrl)session).onDestroyed();
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
session.invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final static class DesktopEntry {
|
||||
Desktop desktop;
|
||||
int noAtmosphereResourceCount = 0;
|
||||
|
||||
private DesktopEntry(Desktop desktop) {
|
||||
this.desktop = desktop;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* add desktop to watch list
|
||||
* @param desktop
|
||||
*/
|
||||
public static void addDesktop(Desktop desktop) {
|
||||
INSTANCE.desktops.add(new DesktopEntry(desktop));
|
||||
}
|
||||
|
||||
/**
|
||||
* remove desktop from watch list
|
||||
* @param desktop
|
||||
*/
|
||||
public static void removeDesktop(Desktop desktop) {
|
||||
Iterator<DesktopEntry> iterator = INSTANCE.desktops.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
DesktopEntry entry = iterator.next();
|
||||
if (entry.desktop == desktop) {
|
||||
iterator.remove();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue