Skip to content

Commit 4a51f9d

Browse files
committed
Enhance service semaphore to support parameter-based locking (OFBIZ-13395)
- Added attribute to service definitions - Extended to include - Updated locking logic to use scope - Modified dispatcher to pass parameter values from service requests - Allows concurrent execution of the same service for different parameter values - Enables finer-grained concurrency control compared to service-level locking
1 parent 2d3874b commit 4a51f9d

7 files changed

Lines changed: 43 additions & 5 deletions

File tree

applications/datamodel/DATAMODEL_CHANGES.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,7 @@ No changes
419419
|SalaryStep |lastModifiedByUserLogin |Added |No |NA
420420
|SalesOpportunity |nextStepDate |Added |No |NA
421421
|ServiceSemaphore |lockedByInstanceId |Added |No |NA
422+
|ServiceSemaphore |parameterValue |Added |Yes |NA
422423
|ShoppingListItem |modifiedPrice |Added |No |NA
423424
|SkillType |parentTypeId |Added |No |NA
424425
|SkillType |hasTable |Added |No |NA

framework/service/dtd/services.xsd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ under the License.
131131
</xs:attribute>
132132
<xs:attribute name="semaphore-wait-seconds" type="xs:int" default="300"/>
133133
<xs:attribute name="semaphore-sleep" type="xs:int" default="500"/>
134+
<xs:attribute name="semaphore-parameter-name" type="xs:string"/>
134135
</xs:attributeGroup>
135136
<xs:element name="notification">
136137
<xs:complexType>

framework/service/entitydef/entitymodel.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,10 +212,12 @@ under the License.
212212
<entity entity-name="ServiceSemaphore" package-name="org.apache.ofbiz.service.semaphore" title="Semaphore Lock"
213213
sequence-bank-size="100">
214214
<field name="serviceName" type="name"></field>
215+
<field name="parameterValue" type="name"/>
215216
<field name="lockedByInstanceId" type="id"></field>
216217
<field name="lockThread" type="name"></field>
217218
<field name="lockTime" type="date-time"></field>
218219
<prim-key field="serviceName"/>
220+
<prim-key field="parameterValue"/>
219221
</entity>
220222

221223
</entitymodel>

framework/service/src/main/java/org/apache/ofbiz/service/ModelService.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,9 @@ public class ModelService extends AbstractMap<String, Object> implements Seriali
185185
/** Semaphore sleep time (in milliseconds) */
186186
private int semaphoreSleep;
187187

188+
/** Semaphore parameter name */
189+
private String semaphoreParameterName;
190+
188191
/** Require a new transaction for this service */
189192
private boolean hideResultInLog;
190193

@@ -398,6 +401,14 @@ public void setSemaphoreSleep(int semaphoreSleep) {
398401
this.semaphoreSleep = semaphoreSleep;
399402
}
400403

404+
/**
405+
* Sets semaphore parameter name.
406+
* @param semaphoreParameterName the semaphore sleep
407+
*/
408+
public void setSemaphoreParameterName(String semaphoreParameterName) {
409+
this.semaphoreParameterName = semaphoreParameterName;
410+
}
411+
401412
/**
402413
* Sets hide result in log.
403414
* @param hideResultInLog the hide result in log
@@ -574,6 +585,14 @@ public int getSemaphoreSleep() {
574585
return semaphoreSleep;
575586
}
576587

588+
/**
589+
* Gets semaphore parameter name.
590+
* @return the semaphore parameter name
591+
*/
592+
public String getSemaphoreParameterName() {
593+
return semaphoreParameterName;
594+
}
595+
577596
/**
578597
* Gets impl services.
579598
* @return the impl services
@@ -791,6 +810,7 @@ public ModelService(ModelService model) {
791810
this.debug = model.debug;
792811
this.semaphoreWait = model.semaphoreWait;
793812
this.semaphoreSleep = model.semaphoreSleep;
813+
this.semaphoreParameterName = model.semaphoreParameterName;
794814
this.contextInfo = model.contextInfo;
795815
this.definitionLocation = model.definitionLocation;
796816
this.description = model.description;

framework/service/src/main/java/org/apache/ofbiz/service/ModelServiceReader.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,11 @@ private ModelService createModelService(Element serviceElement, String resourceL
214214
}
215215
service.setSemaphoreSleep(semaphoreSleep);
216216

217+
String semaphoreParamName = UtilXml.checkEmpty(serviceElement.getAttribute("semaphore-parameter-name"));
218+
if (UtilValidate.isNotEmpty(semaphoreParamName)) {
219+
service.setSemaphoreParameterName(semaphoreParamName);
220+
}
221+
217222
// set the max retry field
218223
String maxRetryStr = UtilXml.checkEmpty(serviceElement.getAttribute("max-retry"));
219224
int maxRetry = 0;

framework/service/src/main/java/org/apache/ofbiz/service/ServiceDispatcher.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,9 +284,16 @@ public Map<String, Object> runSync(String localName, ModelService modelService,
284284
boolean isError = false;
285285
boolean beganTrans = false;
286286
try {
287+
String semaphoreParamValue = "_NA_";
288+
String semaphoreParamName = modelService.getSemaphoreParameterName();
289+
if (UtilValidate.isNotEmpty(semaphoreParamName)) {
290+
Object paramObj = params.get(semaphoreParamName);
291+
semaphoreParamValue = (paramObj != null) ? paramObj.toString() : "_NULL_";
292+
}
293+
287294
// check for semaphore and acquire a lock
288295
if ("wait".equals(modelService.getSemaphore()) || "fail".equals(modelService.getSemaphore())) {
289-
lock = new ServiceSemaphore(delegator, modelService);
296+
lock = new ServiceSemaphore(delegator, modelService, semaphoreParamValue);
290297
lock.acquire();
291298
}
292299

framework/service/src/main/java/org/apache/ofbiz/service/semaphore/ServiceSemaphore.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,19 @@ public final class ServiceSemaphore {
5050
private Delegator delegator;
5151
private GenericValue lock;
5252
private ModelService model;
53+
private String parameterValue;
5354

5455
private int wait = 0;
5556
private int mode;
5657
private Timestamp lockTime = null;
5758

58-
public ServiceSemaphore(Delegator delegator, ModelService model) {
59+
public ServiceSemaphore(Delegator delegator, ModelService model, String parameterValue) {
5960
this.delegator = delegator;
6061
this.mode = "wait".equals(model.getSemaphore()) ? SEMAPHORE_MODE_WAIT
6162
: ("fail".equals(model.getSemaphore()) ? SEMAPHORE_MODE_FAIL : SEMAPHORE_MODE_NONE);
6263
this.model = model;
6364
this.lock = null;
65+
this.parameterValue = parameterValue;
6466
}
6567

6668
/**
@@ -147,8 +149,8 @@ private boolean checkLockNeedToWait() throws SemaphoreFailException {
147149

148150
try {
149151
if (EntityQuery.use(delegator).from("ServiceSemaphore")
150-
.where("serviceName", model.getName()).queryCount() == 0) {
151-
semaphore = delegator.makeValue("ServiceSemaphore", "serviceName", model.getName(),
152+
.where("serviceName", model.getName(), "parameterValue", parameterValue).queryCount() == 0) {
153+
semaphore = delegator.makeValue("ServiceSemaphore", "serviceName", model.getName(), "parameterValue", parameterValue,
152154
"lockedByInstanceId", JobManager.INSTANCE_ID, "lockThread", threadName, "lockTime", lockTime);
153155

154156
// use the special method below so we can reuse the unique tx functions
@@ -196,7 +198,7 @@ private synchronized boolean dbWrite(GenericValue value, boolean delete) {
196198
} else {
197199
// Last check before inserting data in this transaction to avoid error log
198200
isError = EntityQuery.use(delegator).from("ServiceSemaphore")
199-
.where("serviceName", model.getName()).queryCount() != 0;
201+
.where("serviceName", model.getName(), "parameterValue", parameterValue).queryCount() != 0;
200202
if (!isError) {
201203
lock = value.create();
202204
}

0 commit comments

Comments
 (0)