/******************************************************************************
* Copyright (C) 2008 Low Heng Sin *
* Copyright (C) 2008 Idalica Corporation *
* This program is free software; you can redistribute it and/or modify it *
* under the terms version 2 of the GNU General Public License as published *
* by the Free Software Foundation. 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., *
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
*****************************************************************************/
package org.adempiere.webui.dashboard;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
import java.util.logging.Level;
import org.adempiere.webui.AdempiereWebUI;
import org.adempiere.webui.desktop.IDesktop;
import org.adempiere.webui.session.ServerContext;
import org.adempiere.webui.session.SessionContextListener;
import org.adempiere.webui.util.ServerPushTemplate;
import org.compiere.model.MSysConfig;
import org.compiere.util.CLogger;
import org.zkoss.util.Locales;
import org.zkoss.zk.ui.Desktop;
import org.zkoss.zk.ui.DesktopUnavailableException;
/**
*
* @author hengsin
* @author Cristina Ghita, www.arhipac.ro BF [2871741] Error at start
* @see https://sourceforge.net/tracker/?func=detail&atid=955896&aid=2871741&group_id=176962
*/
public class DashboardRunnable implements Runnable, Serializable
{
private static final long serialVersionUID = 5995227773511788894L;
private Desktop desktop;
private boolean stop = false;
private List<DashboardPanel> dashboardPanels;
private IDesktop appDesktop;
private Locale locale;
private static final CLogger logger = CLogger.getCLogger(DashboardRunnable.class);
private final static String ZK_DASHBOARD_REFRESH_INTERVAL = "ZK_DASHBOARD_REFRESH_INTERVAL";
/**
*
* @param desktop zk desktop interface
* @param appDesktop adempiere desktop interface
*/
public DashboardRunnable(Desktop desktop, IDesktop appDesktop) {
this.desktop = desktop;
this.appDesktop = appDesktop;
dashboardPanels = new ArrayList<DashboardPanel>();
locale = Locales.getCurrent();
}
public DashboardRunnable(DashboardRunnable tmp, Desktop desktop,
IDesktop appDesktop) {
this(desktop, appDesktop);
this.dashboardPanels = tmp.dashboardPanels;
}
public void run()
{
// default Update every one minutes
int interval = MSysConfig.getIntValue(ZK_DASHBOARD_REFRESH_INTERVAL, 60000);
int cumulativeFailure = 0;
while(!stop) {
try {
Thread.sleep(interval);
} catch (InterruptedException e1) {
if (stop) break;
}
if (desktop.isAlive()) {
Locales.setThreadLocal(locale);
try {
refreshDashboard();
cumulativeFailure = 0;
} catch (DesktopUnavailableException de) {
cumulativeFailure++;
} catch (Exception e) {
logger.log(Level.INFO, e.getLocalizedMessage(), (e.getCause() != null ? e.getCause() : e));
cumulativeFailure++;
}
if (cumulativeFailure > 3)
break;
} else {
logger.log(Level.INFO, "Desktop destroy, will kill session.");
killSession();
break;
}
}
}
private void killSession() {
if (desktop.getSession() != null && desktop.getSession().getNativeSession() != null)
{
//differentiate between real destroy and refresh
try
{
Thread.sleep(90000);
}
catch (InterruptedException e)
{
try
{
desktop.getSession().getAttributes().clear();
desktop.getSession().invalidate();
}
catch (Exception e1) {}
return;
}
try
{
Object sessionObj = desktop.getSession().getAttribute(AdempiereWebUI.ZK_DESKTOP_SESSION_KEY);
if (sessionObj != null && sessionObj instanceof Desktop)
{
Desktop sessionDesktop = (Desktop) sessionObj;
//don't destroy session if it have been attached to another desktop ( refresh will do that )
if (sessionDesktop == desktop)
{
desktop.getSession().getAttributes().clear();
desktop.getSession().invalidate();
}
}
else
{
desktop.getSession().getAttributes().clear();
desktop.getSession().invalidate();
}
}
catch (Exception e1) {}
}
}
/**
* Refresh dashboard content
*/
public void refreshDashboard()
{
ServerPushTemplate template = new ServerPushTemplate(desktop);
for(int i = 0; i < dashboardPanels.size(); i++)
{
//make sure context is correct
Properties ctx = (Properties)template.getDesktop().getSession().getAttribute(SessionContextListener.SESSION_CTX);
if (ctx != null)
{
ServerContext serverContext = ServerContext.getCurrentInstance();
if (serverContext == null) {
serverContext = ServerContext.newInstance();
serverContext.putAll(ctx);
} else {
String id = ctx.getProperty(SessionContextListener.SERVLET_SESSION_ID);
if (id == null || !id.equals(serverContext.getProperty(SessionContextListener.SERVLET_SESSION_ID))) {
serverContext.clear();
serverContext.putAll(ctx);
}
}
}
dashboardPanels.get(i).refresh(template);
}
//make sure context is correct
Properties ctx = (Properties)template.getDesktop().getSession().getAttribute(SessionContextListener.SESSION_CTX);
if (ctx != null)
{
ServerContext serverContext = ServerContext.getCurrentInstance();
if (serverContext == null) {
serverContext = ServerContext.newInstance();
serverContext.putAll(ctx);
} else {
String id = ctx.getProperty(SessionContextListener.SERVLET_SESSION_ID);
if (id == null || !id.equals(serverContext.getProperty(SessionContextListener.SERVLET_SESSION_ID))) {
serverContext.clear();
serverContext.putAll(ctx);
}
}
}
appDesktop.onServerPush(template);
}
public void stop() {
stop = true;
}
/**
* Add DashboardPanel to the auto refresh list
* @param dashboardPanel
*/
public void add(DashboardPanel dashboardPanel) {
dashboardPanels.add(dashboardPanel);
}
}