This is an automated email from the ASF dual-hosted git repository.

mridulpathak pushed a commit to branch release24.09
in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git


The following commit(s) were added to refs/heads/release24.09 by this push:
     new d2b1f10c8f Fixed: EntityEcaUtil cache-rebuild race under concurrent 
Delegator construction (OFBIZ-13517)
d2b1f10c8f is described below

commit d2b1f10c8f62e52cf1576873446f1dc79b1d5e5f
Author: Mridul Pathak <[email protected]>
AuthorDate: Tue Sep 1 20:07:28 2026 +0530

    Fixed: EntityEcaUtil cache-rebuild race under concurrent Delegator 
construction (OFBIZ-13517)
    
    Threads racing a cache miss on the same entity-eca-reader each 
independently rebuilt the full cache before only one publish won. Added a lock 
with double-checked re-verification around the check-then-build-then-publish 
sequence, mirroring the sibling ServiceEcaUtil race fix in 485496ad3e (#1805).
---
 .../org/apache/ofbiz/entityext/eca/EntityEcaUtil.java  | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git 
a/framework/entityext/src/main/java/org/apache/ofbiz/entityext/eca/EntityEcaUtil.java
 
b/framework/entityext/src/main/java/org/apache/ofbiz/entityext/eca/EntityEcaUtil.java
index 46e1350566..13c7dbba27 100644
--- 
a/framework/entityext/src/main/java/org/apache/ofbiz/entityext/eca/EntityEcaUtil.java
+++ 
b/framework/entityext/src/main/java/org/apache/ofbiz/entityext/eca/EntityEcaUtil.java
@@ -52,15 +52,25 @@ public final class EntityEcaUtil {
     private static final UtilCache<String, Map<String, Map<String, 
List<EntityEcaRule>>>> ENTITY_ECA_READERS =
             UtilCache.createUtilCache("entity.EcaReaders", 0, 0, false);
 
+    // Guards getEntityEcaCache()'s check-then-build-then-publish sequence: 
concurrent Delegator
+    // construction (see GenericDelegator.initEntityEcaHandler()) can race a 
cache miss for the same
+    // reader name, each redundantly rebuilding before only one publish wins.
+    private static final Object CONFIG_LOCK = new Object();
+
     private EntityEcaUtil() { }
 
     public static Map<String, Map<String, List<EntityEcaRule>>> 
getEntityEcaCache(String entityEcaReaderName) {
         Map<String, Map<String, List<EntityEcaRule>>> ecaCache = 
ENTITY_ECA_READERS.get(entityEcaReaderName);
         if (ecaCache == null) {
-            // FIXME: Collections are not thread safe
-            ecaCache = new HashMap<>();
-            readConfig(entityEcaReaderName, ecaCache);
-            ecaCache = 
ENTITY_ECA_READERS.putIfAbsentAndGet(entityEcaReaderName, ecaCache);
+            synchronized (CONFIG_LOCK) {
+                // Re-check: another thread may have already published this 
while we waited for the lock.
+                ecaCache = ENTITY_ECA_READERS.get(entityEcaReaderName);
+                if (ecaCache == null) {
+                    ecaCache = new HashMap<>();
+                    readConfig(entityEcaReaderName, ecaCache);
+                    ecaCache = 
ENTITY_ECA_READERS.putIfAbsentAndGet(entityEcaReaderName, ecaCache);
+                }
+            }
         }
         return ecaCache;
     }

Reply via email to