From 486201c8b1e874cbe4819675cae05b7c0b4dc0e9 Mon Sep 17 00:00:00 2001 From: Heng Sin Low Date: Mon, 25 Feb 2013 19:57:24 +0800 Subject: [PATCH] IDEMPIERE-663 Zk: Remove the need of re-query for table editor after user have create a new record. --- .../src/org/compiere/model/PO.java | 3 + .../src/org/compiere/util/CCache.java | 5 +- .../src/org/compiere/util/CacheInterface.java | 6 ++ .../src/org/compiere/util/CacheMgt.java | 52 +++++++++++ .../compiere/util/CacheNewRecordCallable.java | 47 ++++++++++ .../org/adempiere/webui/editor/WEditor.java | 1 + .../webui/editor/WTableDirEditor.java | 87 ++++++++++++++++++- 7 files changed, 197 insertions(+), 4 deletions(-) create mode 100644 org.adempiere.base/src/org/compiere/util/CacheNewRecordCallable.java diff --git a/org.adempiere.base/src/org/compiere/model/PO.java b/org.adempiere.base/src/org/compiere/model/PO.java index 5feaf4f60e..e40bd7f530 100644 --- a/org.adempiere.base/src/org/compiere/model/PO.java +++ b/org.adempiere.base/src/org/compiere/model/PO.java @@ -2255,6 +2255,9 @@ public abstract class PO m_createNew = false; if (!newRecord) CacheMgt.get().reset(p_info.getTableName()); + else if (get_ID() > 0) + CacheMgt.get().newRecord(p_info.getTableName(), get_ID()); + return success; } // saveFinish diff --git a/org.adempiere.base/src/org/compiere/util/CCache.java b/org.adempiere.base/src/org/compiere/util/CCache.java index cffe2f4ded..d6949d5174 100644 --- a/org.adempiere.base/src/org/compiere/util/CCache.java +++ b/org.adempiere.base/src/org/compiere/util/CCache.java @@ -394,5 +394,8 @@ public class CCache implements CacheInterface, Map, Serializable V removed = cache.remove(recordId); return removed != null ? 1 : 0; } - + + @Override + public void newRecord(int record_ID) { + } } // CCache diff --git a/org.adempiere.base/src/org/compiere/util/CacheInterface.java b/org.adempiere.base/src/org/compiere/util/CacheInterface.java index 44ee8ebd3a..5fb59afb9e 100644 --- a/org.adempiere.base/src/org/compiere/util/CacheInterface.java +++ b/org.adempiere.base/src/org/compiere/util/CacheInterface.java @@ -41,6 +41,12 @@ public interface CacheInterface * @return number of items */ public int size(); + + /** + * New record created notification + * @param record_ID + */ + public void newRecord(int record_ID); } // CacheInterface diff --git a/org.adempiere.base/src/org/compiere/util/CacheMgt.java b/org.adempiere.base/src/org/compiere/util/CacheMgt.java index b76247acf9..f59a86c648 100644 --- a/org.adempiere.base/src/org/compiere/util/CacheMgt.java +++ b/org.adempiere.base/src/org/compiere/util/CacheMgt.java @@ -159,6 +159,24 @@ public class CacheMgt } } + /** + * do a cluster wide cache reset for tableName with recordId key + * @param tableName + * @param recordId record id for the cache entries to delete. pass -1 if you don't want to delete + * cache entries by record id + * @return number of deleted cache entries + */ + private void clusterNewRecord(String tableName, int recordId) { + IServiceHolder holder = Service.locator().locate(IClusterService.class); + IClusterService service = holder.getService(); + if (service != null) { + CacheNewRecordCallable callable = new CacheNewRecordCallable(tableName, recordId); + service.execute(callable, service.getMembers()); + } else { + localNewRecord(tableName, recordId); + } + } + /** * do a cluster wide cache reset * @return number of deleted cache entries @@ -248,6 +266,36 @@ public class CacheMgt return total; } + /** + * Reset local Cache + * @param tableName table name + * @param Record_ID record if applicable or 0 for all + * @return number of deleted cache entries + */ + protected void localNewRecord (String tableName, int Record_ID) + { + if (tableName == null) + return; + + if (!m_tableNames.contains(tableName)) + return; + // + for (int i = 0; i < m_instances.size(); i++) + { + CacheInterface stored = (CacheInterface)m_instances.get(i); + if (stored != null && stored instanceof CCache) + { + CCache cc = (CCache)stored; + if (cc.getTableName() != null && cc.getTableName().startsWith(tableName)) // reset lines/dependent too + { + { + stored.newRecord(Record_ID); + } + } + } + } + } + /** * Total Cached Elements * @return count @@ -298,4 +346,8 @@ public class CacheMgt .append("]"); return sb.toString (); } // toString + + public void newRecord(String tableName, int recordId) { + clusterNewRecord(tableName, recordId); + } } // CCache diff --git a/org.adempiere.base/src/org/compiere/util/CacheNewRecordCallable.java b/org.adempiere.base/src/org/compiere/util/CacheNewRecordCallable.java new file mode 100644 index 0000000000..3cee5e8d44 --- /dev/null +++ b/org.adempiere.base/src/org/compiere/util/CacheNewRecordCallable.java @@ -0,0 +1,47 @@ +/****************************************************************************** + * 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; + +import java.io.Serializable; +import java.util.concurrent.Callable; + +/** + * + * @author hengsin + * + */ +public class CacheNewRecordCallable implements Callable, Serializable +{ + + /** + * generated serial id + */ + private static final long serialVersionUID = 6669645804211785491L; + + private String tableName; + private int Record_ID; + + protected CacheNewRecordCallable(String tableName, int Record_ID) + { + this.tableName = tableName; + this.Record_ID = Record_ID; + } + + @Override + public Integer call() throws Exception { + CacheMgt.get().localNewRecord(tableName, Record_ID); + return 1; + } + +} \ No newline at end of file diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/editor/WEditor.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/editor/WEditor.java index a560b9353f..26c29193a8 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/editor/WEditor.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/editor/WEditor.java @@ -118,6 +118,7 @@ public abstract class WEditor implements EventListener, PropertyChangeLis this.gridField = gridField; if (gridField.getGridTab() != null) { comp.setWidgetAttribute(AdempiereWebUI.WIDGET_INSTANCE_NAME, gridField.getGridTab().getTableName()+"0"+gridField.getColumnName()); + this.gridTab = gridField.getGridTab(); } else { comp.setWidgetAttribute(AdempiereWebUI.WIDGET_INSTANCE_NAME, gridField.getColumnName()); } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/editor/WTableDirEditor.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/editor/WTableDirEditor.java index cf2349cb4c..a0a137f24b 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/editor/WTableDirEditor.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/editor/WTableDirEditor.java @@ -43,13 +43,17 @@ import org.compiere.model.MBPartnerLocation; import org.compiere.model.MLocation; import org.compiere.model.MQuery; import org.compiere.model.MTable; +import org.compiere.util.CCache; import org.compiere.util.CLogger; +import org.compiere.util.CacheMgt; import org.compiere.util.DisplayType; import org.compiere.util.Env; import org.compiere.util.KeyNamePair; import org.compiere.util.Msg; import org.compiere.util.NamePair; import org.compiere.util.ValueNamePair; +import org.zkoss.zk.ui.Executions; +import org.zkoss.zk.ui.Page; import org.zkoss.zk.ui.event.Event; import org.zkoss.zk.ui.event.EventListener; import org.zkoss.zk.ui.event.Events; @@ -81,9 +85,12 @@ ContextMenuListener, IZoomableEditor public static final String SHORT_LIST_EVENT = "SHORT_LIST"; // IDEMPIERE 90 protected boolean onlyShortListItems; // IDEMPIERE 90 + private CCacheListener tableCacheListener; + public WTableDirEditor(GridField gridField) { - super(new Combobox(), gridField); + super(new EditorCombobox(), gridField); + ((EditorCombobox)getComponent()).editor = this; lookup = gridField.getLookup(); init(); } @@ -100,7 +107,8 @@ ContextMenuListener, IZoomableEditor */ public WTableDirEditor(Lookup lookup, String label, String description, boolean mandatory, boolean readonly, boolean updateable) { - super(new Combobox(), label, description, mandatory, readonly, updateable); + super(new EditorCombobox(), label, description, mandatory, readonly, updateable); + ((EditorCombobox)getComponent()).editor = this; if (lookup == null) { @@ -123,7 +131,8 @@ ContextMenuListener, IZoomableEditor public WTableDirEditor(String columnName, boolean mandatory, boolean isReadOnly, boolean isUpdateable, Lookup lookup) { - super(new Combobox(), columnName, null, null, mandatory, isReadOnly, isUpdateable); + super(new EditorCombobox(), columnName, null, null, mandatory, isReadOnly, isUpdateable); + ((EditorCombobox)getComponent()).editor = this; if (lookup == null) { throw new IllegalArgumentException("Lookup cannot be null"); @@ -201,6 +210,12 @@ ContextMenuListener, IZoomableEditor } } + private void createCacheListener() { + String columnName = lookup.getColumnName(); + String tableName = columnName.substring(0, columnName.indexOf(".")); + tableCacheListener = new CCacheListener(tableName, this); + } + @Override public String getDisplay() { @@ -600,4 +615,70 @@ ContextMenuListener, IZoomableEditor || (isReadWrite() && lookup.getSize() != getComponent().getItemCount()))) this.actionRefresh(); } + + private static class EditorCombobox extends Combobox { + + /** + * generated serial id + */ + private static final long serialVersionUID = 4540856986889452983L; + protected WTableDirEditor editor; + + @Override + public void onPageAttached(Page newpage, Page oldpage) { + super.onPageAttached(newpage, oldpage); + if (editor.tableCacheListener == null) { + editor.createCacheListener(); + } + } + + @Override + public void onPageDetached(Page page) { + super.onPageDetached(page); + if (editor.tableCacheListener != null) { + CacheMgt.get().unregister(editor.tableCacheListener); + editor.tableCacheListener = null; + } + } + } + + private static class CCacheListener extends CCache { + /** + * generated serial + */ + private static final long serialVersionUID = 3543247404379028327L; + private WTableDirEditor editor; + + protected CCacheListener(String tableName, WTableDirEditor editor) { + super(tableName, tableName, 0, true); + this.editor = editor; + } + + @Override + public int reset() { + if (editor.getComponent().getDesktop() != null && editor.isReadWrite()) { + refreshLookupList(); + } + return 0; + } + + private void refreshLookupList() { + Executions.schedule(editor.getComponent().getDesktop(), new EventListener() { + @Override + public void onEvent(Event event) { + try { + if (editor.isReadWrite()) + editor.actionRefresh(); + } catch (Exception e) {} + } + }, new Event("onResetLookupList")); + } + + @Override + public void newRecord(int record_ID) { + if (editor.getComponent().getDesktop() != null && editor.isReadWrite()) { + refreshLookupList(); + } + } + } }