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:
parent
7e24ff5ae5
commit
9d312ff605
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue