/*********************************************************************** * 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.Iterator; 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.WebAppCtrl; import fi.jawsy.jawwa.zk.atmosphere.AtmosphereServerPush; /** * watch for disconnected desktop and destroy it * @author hengsin * */ public class DesktopWatchDog { /** singleton instance **/ private final static DesktopWatchDog INSTANCE = new DesktopWatchDog(); /** Desktops being watched **/ private final ConcurrentLinkedDeque desktops = new ConcurrentLinkedDeque(); /** * default constructor */ private DesktopWatchDog() { Adempiere.getThreadPoolExecutor().scheduleWithFixedDelay(() -> { doMonitoring(); }, 60, 40, TimeUnit.SECONDS); } /** * Check each entries in {@link #desktops}. */ private void doMonitoring() { Iterator iterator = desktops.iterator(); while (iterator.hasNext()) { DesktopEntry entry = iterator.next(); //not active, remove from watch list 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 >= 5) { //no message from desktop for 5 consecutive run of doMonitoring. //remove desktop from DesktopCache. 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); } catch (Throwable t) { t.printStackTrace(); } } } } 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 iterator = INSTANCE.desktops.iterator(); while (iterator.hasNext()) { DesktopEntry entry = iterator.next(); if (entry.desktop == desktop) { iterator.remove(); break; } } } /** * Remove other desktops that share the same session with the pass in desktop parameter * @param desktop */ public static void removeOtherDesktopsInSession(Desktop desktop) { Iterator iterator = INSTANCE.desktops.iterator(); while (iterator.hasNext()) { DesktopEntry entry = iterator.next(); if (entry.desktop == desktop) continue; if (entry.desktop.getSession() != desktop.getSession()) continue; iterator.remove(); try { final WebApp wapp = desktop.getWebApp(); final Session session = desktop.getSession(); final DesktopCache desktopCache = ((WebAppCtrl) wapp).getDesktopCache(session); desktopCache.removeDesktop(entry.desktop); } catch (Throwable t) { t.printStackTrace(); } } } }