diff --git a/org.adempiere.base/src/org/compiere/util/CacheChangeListener.java b/org.adempiere.base/src/org/compiere/util/CacheChangeListener.java new file mode 100644 index 0000000000..d680246950 --- /dev/null +++ b/org.adempiere.base/src/org/compiere/util/CacheChangeListener.java @@ -0,0 +1,47 @@ +/*********************************************************************** + * This file is part of iDempiere ERP Open Source * + * http://www.idempiere.org * + * * + * Copyright (C) Contributors * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * + * MA 02110-1301, USA. * + * * + * Contributors: * + * - hengsin * + **********************************************************************/ +package org.compiere.util; + +/** + * Listener for cache reset event. + * Note that this is ignore by CacheMgt if CCache implementation that implement this interface + * doesn't return null for getTableName(). + * @author hengsin + * + */ +public interface CacheChangeListener { + /** + * Reset Cache + * @param tableName + */ + public void reset(String tableName); + + /** + * Reset Cache by record id + * @param tableName + * @param recordId + */ + public void reset(String tableName, int recordId); +} diff --git a/org.adempiere.base/src/org/compiere/util/CacheMgt.java b/org.adempiere.base/src/org/compiere/util/CacheMgt.java index 3edab8c529..9aae940947 100644 --- a/org.adempiere.base/src/org/compiere/util/CacheMgt.java +++ b/org.adempiere.base/src/org/compiere/util/CacheMgt.java @@ -66,6 +66,8 @@ public class CacheMgt private ArrayList m_tableNames = new ArrayList(); /** Logger */ private static CLogger log = CLogger.getCLogger(CacheMgt.class); + /** Cache change listeners **/ + private List m_listeners = new ArrayList(); public static int MAX_SIZE = 1000; static @@ -103,6 +105,12 @@ public class CacheMgt m_tableNames.add(tableName); m_instances.add (instance); + + if (tableName == null && instance instanceof CacheChangeListener) + { + m_listeners.add((CacheChangeListener) instance); + } + Map map = null; if (distributed) { @@ -305,6 +313,15 @@ public class CacheMgt } if (log.isLoggable(Level.FINE)) log.fine(tableName + ": #" + counter + " (" + total + ")"); + CacheChangeListener[] listeners = m_listeners.toArray(new CacheChangeListener[0]); + for(CacheChangeListener listener : listeners) + { + if (Record_ID == -1) + listener.reset(tableName); + else + listener.reset(tableName, Record_ID); + } + return total; } @@ -335,7 +352,7 @@ public class CacheMgt } } } - } + } } /** diff --git a/org.adempiere.base/src/org/compiere/util/DefaultEvaluatee.java b/org.adempiere.base/src/org/compiere/util/DefaultEvaluatee.java index a9b4ee59c2..771de30242 100644 --- a/org.adempiere.base/src/org/compiere/util/DefaultEvaluatee.java +++ b/org.adempiere.base/src/org/compiere/util/DefaultEvaluatee.java @@ -24,11 +24,14 @@ **********************************************************************/ package org.compiere.util; +import java.util.List; import java.util.Properties; +import java.util.stream.Collectors; import org.compiere.model.GridTab; import org.compiere.model.MColumn; import org.compiere.model.MTable; +import org.compiere.model.PO; /** * @author hengsin @@ -40,6 +43,8 @@ public class DefaultEvaluatee implements Evaluatee { private int m_WindowNo; private int m_TabNo; + private static final ReferenceCache s_ReferenceCache = new ReferenceCache("DefaultEvaluatee_ReferenceCache", 100, 1, 2000); + /** * * @param gridTab @@ -106,23 +111,68 @@ public class DefaultEvaluatee implements Evaluatee { } if (column != null) { String foreignTable = column.getReferenceTableName(); - refValue = DB.getSQLValueString(null, - "SELECT " + foreignColumn + " FROM " + foreignTable + " WHERE " - + foreignTable + "_ID = ?", id); - return refValue; + MTable table = MTable.get(Env.getCtx(), foreignTable); + if (table != null) { + return getColumnValue(table, foreignTable, foreignColumn, id, refValue); + } } else { // no MColumn found, try tableName from columnName String foreignTable = variableName.substring(0, variableName.length()-3); MTable table = MTable.get(ctx, foreignTable); if (table != null) { - refValue = DB.getSQLValueString(null, - "SELECT " + foreignColumn + " FROM " + foreignTable + " WHERE " - + foreignTable + "_ID = ?", id); - return refValue; + return getColumnValue(table, foreignTable, foreignColumn, id, refValue); } } } } return value; } + + private String getColumnValue(MTable table, String foreignTable, String foreignColumn, int id, String refValue) { + String key = foreignTable+"|"+id; + PO po = null; + if (s_ReferenceCache.containsKey(key)) + { + po = s_ReferenceCache.get(key); + if (po != null && po.get_ID() == id) + refValue = po.get_ValueAsString(foreignColumn); + else + po = null; + } + if (po == null) + { + po = table.getPO(id, null); + if (po != null && po.get_ID() == id) + { + s_ReferenceCache.put(key, po); + refValue = po.get_ValueAsString(foreignColumn); + } + } + return refValue; + } + + private static final class ReferenceCache extends CCache implements CacheChangeListener { + + private static final long serialVersionUID = 6884795644185015913L; + + private ReferenceCache(String name, int initialCapacity, int expireMinutes, int maxSize) { + super(null, name, initialCapacity, expireMinutes, false, maxSize); + } + + @Override + public void reset(String tableName) { + String filter = tableName + "|"; + List keys = keySet().stream().filter(e -> e.startsWith(filter)).collect(Collectors.toList()); + if (!keys.isEmpty()) { + for(String key : keys) + remove(key); + } + } + + @Override + public void reset(String tableName, int recordId) { + String key = tableName + "|" + recordId; + remove(key); + } + } }