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

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


The following commit(s) were added to refs/heads/trunk by this push:
     new b3ff76a0a8 Fixed: "null DispatchContext" issue under high load and 
concurrency (OFBIZ-13153)
b3ff76a0a8 is described below

commit b3ff76a0a8b78ecf899231a436edddd1acd3e099
Author: Nicolas Malin <[email protected]>
AuthorDate: Thu Nov 6 16:54:16 2025 +0100

    Fixed: "null DispatchContext" issue under high load and concurrency 
(OFBIZ-13153)
    
    Under high volumetry system or during test process with server with 
mutliple core, ofbiz failed some service due to error like :
    ****
         Caused by: java.lang.NullPointerException: Cannot invoke 
"org.apache.ofbiz.service.DispatchContext.getSecurity()" because "dctx" is null
    ****
    
    This is a randomly error who seems to find it origin on the initialisation 
of the dispatcher. On multiple threading system, the dispatcher object is 
initialize by twice or more process at the same time that failed the 
dispatchContext registration.
    
    To solve it, we extract dispatchContext registration during the dispatcher 
initialisationt and move this function as sync to be ensure that only one 
thread that set it.
    
    Thanks to Mayank S for raise this issue
---
 .../ofbiz/service/GenericAbstractDispatcher.java       | 16 ++++++++++++++++
 .../apache/ofbiz/service/GenericDispatcherFactory.java | 18 +-----------------
 .../java/org/apache/ofbiz/service/LocalDispatcher.java |  5 +++++
 .../org/apache/ofbiz/service/ServiceDispatcher.java    |  8 ++++----
 4 files changed, 26 insertions(+), 21 deletions(-)

diff --git 
a/framework/service/src/main/java/org/apache/ofbiz/service/GenericAbstractDispatcher.java
 
b/framework/service/src/main/java/org/apache/ofbiz/service/GenericAbstractDispatcher.java
index bb0a1cacfe..7e56968a85 100644
--- 
a/framework/service/src/main/java/org/apache/ofbiz/service/GenericAbstractDispatcher.java
+++ 
b/framework/service/src/main/java/org/apache/ofbiz/service/GenericAbstractDispatcher.java
@@ -44,6 +44,22 @@ public abstract class GenericAbstractDispatcher implements 
LocalDispatcher {
     private ServiceDispatcher dispatcher = null;
     private String name = null;
 
+    @Override
+    public void initDispatchContext() {
+        ClassLoader loader;
+        try {
+            loader = Thread.currentThread().getContextClassLoader();
+        } catch (SecurityException e) {
+            loader = this.getClass().getClassLoader();
+        }
+        DispatchContext ctx = new DispatchContext(this.getName(), loader, 
this);
+        this.getDispatcher().register(ctx);
+        this.setCtx(ctx);
+        if (Debug.verboseOn()) {
+            Debug.logVerbose("[GenericDispatcher] : Created Dispatcher for: " 
+ this.getName(), MODULE);
+        }
+    }
+
     /**
      * Gets ctx.
      * @return the ctx
diff --git 
a/framework/service/src/main/java/org/apache/ofbiz/service/GenericDispatcherFactory.java
 
b/framework/service/src/main/java/org/apache/ofbiz/service/GenericDispatcherFactory.java
index f79d730d2d..b89748ea5d 100644
--- 
a/framework/service/src/main/java/org/apache/ofbiz/service/GenericDispatcherFactory.java
+++ 
b/framework/service/src/main/java/org/apache/ofbiz/service/GenericDispatcherFactory.java
@@ -20,7 +20,6 @@ package org.apache.ofbiz.service;
 
 import java.util.Map;
 
-import org.apache.ofbiz.base.util.Debug;
 import org.apache.ofbiz.base.util.UtilValidate;
 import org.apache.ofbiz.entity.Delegator;
 
@@ -44,6 +43,7 @@ public class GenericDispatcherFactory implements 
LocalDispatcherFactory {
         // ServiceDispatcher with name "dispatcherName"
         if (dispatcher == null) {
             dispatcher = new GenericDispatcher(name, delegator);
+            dispatcher.initDispatchContext();
         }
         return dispatcher;
     }
@@ -51,24 +51,8 @@ public class GenericDispatcherFactory implements 
LocalDispatcherFactory {
     // The default LocalDispatcher implementation.
     private static final class GenericDispatcher extends 
GenericAbstractDispatcher {
         private GenericDispatcher(String name, Delegator delegator) {
-            ClassLoader loader;
-            try {
-                loader = Thread.currentThread().getContextClassLoader();
-            } catch (SecurityException e) {
-                loader = this.getClass().getClassLoader();
-            }
             this.setName(name);
             this.setDispatcher(ServiceDispatcher.getInstance(delegator));
-            /*
-             * FIXME: "this" reference escape. DispatchContext constructor uses
-             * this object before it is fully constructed.
-             */
-            DispatchContext ctx = new DispatchContext(name, loader, this);
-            this.getDispatcher().register(ctx);
-            this.setCtx(ctx);
-            if (Debug.verboseOn()) {
-                Debug.logVerbose("[GenericDispatcher] : Created Dispatcher 
for: " + name, MODULE);
-            }
         }
 
         @Override
diff --git 
a/framework/service/src/main/java/org/apache/ofbiz/service/LocalDispatcher.java 
b/framework/service/src/main/java/org/apache/ofbiz/service/LocalDispatcher.java
index 0da848c73d..666e12cad2 100644
--- 
a/framework/service/src/main/java/org/apache/ofbiz/service/LocalDispatcher.java
+++ 
b/framework/service/src/main/java/org/apache/ofbiz/service/LocalDispatcher.java
@@ -34,6 +34,11 @@ import org.apache.ofbiz.service.job.JobManager;
  */
 public interface LocalDispatcher {
 
+    /**
+     * Initialize a dispatch context for this dispatch after the creation is ok
+     */
+    void initDispatchContext();
+
     /**
      * Disables running of Service Engine Condition Actions (SECAs).  Intended 
to be turned off temporarily.
      */
diff --git 
a/framework/service/src/main/java/org/apache/ofbiz/service/ServiceDispatcher.java
 
b/framework/service/src/main/java/org/apache/ofbiz/service/ServiceDispatcher.java
index e4acccf470..bde06cc15b 100644
--- 
a/framework/service/src/main/java/org/apache/ofbiz/service/ServiceDispatcher.java
+++ 
b/framework/service/src/main/java/org/apache/ofbiz/service/ServiceDispatcher.java
@@ -188,7 +188,7 @@ public final class ServiceDispatcher {
      * Registers the loader with this ServiceDispatcher
      * @param context the context of the local dispatcher
      */
-    public void register(DispatchContext context) {
+    public synchronized void register(DispatchContext context) {
         Debug.logInfo("Registering dispatcher: " + context.getName(), MODULE);
         this.localContext.put(context.getName(), context);
     }
@@ -196,7 +196,7 @@ public final class ServiceDispatcher {
      * De-Registers the loader with this ServiceDispatcher
      * @param local the LocalDispatcher to de-register
      */
-    public void deregister(LocalDispatcher local) {
+    public synchronized void deregister(LocalDispatcher local) {
         Debug.logInfo("De-Registering dispatcher: " + local.getName(), MODULE);
         localContext.remove(local.getName());
         if (localContext.isEmpty()) {
@@ -277,7 +277,7 @@ public final class ServiceDispatcher {
         Map<String, List<ServiceEcaRule>> eventMap = null;
         Map<String, Object> ecaContext = null;
         RunningService rs = null;
-        DispatchContext ctx = localContext.get(localName);
+        DispatchContext ctx = getLocalContext(localName);
         GenericEngine engine = null;
         Transaction parentTransaction = null;
         boolean isFailure = false;
@@ -696,7 +696,7 @@ public final class ServiceDispatcher {
         Locale locale = checkLocale(context);
 
         // setup the engine and context
-        DispatchContext ctx = localContext.get(localName);
+        DispatchContext ctx = this.getLocalContext(localName);
         GenericEngine engine = this.getGenericEngine(service.getEngineName());
 
         // for isolated transactions

Reply via email to