This is an automated email from the ASF dual-hosted git repository.
mridulpathak 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 266ed187c3 Move the GenericDelegator startup work out of its
constructor
266ed187c3 is described below
commit 266ed187c3347b3fffbac708a0404cb5c65c6c21
Author: Mridul Pathak <[email protected]>
AuthorDate: Sun Nov 1 13:19:02 2026 +0530
Move the GenericDelegator startup work out of its constructor
The GenericDelegator constructor called overridable methods and handed this
to ModelEntityChecker, to the helper tasks run on other threads and to a new
EntityCrypto before the object was fully built. The constructor now only
assigns fields, and the entity definition check and helper initialization move
to a new Delegator.initialize() lifecycle method, a no-op by default, which
DelegatorFactory calls before setting up the entity ECA handler and runs only
once. The EntityCrypto is crea [...]
---
.../java/org/apache/ofbiz/entity/Delegator.java | 10 ++++
.../org/apache/ofbiz/entity/DelegatorFactory.java | 5 +-
.../org/apache/ofbiz/entity/GenericDelegator.java | 64 ++++++++++++++++------
3 files changed, 61 insertions(+), 18 deletions(-)
diff --git
a/framework/entity/src/main/java/org/apache/ofbiz/entity/Delegator.java
b/framework/entity/src/main/java/org/apache/ofbiz/entity/Delegator.java
index c414b287e0..3a5427a2d2 100644
--- a/framework/entity/src/main/java/org/apache/ofbiz/entity/Delegator.java
+++ b/framework/entity/src/main/java/org/apache/ofbiz/entity/Delegator.java
@@ -690,6 +690,16 @@ public interface Delegator extends DelegatorProvider {
*/
GenericValue getRelatedOne(String relationName, GenericValue value,
boolean useCache) throws GenericEntityException;
+ /**
+ * Does the startup work that needs a fully constructed delegator, such as
checking the entity definitions and
+ * initializing the datasource helpers. {@link DelegatorFactory} calls it
once the delegator is created, before
+ * {@link #initEntityEcaHandler()}; a delegator created without the
factory must call it itself. Calling it again
+ * does nothing.
+ * @throws GenericEntityException if the startup work fails
+ */
+ default void initialize() throws GenericEntityException {
+ }
+
void initEntityEcaHandler();
void initDistributedCacheClear();
diff --git
a/framework/entity/src/main/java/org/apache/ofbiz/entity/DelegatorFactory.java
b/framework/entity/src/main/java/org/apache/ofbiz/entity/DelegatorFactory.java
index 1bc38ed436..5d2d138bd2 100644
---
a/framework/entity/src/main/java/org/apache/ofbiz/entity/DelegatorFactory.java
+++
b/framework/entity/src/main/java/org/apache/ofbiz/entity/DelegatorFactory.java
@@ -76,10 +76,13 @@ public abstract class DelegatorFactory implements
Factory<Delegator, String> {
}
@Override
- public Delegator call() throws ClassNotFoundException {
+ public Delegator call() throws ClassNotFoundException,
GenericEntityException {
try {
Delegator delegator =
UtilObject.getObjectFromFactory(DelegatorFactory.class, delegatorName);
+ // check the entity definitions and setup the datasource
helpers
+ delegator.initialize();
+
// setup the Entity ECA Handler
delegator.initEntityEcaHandler();
diff --git
a/framework/entity/src/main/java/org/apache/ofbiz/entity/GenericDelegator.java
b/framework/entity/src/main/java/org/apache/ofbiz/entity/GenericDelegator.java
index 5e9c6f08e8..257372e36b 100644
---
a/framework/entity/src/main/java/org/apache/ofbiz/entity/GenericDelegator.java
+++
b/framework/entity/src/main/java/org/apache/ofbiz/entity/GenericDelegator.java
@@ -119,7 +119,9 @@ public class GenericDelegator implements Delegator {
private boolean warnNoEcaHandler = false;
private final AtomicReference<Future<EntityEcaHandler<?>>>
entityEcaHandler = new AtomicReference<>();
private final AtomicReference<SequenceUtil> atomicRefSequence = new
AtomicReference<>(null);
- private EntityCrypto crypto = null;
+ private String kekText = null;
+ private final AtomicReference<EntityCrypto> crypto = new
AtomicReference<>();
+ private volatile boolean initialized = false;
/** A ThreadLocal variable to allow other methods to specify a user
identifier (usually the userLoginId, though technically the Entity Engine
* doesn't know anything about the UserLogin entity) */
@@ -199,14 +201,13 @@ public class GenericDelegator implements Delegator {
/** Only allow creation through the factory method */
protected GenericDelegator(String delegatorFullName) throws
GenericEntityException {
- this.setDelegatorNames(delegatorFullName);
+ assignDelegatorNames(delegatorFullName);
this.delegatorInfo =
EntityConfig.getInstance().getDelegator(delegatorBaseName);
if (this.delegatorInfo == null) {
throw new GenericEntityException("No configuration found for
delegator [" + delegatorFullName + "]");
}
- String kekText;
// before continuing, if there is a tenantId use the base delegator to
see if it is valid
if (UtilValidate.isNotEmpty(this.delegatorTenantId)) {
Delegator baseDelegator =
DelegatorFactory.getDelegator(this.delegatorBaseName);
@@ -218,21 +219,33 @@ public class GenericDelegator implements Delegator {
throw new GenericEntityException("No Tenant record found for
delegator [" + this.delegatorFullName + "] with tenantId ["
+ this.delegatorTenantId + "]");
}
- GenericValue kekValue =
EntityQuery.use(baseDelegator).from("TenantKeyEncryptingKey").where("tenantId",
getDelegatorTenantId())
+ GenericValue kekValue =
EntityQuery.use(baseDelegator).from("TenantKeyEncryptingKey").where("tenantId",
this.delegatorTenantId)
.cache(true).queryOne();
if (kekValue != null) {
- kekText = kekValue.getString("kekText");
+ this.kekText = kekValue.getString("kekText");
} else {
- kekText = this.delegatorInfo.getKeyEncryptingKey();
+ this.kekText = this.delegatorInfo.getKeyEncryptingKey();
}
} else {
- kekText = this.delegatorInfo.getKeyEncryptingKey();
+ this.kekText = this.delegatorInfo.getKeyEncryptingKey();
}
this.modelReader = ModelReader.getModelReader(delegatorBaseName);
this.modelGroupReader =
ModelGroupReader.getModelGroupReader(delegatorBaseName);
cache = new Cache(delegatorFullName);
+ }
+
+ /**
+ * Checks the entity definitions and initializes the datasource helper of
every entity group of this delegator.
+ * Only the first call does the work.
+ * @throws GenericEntityException if the entity definition check fails
+ */
+ @Override
+ public synchronized void initialize() throws GenericEntityException {
+ if (this.initialized) {
+ return;
+ }
// do the entity model check
List<String> warningList = new LinkedList<>();
@@ -252,11 +265,21 @@ public class GenericDelegator implements Delegator {
futures.add(ExecutionPool.GLOBAL_BATCH.submit(createHelperCallable(groupName)));
}
ExecutionPool.getAllFutures(futures);
+ this.initialized = true;
+ }
- // NOTE: doing some things before the ECAs and such to make sure it is
in place just in case it is used in a service engine startup thing or
- // something
- // setup the crypto class; this also after the delegator is in the
cache otherwise we get infinite recursion
- this.crypto = new EntityCrypto(this, kekText);
+ /**
+ * Gets the entity crypto of this delegator, creating it on first use.
+ * @return the entity crypto
+ * @throws EntityCryptoException if the entity crypto cannot be created
+ */
+ private EntityCrypto getEntityCrypto() throws EntityCryptoException {
+ EntityCrypto entityCrypto = this.crypto.get();
+ if (entityCrypto == null) {
+ this.crypto.compareAndSet(null, new EntityCrypto(this,
this.kekText));
+ entityCrypto = this.crypto.get();
+ }
+ return entityCrypto;
}
private void initializeOneGenericHelper(String groupName) {
@@ -312,6 +335,10 @@ public class GenericDelegator implements Delegator {
* @param delegatorFullName the delegator full name
*/
protected void setDelegatorNames(String delegatorFullName) {
+ assignDelegatorNames(delegatorFullName);
+ }
+
+ private void assignDelegatorNames(String delegatorFullName) {
this.delegatorFullName = delegatorFullName;
int hashSymbolIndex = delegatorFullName.indexOf('#');
@@ -1959,8 +1986,9 @@ public class GenericDelegator implements Delegator {
if (dcc != null) {
dcc.clearAllCaches();
}
- if (this.crypto != null) {
- this.crypto.clearKeyCache();
+ EntityCrypto entityCrypto = this.crypto.get();
+ if (entityCrypto != null) {
+ entityCrypto.clearKeyCache();
}
}
@@ -2546,7 +2574,7 @@ public class GenericDelegator implements Delegator {
if (fieldValue instanceof String &&
UtilValidate.isEmpty(fieldValue)) {
return fieldValue;
}
- return this.crypto.encrypt(entityName, encryptMethod, fieldValue);
+ return getEntityCrypto().encrypt(entityName, encryptMethod,
fieldValue);
}
return fieldValue;
}
@@ -2557,7 +2585,7 @@ public class GenericDelegator implements Delegator {
@Override
public Object decryptFieldValue(String entityName,
ModelField.EncryptMethod encryptMethod, String encValue) throws
EntityCryptoException {
if (UtilValidate.isNotEmpty(encValue)) {
- return this.crypto.decrypt(entityName, encryptMethod, encValue);
+ return getEntityCrypto().decrypt(entityName, encryptMethod,
encValue);
}
return null;
}
@@ -2567,7 +2595,7 @@ public class GenericDelegator implements Delegator {
*/
@Override
public void setEntityCrypto(EntityCrypto crypto) {
- this.crypto = crypto;
+ this.crypto.set(crypto);
}
/**
@@ -2699,7 +2727,9 @@ public class GenericDelegator implements Delegator {
newDelegator.distributedCacheClear.set(this.distributedCacheClear.get());
newDelegator.originalDelegatorName = getOriginalDelegatorName();
newDelegator.entityEcaHandler.set(this.entityEcaHandler.get());
- newDelegator.crypto = this.crypto;
+ newDelegator.kekText = this.kekText;
+ newDelegator.crypto.set(this.crypto.get());
+ newDelegator.initialized = this.initialized;
// In case this delegator is in testMode give it a reference to
// the rollback list
newDelegator.testMode = this.testMode;