IDEMPIERE-348 Zk Performance: remove use of polling background thread for update of dashboard. Use server side event to update calendar and recent items dashboard widget. Activities dashboard widget is still using polling but update of home tab label for activities count is now event driven.

This commit is contained in:
Heng Sin Low 2013-01-17 01:14:16 +08:00
parent 7e24ff5ae5
commit 9d312ff605
12 changed files with 454 additions and 93 deletions

View File

@ -16,15 +16,22 @@ package org.compiere.model;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Properties; import java.util.Properties;
import org.adempiere.base.Service;
import org.adempiere.base.event.EventManager;
import org.adempiere.exceptions.AdempiereException; import org.adempiere.exceptions.AdempiereException;
import org.compiere.util.CCache; import org.compiere.util.CCache;
import org.compiere.util.CLogger; import org.compiere.util.CLogger;
import org.compiere.util.DB; import org.compiere.util.DB;
import org.compiere.util.Env; import org.compiere.util.Env;
import org.idempiere.distributed.IMessageService;
import org.idempiere.distributed.ITopic;
import org.osgi.service.event.Event;
/** /**
* Recent Item model * Recent Item model
@ -33,6 +40,8 @@ import org.compiere.util.Env;
*/ */
public class MRecentItem extends X_AD_RecentItem public class MRecentItem extends X_AD_RecentItem
{ {
public static final String ON_RECENT_ITEM_CHANGED_TOPIC = "onRecentItemChanged";
/** /**
* *
*/ */
@ -166,6 +175,24 @@ public class MRecentItem extends X_AD_RecentItem
ri.setAD_Window_ID(AD_Window_ID); ri.setAD_Window_ID(AD_Window_ID);
ri.setAD_Tab_ID(AD_Tab_ID); ri.setAD_Tab_ID(AD_Tab_ID);
ri.saveEx(); ri.saveEx();
publishChangedEvent(AD_User_ID);
}
private static void publishChangedEvent(int AD_User_ID) {
IMessageService service = Service.locator().locate(IMessageService.class).getService();
if (service != null) {
ITopic<Integer> topic = service.getTopic(ON_RECENT_ITEM_CHANGED_TOPIC);
topic.publish(AD_User_ID);
} else {
postOnChangedEvent(AD_User_ID);
}
}
public static void postOnChangedEvent(int AD_User_ID) {
Map<String, Integer> properties = new HashMap<String, Integer>();
properties.put("AD_User_ID", AD_User_ID);
Event event = new Event(ON_RECENT_ITEM_CHANGED_TOPIC, properties);
EventManager.getInstance().postEvent(event);
} }
/* /*
@ -178,6 +205,7 @@ public class MRecentItem extends X_AD_RecentItem
if (ri != null) { if (ri != null) {
DB.executeUpdateEx("UPDATE AD_RecentItem SET Updated=SYSDATE WHERE AD_RecentItem_ID=?", new Object[] {ri.getAD_RecentItem_ID()}, null); DB.executeUpdateEx("UPDATE AD_RecentItem SET Updated=SYSDATE WHERE AD_RecentItem_ID=?", new Object[] {ri.getAD_RecentItem_ID()}, null);
deleteExtraRecentItems(ctx, AD_User_ID); deleteExtraRecentItems(ctx, AD_User_ID);
publishChangedEvent(AD_User_ID);
} }
} }

View File

@ -19,9 +19,11 @@ package org.compiere.util;
import java.sql.Connection; import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Savepoint; import java.sql.Savepoint;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -85,6 +87,8 @@ public class Trx
private static Trx.TrxMonitor s_monitor = new Trx.TrxMonitor(); private static Trx.TrxMonitor s_monitor = new Trx.TrxMonitor();
private List<TrxEventListener> listeners = new ArrayList<TrxEventListener>();
public static void startTrxMonitor() public static void startTrxMonitor()
{ {
Adempiere.getThreadPoolExecutor().scheduleWithFixedDelay(s_monitor, 5, 5, TimeUnit.MINUTES); Adempiere.getThreadPoolExecutor().scheduleWithFixedDelay(s_monitor, 5, 5, TimeUnit.MINUTES);
@ -278,6 +282,7 @@ public class Trx
m_connection.rollback(); m_connection.rollback();
log.log(isLocalTrx(m_trxName) ? Level.FINE : Level.INFO, "**** " + m_trxName); log.log(isLocalTrx(m_trxName) ? Level.FINE : Level.INFO, "**** " + m_trxName);
m_active = false; m_active = false;
fireAfterRollbackEvent(true);
return true; return true;
} }
} }
@ -287,13 +292,22 @@ public class Trx
if (throwException) if (throwException)
{ {
m_active = false; m_active = false;
fireAfterRollbackEvent(false);
throw e; throw e;
} }
} }
m_active = false; m_active = false;
fireAfterRollbackEvent(false);
return false; return false;
} // rollback } // rollback
private void fireAfterRollbackEvent(boolean success) {
TrxEventListener[] copies = listeners.toArray(new TrxEventListener[0]);
for(TrxEventListener l : copies) {
l.afterRollback(this, success);
}
}
/** /**
* Rollback * Rollback
* @return true if success, false if failed or transaction already rollback * @return true if success, false if failed or transaction already rollback
@ -347,6 +361,7 @@ public class Trx
m_connection.commit(); m_connection.commit();
log.info ("**** " + m_trxName); log.info ("**** " + m_trxName);
m_active = false; m_active = false;
fireAfterCommitEvent(true);
return true; return true;
} }
} }
@ -356,13 +371,22 @@ public class Trx
if (throwException) if (throwException)
{ {
m_active = false; m_active = false;
fireAfterCommitEvent(false);
throw e; throw e;
} }
} }
m_active = false; m_active = false;
fireAfterCommitEvent(false);
return false; return false;
} // commit } // commit
private void fireAfterCommitEvent(boolean success) {
TrxEventListener[] copies = listeners.toArray(new TrxEventListener[0]);
for(TrxEventListener l : copies) {
l.afterCommit(this, success);
}
}
/** /**
* Commit * Commit
* @return true if success * @return true if success
@ -417,10 +441,18 @@ public class Trx
} }
m_connection = null; m_connection = null;
m_active = false; m_active = false;
fireAfterCloseEvent();
log.config(m_trxName); log.config(m_trxName);
return true; return true;
} // close } // close
private void fireAfterCloseEvent() {
TrxEventListener[] copies = listeners.toArray(new TrxEventListener[0]);
for(TrxEventListener l : copies) {
l.afterClose(this);
}
}
/** /**
* *
* @param name * @param name
@ -589,6 +621,18 @@ public class Trx
m_timeout = timeout; m_timeout = timeout;
} }
/**
*
* @param listener
*/
public void addTrxEventListener(TrxEventListener listener) {
listeners.add(listener);
}
public boolean removeTrxEventListener(TrxEventListener listener) {
return listeners.remove(listener);
}
static class TrxMonitor implements Runnable static class TrxMonitor implements Runnable
{ {

View File

@ -0,0 +1,24 @@
/******************************************************************************
* Copyright (C) 2013 Heng Sin Low *
* Copyright (C) 2013 Trek Global *
* 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.compiere.util;
/**
* @author hengsin
*
*/
public interface TrxEventListener {
public void afterCommit(Trx trx, boolean success);
public void afterRollback(Trx trx, boolean success);
public void afterClose(Trx trx);
}

View File

@ -30,6 +30,7 @@ import java.util.TimeZone;
import org.adempiere.webui.component.Window; import org.adempiere.webui.component.Window;
import org.adempiere.webui.session.SessionManager; import org.adempiere.webui.session.SessionManager;
import org.compiere.model.X_R_RequestType; import org.compiere.model.X_R_RequestType;
import org.compiere.util.Env;
import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart; import org.jfree.chart.JFreeChart;
import org.jfree.chart.encoders.EncoderUtil; import org.jfree.chart.encoders.EncoderUtil;
@ -116,7 +117,7 @@ public class CalendarWindow extends Window implements EventListener<Event> {
lbxRequestTypes.addEventListener(Events.ON_SELECT, this); lbxRequestTypes.addEventListener(Events.ON_SELECT, this);
lbxRequestTypes.appendItem("(Show All)", "0"); lbxRequestTypes.appendItem("(Show All)", "0");
ArrayList<X_R_RequestType> types = DPCalendar.getRequestTypes(); ArrayList<X_R_RequestType> types = DPCalendar.getRequestTypes(Env.getCtx());
for(X_R_RequestType type : types) for(X_R_RequestType type : types)
lbxRequestTypes.appendItem(type.getName(), type.getR_RequestType_ID() + ""); lbxRequestTypes.appendItem(type.getName(), type.getR_RequestType_ID() + "");
lbxRequestTypes.setSelectedIndex(0); lbxRequestTypes.setSelectedIndex(0);
@ -215,7 +216,7 @@ public class CalendarWindow extends Window implements EventListener<Event> {
int R_RequestType_ID = Integer.parseInt(li.getValue().toString()); int R_RequestType_ID = Integer.parseInt(li.getValue().toString());
scm.clear(); scm.clear();
ArrayList<ADCalendarEvent> events = DPCalendar.getEvents(R_RequestType_ID); ArrayList<ADCalendarEvent> events = DPCalendar.getEvents(R_RequestType_ID, Env.getCtx());
for (ADCalendarEvent event : events) for (ADCalendarEvent event : events)
scm.add(event); scm.add(event);
calendars.setModel(scm); calendars.setModel(scm);
@ -341,7 +342,7 @@ public class CalendarWindow extends Window implements EventListener<Event> {
lbxRequestTypes.removeItemAt(i); lbxRequestTypes.removeItemAt(i);
lbxRequestTypes.appendItem("(Show All)", "0"); lbxRequestTypes.appendItem("(Show All)", "0");
ArrayList<X_R_RequestType> types = DPCalendar.getRequestTypes(); ArrayList<X_R_RequestType> types = DPCalendar.getRequestTypes(Env.getCtx());
for(X_R_RequestType requestType : types) for(X_R_RequestType requestType : types)
{ {
Listitem item = lbxRequestTypes.appendItem(requestType.getName(), requestType.getR_RequestType_ID() + ""); Listitem item = lbxRequestTypes.appendItem(requestType.getName(), requestType.getR_RequestType_ID() + "");
@ -352,7 +353,7 @@ public class CalendarWindow extends Window implements EventListener<Event> {
lbxRequestTypes.setSelectedIndex(0); lbxRequestTypes.setSelectedIndex(0);
scm.clear(); scm.clear();
ArrayList<ADCalendarEvent> events = DPCalendar.getEvents(R_RequestType_ID); ArrayList<ADCalendarEvent> events = DPCalendar.getEvents(R_RequestType_ID, Env.getCtx());
for (ADCalendarEvent event : events) for (ADCalendarEvent event : events)
scm.add(event); scm.add(event);
calendars.setModel(scm); calendars.setModel(scm);

View File

@ -15,9 +15,12 @@ package org.adempiere.webui.dashboard;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level; import java.util.logging.Level;
import org.adempiere.webui.component.Button; import org.adempiere.webui.component.Button;
import org.adempiere.webui.desktop.IDesktop;
import org.adempiere.webui.session.SessionManager; import org.adempiere.webui.session.SessionManager;
import org.adempiere.webui.util.ServerPushTemplate; import org.adempiere.webui.util.ServerPushTemplate;
import org.compiere.model.MRole; import org.compiere.model.MRole;
@ -29,6 +32,8 @@ import org.compiere.util.Util;
import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event; import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener; import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.EventQueue;
import org.zkoss.zk.ui.event.EventQueues;
import org.zkoss.zk.ui.event.Events; import org.zkoss.zk.ui.event.Events;
import org.zkoss.zul.Box; import org.zkoss.zul.Box;
import org.zkoss.zul.Vbox; import org.zkoss.zul.Vbox;
@ -221,27 +226,41 @@ public class DPActivities extends DashboardPanel implements EventListener<Event>
@Override @Override
public void refresh(ServerPushTemplate template) public void refresh(ServerPushTemplate template)
{ {
noOfNotice = getNoticeCount(); int notice = getNoticeCount();
noOfRequest = getRequestCount(); int request = getRequestCount();
noOfWorkflow = getWorkflowCount(); int workflow = getWorkflowCount();
noOfUnprocessed = getUnprocessedCount(); int unprocessed = getUnprocessedCount();
if (noOfNotice != notice || noOfRequest != request
template.executeAsync(this); || noOfWorkflow != workflow || noOfUnprocessed != unprocessed )
{
noOfNotice = notice;
noOfRequest = request;
noOfWorkflow = workflow;
noOfUnprocessed = unprocessed;
template.executeAsync(this);
}
} }
@Override @Override
public void updateUI() { public void updateUI() {
//don't update if not visible
Component c = this.getParent();
while (c != null) {
if (!c.isVisible())
return;
c = c.getParent();
}
btnNotice.setLabel(labelN + " : " + noOfNotice); btnNotice.setLabel(labelN + " : " + noOfNotice);
btnRequest.setLabel(labelR + " : " + noOfRequest); btnRequest.setLabel(labelR + " : " + noOfRequest);
btnWorkflow.setLabel(labelW + " : " + noOfWorkflow); btnWorkflow.setLabel(labelW + " : " + noOfWorkflow);
if (isShowUnprocessed()) btnUnprocessed.setLabel(labelU + " : " + noOfUnprocessed); if (isShowUnprocessed()) btnUnprocessed.setLabel(labelU + " : " + noOfUnprocessed);
EventQueue<Event> queue = EventQueues.lookup(IDesktop.ACTIVITIES_EVENT_QUEUE, true);
Map<String, Object> map = new HashMap<String, Object>();
map.put("notice", noOfNotice);
map.put("request", noOfRequest);
map.put("workflow", noOfWorkflow);
map.put("unprocessed", noOfUnprocessed);
Event event = new Event(IDesktop.ON_ACTIVITIES_CHANGED_EVENT, null, map);
queue.publish(event);
}
@Override
public boolean isPooling() {
return true;
} }
public void onEvent(Event event) public void onEvent(Event event)

View File

@ -20,17 +20,34 @@ import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.adempiere.base.Service;
import org.adempiere.base.event.AbstractEventHandler;
import org.adempiere.base.event.EventManager;
import org.adempiere.base.event.IEventTopics;
import org.adempiere.webui.session.SessionManager; import org.adempiere.webui.session.SessionManager;
import org.adempiere.webui.util.ServerPushTemplate;
import org.compiere.model.I_R_Request;
import org.compiere.model.PO;
import org.compiere.model.X_R_RequestType; import org.compiere.model.X_R_RequestType;
import org.compiere.util.DB; import org.compiere.util.DB;
import org.compiere.util.Env; import org.compiere.util.Env;
import org.compiere.util.Trx;
import org.compiere.util.TrxEventListener;
import org.idempiere.distributed.IMessageService;
import org.idempiere.distributed.ITopic;
import org.idempiere.distributed.ITopicSubscriber;
import org.osgi.service.event.EventHandler;
import org.zkoss.calendar.Calendars; import org.zkoss.calendar.Calendars;
import org.zkoss.calendar.api.CalendarEvent; import org.zkoss.calendar.api.CalendarEvent;
import org.zkoss.calendar.event.CalendarsEvent; import org.zkoss.calendar.event.CalendarsEvent;
import org.zkoss.calendar.impl.SimpleCalendarModel; import org.zkoss.calendar.impl.SimpleCalendarModel;
import org.zkoss.util.Locales; import org.zkoss.util.Locales;
import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Desktop;
import org.zkoss.zk.ui.Executions; import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.event.Event; import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener; import org.zkoss.zk.ui.event.EventListener;
@ -45,7 +62,7 @@ import org.zkoss.zul.Toolbarbutton;
* @author Elaine * @author Elaine
* @date November 20, 2008 * @date November 20, 2008
*/ */
public class DPCalendar extends DashboardPanel implements EventListener<Event> { public class DPCalendar extends DashboardPanel implements EventListener<Event>, EventHandler {
/** /**
@ -55,24 +72,29 @@ public class DPCalendar extends DashboardPanel implements EventListener<Event> {
private Calendars calendars; private Calendars calendars;
private SimpleCalendarModel scm; private SimpleCalendarModel scm;
private Toolbarbutton btnCal, btnRefresh; private Toolbarbutton btnCal, btnRefresh;
private Button btnCurrentDate; private Button btnCurrentDate;
private Label lblDate; private Label lblDate;
private Component divArrowLeft, divArrowRight; private Component divArrowLeft, divArrowRight;
private static final String ON_REQUEST_CHANGED_TOPIC = "onRequestChanged";
private EventWindow eventWin; private EventWindow eventWin;
private Properties ctx;
private Desktop desktop;
private static RequestEventHandler eventHandler;
private static TopicSubscriber subscriber;
public DPCalendar() { public DPCalendar() {
super(); super();
scm = new SimpleCalendarModel(); ctx = new Properties();
ArrayList<ADCalendarEvent> events = getEvents(0); ctx.putAll(Env.getCtx());
for (ADCalendarEvent event : events)
scm.add(event);
Component component = Executions.createComponents("calendar_mini.zul", this, null); Component component = Executions.createComponents("calendar_mini.zul", this, null);
calendars = (Calendars) component.getFellow("cal"); calendars = (Calendars) component.getFellow("cal");
calendars.setModel(scm);
btnCal = (Toolbarbutton) component.getFellow("btnCal"); btnCal = (Toolbarbutton) component.getFellow("btnCal");
btnCal.addEventListener(Events.ON_CLICK, this); btnCal.addEventListener(Events.ON_CLICK, this);
@ -96,6 +118,25 @@ public class DPCalendar extends DashboardPanel implements EventListener<Event> {
calendars.addEventListener("onEventCreate", this); calendars.addEventListener("onEventCreate", this);
calendars.addEventListener("onEventEdit", this); calendars.addEventListener("onEventEdit", this);
EventManager.getInstance().register(ON_REQUEST_CHANGED_TOPIC, this);
createStaticListeners();
}
private synchronized void createStaticListeners() {
if (eventHandler == null) {
eventHandler = new RequestEventHandler();
eventHandler.bindEventManager(EventManager.getInstance());
}
if (subscriber == null) {
subscriber = new TopicSubscriber();
IMessageService service = Service.locator().locate(IMessageService.class).getService();
if (service != null) {
ITopic<Map<String,String>> topic = service.getTopic("onRequestChanged");
topic.subscribe(subscriber);
}
}
} }
public void onEvent(Event e) throws Exception { public void onEvent(Event e) throws Exception {
@ -143,7 +184,7 @@ public class DPCalendar extends DashboardPanel implements EventListener<Event> {
} }
} }
public static ArrayList<ADCalendarEvent> getEvents(int RequestTypeID) { public static ArrayList<ADCalendarEvent> getEvents(int RequestTypeID, Properties ctx) {
ArrayList<ADCalendarEvent> events = new ArrayList<ADCalendarEvent>(); ArrayList<ADCalendarEvent> events = new ArrayList<ADCalendarEvent>();
String sql = "SELECT DISTINCT r.R_Request_ID, r.DateNextAction, " String sql = "SELECT DISTINCT r.R_Request_ID, r.DateNextAction, "
+ "r.DateStartPlan, r.DateCompletePlan, r.StartTime, r.EndTime, " + "r.DateStartPlan, r.DateCompletePlan, r.StartTime, r.EndTime, "
@ -162,10 +203,10 @@ public class DPCalendar extends DashboardPanel implements EventListener<Event> {
try { try {
ps = DB.prepareStatement(sql, null); ps = DB.prepareStatement(sql, null);
ps.setInt(1, Env.getAD_User_ID(Env.getCtx())); ps.setInt(1, Env.getAD_User_ID(ctx));
ps.setInt(2, Env.getAD_User_ID(Env.getCtx())); ps.setInt(2, Env.getAD_User_ID(ctx));
ps.setInt(3, Env.getAD_User_ID(Env.getCtx())); ps.setInt(3, Env.getAD_User_ID(ctx));
ps.setInt(4, Env.getAD_Client_ID(Env.getCtx())); ps.setInt(4, Env.getAD_Client_ID(ctx));
if(RequestTypeID > 0) if(RequestTypeID > 0)
ps.setInt(5, RequestTypeID); ps.setInt(5, RequestTypeID);
@ -313,7 +354,7 @@ public class DPCalendar extends DashboardPanel implements EventListener<Event> {
return events; return events;
} }
public static ArrayList<X_R_RequestType> getRequestTypes() { public static ArrayList<X_R_RequestType> getRequestTypes(Properties ctx) {
ArrayList<X_R_RequestType> types = new ArrayList<X_R_RequestType>(); ArrayList<X_R_RequestType> types = new ArrayList<X_R_RequestType>();
String sql = "SELECT * " String sql = "SELECT * "
+ "FROM R_RequestType " + "FROM R_RequestType "
@ -325,12 +366,12 @@ public class DPCalendar extends DashboardPanel implements EventListener<Event> {
try { try {
ps = DB.prepareStatement(sql, null); ps = DB.prepareStatement(sql, null);
ps.setInt(1, Env.getAD_Client_ID(Env.getCtx())); ps.setInt(1, Env.getAD_Client_ID(ctx));
rs = ps.executeQuery(); rs = ps.executeQuery();
while (rs.next()) { while (rs.next()) {
types.add(new X_R_RequestType(Env.getCtx(), rs, null)); types.add(new X_R_RequestType(ctx, rs, null));
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
@ -345,15 +386,31 @@ public class DPCalendar extends DashboardPanel implements EventListener<Event> {
btnRefreshClicked(); btnRefreshClicked();
} }
private void btnRefreshClicked() { @Override
scm.clear(); public void refresh(ServerPushTemplate template) {
ArrayList<ADCalendarEvent> events = getEvents(0); refreshModel();
for (ADCalendarEvent event : events) template.executeAsync(this);
scm.add(event); desktop = getDesktop();
}
@Override
public void updateUI() {
calendars.setModel(scm); calendars.setModel(scm);
calendars.invalidate(); calendars.invalidate();
} }
private void btnRefreshClicked() {
refreshModel();
updateUI();
}
private void refreshModel() {
scm = new SimpleCalendarModel();
ArrayList<ADCalendarEvent> events = getEvents(0, ctx);
for (ADCalendarEvent event : events)
scm.add(event);
}
private void updateDateLabel() { private void updateDateLabel() {
Date b = calendars.getBeginDate(); Date b = calendars.getBeginDate();
Date e = calendars.getEndDate(); Date e = calendars.getEndDate();
@ -374,4 +431,114 @@ public class DPCalendar extends DashboardPanel implements EventListener<Event> {
calendars.previousPage(); calendars.previousPage();
updateDateLabel(); updateDateLabel();
} }
@Override
public void handleEvent(org.osgi.service.event.Event event) {
if (event.getTopic().equals(ON_REQUEST_CHANGED_TOPIC)) {
String clientId = (String) event.getProperty(I_R_Request.COLUMNNAME_AD_Client_ID);
String salesRepId = (String) event.getProperty(I_R_Request.COLUMNNAME_SalesRep_ID);
String userId = (String) event.getProperty(I_R_Request.COLUMNNAME_AD_User_ID);
String createdBy = (String) event.getProperty(I_R_Request.COLUMNNAME_CreatedBy);
String AD_Client_ID = Integer.toString(Env.getAD_Client_ID(ctx));
String AD_User_ID = Integer.toString(Env.getAD_User_ID(ctx));
if (clientId.equals(AD_Client_ID) && !"0".equals(AD_User_ID)) {
if (salesRepId.equals(AD_User_ID) || userId.equals(AD_User_ID) || createdBy.equals(AD_User_ID)) {
try {
if (desktop != null && desktop.isAlive()) {
ServerPushTemplate template = new ServerPushTemplate(desktop);
refresh(template);
} else {
EventManager.getInstance().unregister(this);
}
} catch (Exception e) {
EventManager.getInstance().unregister(this);
}
}
}
}
}
static class TopicSubscriber implements ITopicSubscriber<Map<String, String>> {
@Override
public void onMessage(Map<String, String> message) {
org.osgi.service.event.Event requestChangedEvent = new org.osgi.service.event.Event(ON_REQUEST_CHANGED_TOPIC, message);
EventManager.getInstance().postEvent(requestChangedEvent);
}
}
static class RequestEventHandler extends AbstractEventHandler {
@Override
protected void doHandleEvent(org.osgi.service.event.Event event) {
PO po = getPO(event);
I_R_Request request = (I_R_Request)po;
Map<String, String> message = new HashMap<String, String>();
message.put(I_R_Request.COLUMNNAME_SalesRep_ID, Integer.toString(request.getSalesRep_ID()));
message.put(I_R_Request.COLUMNNAME_AD_User_ID, Integer.toString(request.getAD_User_ID()));
message.put(I_R_Request.COLUMNNAME_CreatedBy, Integer.toString(request.getCreatedBy()));
message.put(I_R_Request.COLUMNNAME_AD_Client_ID, Integer.toString(request.getAD_Client_ID()));
RequestRunnable runnable = new RequestRunnable(message);
Trx trx = po.get_TrxName() != null ? Trx.get(po.get_TrxName(), false) : null;
if (trx != null && trx.isActive()) {
trx.addTrxEventListener(new TrxListener(runnable));
} else {
runnable.run();
}
}
@Override
protected void initialize() {
registerTableEvent(IEventTopics.PO_AFTER_NEW, I_R_Request.Table_Name);
registerTableEvent(IEventTopics.PO_AFTER_CHANGE, I_R_Request.Table_Name);
registerTableEvent(IEventTopics.PO_AFTER_DELETE, I_R_Request.Table_Name);
}
}
static class RequestRunnable implements Runnable {
private Map<String, String> message;
protected RequestRunnable(Map<String, String> message) {
this.message = message;
}
@Override
public void run() {
IMessageService service = Service.locator().locate(IMessageService.class).getService();
if (service != null) {
ITopic<Map<String,String>> topic = service.getTopic(ON_REQUEST_CHANGED_TOPIC);
topic.publish(message);
} else {
org.osgi.service.event.Event requestChangedEvent = new org.osgi.service.event.Event(ON_REQUEST_CHANGED_TOPIC, message);
EventManager.getInstance().postEvent(requestChangedEvent);
}
}
}
static class TrxListener implements TrxEventListener {
private Runnable runnable;
protected TrxListener(Runnable runnable) {
this.runnable = runnable;
}
@Override
public void afterRollback(Trx trx, boolean success) {
}
@Override
public void afterCommit(Trx trx, boolean success) {
if (success) {
runnable.run();
}
}
@Override
public void afterClose(Trx trx) {
trx.removeTrxEventListener(this);
}
}
} }

View File

@ -14,7 +14,10 @@
package org.adempiere.webui.dashboard; package org.adempiere.webui.dashboard;
import java.util.List; import java.util.List;
import java.util.Properties;
import org.adempiere.base.Service;
import org.adempiere.base.event.EventManager;
import org.adempiere.webui.session.SessionManager; import org.adempiere.webui.session.SessionManager;
import org.adempiere.webui.util.ServerPushTemplate; import org.adempiere.webui.util.ServerPushTemplate;
import org.compiere.model.MQuery; import org.compiere.model.MQuery;
@ -24,7 +27,12 @@ import org.compiere.model.MTable;
import org.compiere.util.Env; import org.compiere.util.Env;
import org.compiere.util.Msg; import org.compiere.util.Msg;
import org.compiere.util.Util; import org.compiere.util.Util;
import org.idempiere.distributed.IMessageService;
import org.idempiere.distributed.ITopic;
import org.idempiere.distributed.ITopicSubscriber;
import org.osgi.service.event.EventHandler;
import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Desktop;
import org.zkoss.zk.ui.event.DropEvent; import org.zkoss.zk.ui.event.DropEvent;
import org.zkoss.zk.ui.event.Event; import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener; import org.zkoss.zk.ui.event.EventListener;
@ -42,7 +50,7 @@ import org.zkoss.zul.Vbox;
* @author Carlos Ruiz / GlobalQSS * @author Carlos Ruiz / GlobalQSS
* @date January 27, 2012 * @date January 27, 2012
*/ */
public class DPRecentItems extends DashboardPanel implements EventListener<Event> { public class DPRecentItems extends DashboardPanel implements EventListener<Event>, EventHandler {
private static final String AD_RECENT_ITEM_ID_ATTR = "AD_RecentItem_ID"; private static final String AD_RECENT_ITEM_ID_ATTR = "AD_RecentItem_ID";
@ -53,12 +61,24 @@ public class DPRecentItems extends DashboardPanel implements EventListener<Event
public static final String DELETE_RECENTITEMS_DROPPABLE = "deleteRecentItems"; public static final String DELETE_RECENTITEMS_DROPPABLE = "deleteRecentItems";
private static TopicSubscriber topicSubscriber;
private Box bxRecentItems; private Box bxRecentItems;
private int AD_User_ID;
private Properties ctx;
private Desktop desktop;
public DPRecentItems() public DPRecentItems()
{ {
super(); super();
ctx = new Properties();
ctx.putAll(Env.getCtx());
AD_User_ID = Env.getAD_User_ID(ctx);
Panel panel = new Panel(); Panel panel = new Panel();
this.appendChild(panel); this.appendChild(panel);
@ -75,7 +95,7 @@ public class DPRecentItems extends DashboardPanel implements EventListener<Event
Image imgr = new Image("/images/Refresh24.png"); Image imgr = new Image("/images/Refresh24.png");
recentItemsToolbar.appendChild(imgr); recentItemsToolbar.appendChild(imgr);
imgr.setStyle("text-align: right; cursor: pointer;"); imgr.setStyle("text-align: right; cursor: pointer;");
imgr.setTooltiptext(Util.cleanAmp(Msg.getMsg(Env.getCtx(), "Refresh"))); imgr.setTooltiptext(Util.cleanAmp(Msg.getMsg(ctx, "Refresh")));
imgr.addEventListener(Events.ON_CLICK, this); imgr.addEventListener(Events.ON_CLICK, this);
// //
@ -83,10 +103,22 @@ public class DPRecentItems extends DashboardPanel implements EventListener<Event
recentItemsToolbar.appendChild(img); recentItemsToolbar.appendChild(img);
img.setStyle("text-align: right;"); img.setStyle("text-align: right;");
img.setDroppable(DELETE_RECENTITEMS_DROPPABLE); img.setDroppable(DELETE_RECENTITEMS_DROPPABLE);
img.setTooltiptext(Util.cleanAmp(Msg.getMsg(Env.getCtx(), "Delete"))); img.setTooltiptext(Util.cleanAmp(Msg.getMsg(ctx, "Delete")));
img.addEventListener(Events.ON_DROP, this); img.addEventListener(Events.ON_DROP, this);
// //
EventManager.getInstance().register(MRecentItem.ON_RECENT_ITEM_CHANGED_TOPIC, this);
createTopicSubscriber();
}
private static synchronized void createTopicSubscriber() {
if (topicSubscriber == null) {
topicSubscriber = new TopicSubscriber();
IMessageService service = Service.locator().locate(IMessageService.class).getService();
if (service != null) {
ITopic<Integer> topic = service.getTopic(MRecentItem.ON_RECENT_ITEM_CHANGED_TOPIC);
topic.subscribe(topicSubscriber);
}
}
} }
private void createRecentItemsPanel() private void createRecentItemsPanel()
@ -101,7 +133,7 @@ public class DPRecentItems extends DashboardPanel implements EventListener<Event
*/ */
private void riDBremove(int AD_RecentItem_ID) private void riDBremove(int AD_RecentItem_ID)
{ {
MRecentItem ri = MRecentItem.get(Env.getCtx(), AD_RecentItem_ID); MRecentItem ri = MRecentItem.get(ctx, AD_RecentItem_ID);
ri.deleteEx(true); ri.deleteEx(true);
} }
@ -144,8 +176,8 @@ public class DPRecentItems extends DashboardPanel implements EventListener<Event
} }
if (AD_RecentItem_ID > 0) { if (AD_RecentItem_ID > 0) {
MRecentItem ri = MRecentItem.get(Env.getCtx(), AD_RecentItem_ID); MRecentItem ri = MRecentItem.get(ctx, AD_RecentItem_ID);
String TableName = MTable.getTableName(Env.getCtx(), ri.getAD_Table_ID()); String TableName = MTable.getTableName(ctx, ri.getAD_Table_ID());
MQuery query = MQuery.getEqualQuery(TableName + "_ID", ri.getRecord_ID()); MQuery query = MQuery.getEqualQuery(TableName + "_ID", ri.getRecord_ID());
SessionManager.getAppDesktop().openWindow(ri.getAD_Window_ID(), query, null); SessionManager.getAppDesktop().openWindow(ri.getAD_Window_ID(), query, null);
@ -170,12 +202,11 @@ public class DPRecentItems extends DashboardPanel implements EventListener<Event
bxRecentItems.removeChild(comp); bxRecentItems.removeChild(comp);
} }
int maxri = MSysConfig.getIntValue(MSysConfig.RecentItems_MaxShown, 10, Env.getAD_Client_ID(Env.getCtx())); int maxri = MSysConfig.getIntValue(MSysConfig.RecentItems_MaxShown, 10, Env.getAD_Client_ID(ctx));
if (maxri <= 0) if (maxri <= 0)
return; return;
int AD_User_ID = Env.getAD_User_ID(Env.getCtx()); List<MRecentItem> ris = MRecentItem.getFromUser(ctx, AD_User_ID);
List<MRecentItem> ris = MRecentItem.getFromUser(Env.getCtx(), AD_User_ID);
int riShown = 0; int riShown = 0;
for (MRecentItem ri : ris) { for (MRecentItem ri : ris) {
String label = ri.getLabel(); String label = ri.getLabel();
@ -224,7 +255,33 @@ public class DPRecentItems extends DashboardPanel implements EventListener<Event
public void updateUI() { public void updateUI() {
refresh(); refresh();
bxRecentItems.invalidate(); bxRecentItems.invalidate();
desktop = getDesktop();
} }
@Override
public void handleEvent(org.osgi.service.event.Event event) {
if (event.getTopic().equals(MRecentItem.ON_RECENT_ITEM_CHANGED_TOPIC) && event.getProperty("AD_User_ID") != null) {
Object property = event.getProperty("AD_User_ID");
if (property instanceof Number) {
int id = ((Number)property).intValue();
if (id == AD_User_ID) {
try {
if (desktop != null && desktop.isAlive()) {
ServerPushTemplate template = new ServerPushTemplate(desktop);
refresh(template);
}
} catch (Exception e) {
EventManager.getInstance().unregister(this);
}
}
}
}
}
static class TopicSubscriber implements ITopicSubscriber<Integer> {
@Override
public void onMessage(Integer message) {
MRecentItem.postOnChangedEvent(message);
}
}
} }

View File

@ -38,4 +38,11 @@ public abstract class DashboardPanel extends Window implements IDashboardPanel {
public void updateUI() { public void updateUI() {
} }
/**
* @return true if this dashboard widget uses polling to update its content
*/
public boolean isPooling() {
return false;
}
} }

View File

@ -18,10 +18,8 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Properties; import java.util.Properties;
import java.util.logging.Level;
import org.adempiere.util.ServerContext; import org.adempiere.util.ServerContext;
import org.adempiere.webui.desktop.IDesktop;
import org.adempiere.webui.session.SessionContextListener; import org.adempiere.webui.session.SessionContextListener;
import org.adempiere.webui.util.ServerPushTemplate; import org.adempiere.webui.util.ServerPushTemplate;
import org.compiere.util.CLogger; import org.compiere.util.CLogger;
@ -42,9 +40,9 @@ public class DashboardRunnable implements Runnable, Serializable
private Desktop desktop; private Desktop desktop;
private List<DashboardPanel> dashboardPanels; private List<DashboardPanel> dashboardPanels;
private IDesktop appDesktop;
private Locale locale; private Locale locale;
@SuppressWarnings("unused")
private static final CLogger logger = CLogger.getCLogger(DashboardRunnable.class); private static final CLogger logger = CLogger.getCLogger(DashboardRunnable.class);
/** /**
@ -52,17 +50,15 @@ public class DashboardRunnable implements Runnable, Serializable
* @param desktop zk desktop interface * @param desktop zk desktop interface
* @param appDesktop adempiere desktop interface * @param appDesktop adempiere desktop interface
*/ */
public DashboardRunnable(Desktop desktop, IDesktop appDesktop) { public DashboardRunnable(Desktop desktop) {
this.desktop = desktop; this.desktop = desktop;
this.appDesktop = appDesktop;
dashboardPanels = new ArrayList<DashboardPanel>(); dashboardPanels = new ArrayList<DashboardPanel>();
locale = Locales.getCurrent(); locale = Locales.getCurrent();
} }
public DashboardRunnable(DashboardRunnable tmp, Desktop desktop, public DashboardRunnable(DashboardRunnable tmp, Desktop desktop) {
IDesktop appDesktop) { this(desktop);
this(desktop, appDesktop);
this.dashboardPanels = tmp.dashboardPanels; this.dashboardPanels = tmp.dashboardPanels;
} }
@ -70,16 +66,17 @@ public class DashboardRunnable implements Runnable, Serializable
{ {
Locales.setThreadLocal(locale); Locales.setThreadLocal(locale);
try { try {
refreshDashboard(); refreshDashboard(true);
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.INFO, e.getLocalizedMessage(), (e.getCause() != null ? e.getCause() : e)); // logger.log(Level.INFO, e.getLocalizedMessage(), (e.getCause() != null ? e.getCause() : e));
throw new RuntimeException(e);
} }
} }
/** /**
* Refresh dashboard content * Refresh dashboard content
*/ */
public void refreshDashboard() public void refreshDashboard(boolean pooling)
{ {
ServerPushTemplate template = new ServerPushTemplate(desktop); ServerPushTemplate template = new ServerPushTemplate(desktop);
@ -102,12 +99,14 @@ public class DashboardRunnable implements Runnable, Serializable
{ {
ServerContext.setCurrentInstance(ctx); ServerContext.setCurrentInstance(ctx);
} }
for(int i = 0; i < dashboardPanels.size(); i++) for(int i = 0; i < dashboardPanels.size(); i++)
{ {
if (pooling && !dashboardPanels.get(i).isPooling())
continue;
dashboardPanels.get(i).refresh(template); dashboardPanels.get(i).refresh(template);
} }
appDesktop.onServerPush(template);
} }
finally finally
{ {

View File

@ -120,7 +120,7 @@ public class DashboardController implements EventListener<Event> {
if (!dashboardLayout.getDesktop().isServerPushEnabled()) if (!dashboardLayout.getDesktop().isServerPushEnabled())
dashboardLayout.getDesktop().enableServerPush(true); dashboardLayout.getDesktop().enableServerPush(true);
dashboardRunnable = new DashboardRunnable(parent.getDesktop(), desktopImpl); dashboardRunnable = new DashboardRunnable(parent.getDesktop());
// Dashboard content // Dashboard content
Vlayout dashboardColumnLayout = null; Vlayout dashboardColumnLayout = null;
@ -416,7 +416,7 @@ public class DashboardController implements EventListener<Event> {
if (!dashboardRunnable.isEmpty()) if (!dashboardRunnable.isEmpty())
{ {
dashboardRunnable.refreshDashboard(); dashboardRunnable.refreshDashboard(false);
// default Update every one minutes // default Update every one minutes
int interval = MSysConfig.getIntValue(MSysConfig.ZK_DASHBOARD_REFRESH_INTERVAL, 60000); int interval = MSysConfig.getIntValue(MSysConfig.ZK_DASHBOARD_REFRESH_INTERVAL, 60000);
@ -617,7 +617,7 @@ public class DashboardController implements EventListener<Event> {
} }
if (!dashboardRunnable.isEmpty()) if (!dashboardRunnable.isEmpty())
dashboardRunnable.refreshDashboard(); dashboardRunnable.refreshDashboard(false);
} }
} }
} }
@ -626,14 +626,13 @@ public class DashboardController implements EventListener<Event> {
* *
* @param page * @param page
* @param desktop * @param desktop
* @param appDesktop
*/ */
public void onSetPage(Page page, Desktop desktop, IDesktop appDesktop) { public void onSetPage(Page page, Desktop desktop) {
if (dashboardFuture != null && !dashboardFuture.isDone()) { if (dashboardFuture != null && !dashboardFuture.isDone()) {
dashboardFuture.cancel(true); dashboardFuture.cancel(true);
DashboardRunnable tmp = dashboardRunnable; DashboardRunnable tmp = dashboardRunnable;
dashboardRunnable = new DashboardRunnable(tmp, desktop, appDesktop); dashboardRunnable = new DashboardRunnable(tmp, desktop);
// default Update every one minutes // default Update every one minutes
int interval = MSysConfig.getIntValue(MSysConfig.ZK_DASHBOARD_REFRESH_INTERVAL, 60000); int interval = MSysConfig.getIntValue(MSysConfig.ZK_DASHBOARD_REFRESH_INTERVAL, 60000);
dashboardFuture = Adempiere.getThreadPoolExecutor().scheduleWithFixedDelay(dashboardRunnable, interval, interval, TimeUnit.MILLISECONDS); dashboardFuture = Adempiere.getThreadPoolExecutor().scheduleWithFixedDelay(dashboardRunnable, interval, interval, TimeUnit.MILLISECONDS);

View File

@ -18,6 +18,7 @@
package org.adempiere.webui.desktop; package org.adempiere.webui.desktop;
import java.io.Serializable; import java.io.Serializable;
import java.util.Map;
import java.util.Properties; import java.util.Properties;
import org.adempiere.base.event.EventManager; import org.adempiere.base.event.EventManager;
@ -29,7 +30,6 @@ import org.adempiere.webui.apps.AEnv;
import org.adempiere.webui.apps.BusyDialog; import org.adempiere.webui.apps.BusyDialog;
import org.adempiere.webui.component.Tabpanel; import org.adempiere.webui.component.Tabpanel;
import org.adempiere.webui.component.ToolBarButton; import org.adempiere.webui.component.ToolBarButton;
import org.adempiere.webui.dashboard.DPActivities;
import org.adempiere.webui.event.MenuListener; import org.adempiere.webui.event.MenuListener;
import org.adempiere.webui.event.ZKBroadCastManager; import org.adempiere.webui.event.ZKBroadCastManager;
import org.adempiere.webui.panel.BroadcastMessageWindow; import org.adempiere.webui.panel.BroadcastMessageWindow;
@ -57,6 +57,8 @@ import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.Page; import org.zkoss.zk.ui.Page;
import org.zkoss.zk.ui.event.Event; import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener; import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.EventQueue;
import org.zkoss.zk.ui.event.EventQueues;
import org.zkoss.zk.ui.event.Events; import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.event.OpenEvent; import org.zkoss.zk.ui.event.OpenEvent;
import org.zkoss.zk.ui.util.Clients; import org.zkoss.zk.ui.util.Clients;
@ -75,7 +77,7 @@ import org.zkoss.zul.West;
* @version $Revision: 0.10 $ * @version $Revision: 0.10 $
* @author Deepak Pansheriya/Vivek - Adding support for message broadcasting * @author Deepak Pansheriya/Vivek - Adding support for message broadcasting
*/ */
public class DefaultDesktop extends TabbedDesktop implements MenuListener, Serializable, EventListener<Event>, IServerPushCallback,EventHandler,DesktopCleanup public class DefaultDesktop extends TabbedDesktop implements MenuListener, Serializable, EventListener<Event>, EventHandler,DesktopCleanup
{ {
/** /**
* generated serial version ID * generated serial version ID
@ -119,6 +121,9 @@ public class DefaultDesktop extends TabbedDesktop implements MenuListener, Seria
//subscribing to broadcast event //subscribing to broadcast event
bindEventManager(); bindEventManager();
ZKBroadCastManager.getBroadCastMgr(); ZKBroadCastManager.getBroadCastMgr();
EventQueue<Event> queue = EventQueues.lookup(ACTIVITIES_EVENT_QUEUE, true);
queue.subscribe(this);
} }
protected Component doCreatePart(Component parent) protected Component doCreatePart(Component parent)
@ -242,18 +247,36 @@ public class DefaultDesktop extends TabbedDesktop implements MenuListener, Seria
} }
} }
} }
else if (eventName.equals(ON_ACTIVITIES_CHANGED_EVENT))
{
@SuppressWarnings("unchecked")
Map<String, Object> map = (Map<String, Object>) event.getData();
Integer notice = (Integer) map.get("notice");
Integer request = (Integer) map.get("request");
Integer workflow = (Integer) map.get("workflow");
Integer unprocessed = (Integer) map.get("unprocessed");
boolean change = false;
if (notice != null && notice.intValue() != noOfNotice)
{
noOfNotice = notice.intValue(); change = true;
}
if (request != null && request.intValue() != noOfRequest)
{
noOfRequest = request.intValue(); change = true;
}
if (workflow != null && workflow.intValue() != noOfWorkflow)
{
noOfWorkflow = workflow.intValue(); change = true;
}
if (unprocessed != null && unprocessed.intValue() != noOfUnprocessed)
{
noOfUnprocessed = unprocessed.intValue(); change = true;
}
if (change)
updateUI();
}
} }
public void onServerPush(ServerPushTemplate template)
{
noOfNotice = DPActivities.getNoticeCount();
noOfRequest = DPActivities.getRequestCount();
noOfWorkflow = DPActivities.getWorkflowCount();
noOfUnprocessed = DPActivities.getUnprocessedCount();
template.executeAsync(this);
}
/** /**
* *
* @param page * @param page
@ -264,11 +287,11 @@ public class DefaultDesktop extends TabbedDesktop implements MenuListener, Seria
this.page = page; this.page = page;
if (dashboardController != null) { if (dashboardController != null) {
dashboardController.onSetPage(page, layout.getDesktop(), this); dashboardController.onSetPage(page, layout.getDesktop());
} }
if (sideController != null) { if (sideController != null) {
sideController.onSetPage(page, layout.getDesktop(), this); sideController.onSetPage(page, layout.getDesktop());
} }
} }
} }

View File

@ -20,7 +20,6 @@ import org.adempiere.webui.apps.ProcessDialog;
import org.adempiere.webui.component.Window; import org.adempiere.webui.component.Window;
import org.adempiere.webui.panel.ADForm; import org.adempiere.webui.panel.ADForm;
import org.adempiere.webui.part.UIPart; import org.adempiere.webui.part.UIPart;
import org.adempiere.webui.util.ServerPushTemplate;
import org.compiere.model.MQuery; import org.compiere.model.MQuery;
import org.compiere.util.WebDoc; import org.compiere.util.WebDoc;
import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.Component;
@ -34,6 +33,8 @@ import org.zkoss.zk.ui.Page;
public interface IDesktop extends UIPart { public interface IDesktop extends UIPart {
public static final String WINDOWNO_ATTRIBUTE = "desktop.windowno"; public static final String WINDOWNO_ATTRIBUTE = "desktop.windowno";
public static final String ACTIVITIES_EVENT_QUEUE = "ActivitiesEventQueue";
public static final String ON_ACTIVITIES_CHANGED_EVENT = "onActivitiesChanged";
/** /**
* *
@ -193,12 +194,4 @@ public interface IDesktop extends UIPart {
* User logout from desktop, do clean up * User logout from desktop, do clean up
*/ */
public void logout(); public void logout();
/**
* Invoke by the server push thread. If the desktop argument is not null, must activate desktop
* before making update to UI. For performance reason, keep the activate of desktop as short
* as possible.
* @param template
*/
public void onServerPush(ServerPushTemplate template);
} }