Author: jaz
Date: Wed Sep 12 13:58:44 2007 New Revision: 575074 URL: http://svn.apache.org/viewvc?rev=575074&view=rev Log: implemented ServiceSemaphore; built in locking to prevent services (when defined) from running at the same time; uses database record to work with a cluser of application servers. Three modes are available: None - Does no locking Wait - Waits for the previous service to complete (currently up to 5 minutes) Fail - Fails when the same service is already running use the semaphore="none|wait|fail" in the service definition (none is the default when the attribute is not defined) Added: ofbiz/trunk/framework/service/src/org/ofbiz/service/semaphore/ ofbiz/trunk/framework/service/src/org/ofbiz/service/semaphore/SemaphoreFailException.java (with props) ofbiz/trunk/framework/service/src/org/ofbiz/service/semaphore/SemaphoreWaitException.java (with props) ofbiz/trunk/framework/service/src/org/ofbiz/service/semaphore/ServiceSemaphore.java (with props) Modified: ofbiz/trunk/framework/service/dtd/services.xsd ofbiz/trunk/framework/service/entitydef/entitygroup.xml ofbiz/trunk/framework/service/entitydef/entitymodel.xml ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelService.java ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelServiceReader.java ofbiz/trunk/framework/service/src/org/ofbiz/service/ServiceDispatcher.java Modified: ofbiz/trunk/framework/service/dtd/services.xsd URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/dtd/services.xsd?rev=575074&r1=575073&r2=575074&view=diff ============================================================================== --- ofbiz/trunk/framework/service/dtd/services.xsd (original) +++ ofbiz/trunk/framework/service/dtd/services.xsd Wed Sep 12 13:58:44 2007 @@ -111,6 +111,15 @@ </xs:restriction> </xs:simpleType> </xs:attribute> + <xs:attribute name="semaphore" default="none"> + <xs:simpleType> + <xs:restriction base="xs:token"> + <xs:enumeration value="none"/> + <xs:enumeration value="fail"/> + <xs:enumeration value="wait"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> </xs:attributeGroup> <xs:element name="notification"> <xs:complexType> Modified: ofbiz/trunk/framework/service/entitydef/entitygroup.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/entitydef/entitygroup.xml?rev=575074&r1=575073&r2=575074&view=diff ============================================================================== --- ofbiz/trunk/framework/service/entitydef/entitygroup.xml (original) +++ ofbiz/trunk/framework/service/entitydef/entitygroup.xml Wed Sep 12 13:58:44 2007 @@ -29,5 +29,10 @@ <entity-group group="org.ofbiz" entity="RecurrenceInfo" /> <entity-group group="org.ofbiz" entity="RecurrenceRule" /> <entity-group group="org.ofbiz" entity="RuntimeData" /> + + <!-- ========================================================= --> + <!-- org.ofbiz.service.semaphore --> + <!-- ========================================================= --> + <entity-group group="org.ofbiz" entity="ServiceSemaphore" /> </entitygroup> Modified: ofbiz/trunk/framework/service/entitydef/entitymodel.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/entitydef/entitymodel.xml?rev=575074&r1=575073&r2=575074&view=diff ============================================================================== --- ofbiz/trunk/framework/service/entitydef/entitymodel.xml (original) +++ ofbiz/trunk/framework/service/entitydef/entitymodel.xml Wed Sep 12 13:58:44 2007 @@ -33,6 +33,7 @@ <!-- ======================== Data Model ===================== --> <!-- The modules in this file are as follows: --> <!-- - org.ofbiz.service.schedule --> + <!-- - org.ofbiz.service.semaphore --> <!-- ========================================================= --> @@ -41,7 +42,7 @@ <!-- ========================================================= --> <entity entity-name="JobSandbox" package-name="org.ofbiz.service.schedule" title="Job Scheduler Sandbox Entity" - sequence-bank-size="100"> + sequence-bank-size="100"> <field name="jobId" type="id-ne"></field> <field name="jobName" type="name"></field> <field name="runTime" type="date-time"></field> @@ -121,9 +122,21 @@ <prim-key field="recurrenceRuleId"/> </entity> <entity entity-name="RuntimeData" package-name="org.ofbiz.service.schedule" title="Runtime Data Entity" - sequence-bank-size="100"> + sequence-bank-size="100"> <field name="runtimeDataId" type="id-ne"></field> <field name="runtimeInfo" type="very-long"></field> <prim-key field="runtimeDataId"/> </entity> + + <!-- ========================================================= --> + <!-- org.ofbiz.service.semaphore --> + <!-- ========================================================= --> + <entity entity-name="ServiceSemaphore" package-name="org.ofbiz.service.semaphore" title="Semaphore Lock Entity" + sequence-bank-size="100"> + <field name="serviceName" type="name"></field> + <field name="lockThread" type="name"></field> + <field name="lockTime" type="date-time"></field> + <prim-key field="serviceName"/> + </entity> + </entitymodel> Modified: ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelService.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelService.java?rev=575074&r1=575073&r2=575074&view=diff ============================================================================== --- ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelService.java (original) +++ ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelService.java Wed Sep 12 13:58:44 2007 @@ -133,6 +133,9 @@ /** Permission service resource-description */ public String permissionResourceDesc; + + /** Semaphore setting (wait, fail, none) */ + public String semaphore; /** Set of services this service implements */ public Set implServices = new ListOrderedSet(); Modified: ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelServiceReader.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelServiceReader.java?rev=575074&r1=575073&r2=575074&view=diff ============================================================================== --- ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelServiceReader.java (original) +++ ofbiz/trunk/framework/service/src/org/ofbiz/service/ModelServiceReader.java Wed Sep 12 13:58:44 2007 @@ -258,7 +258,8 @@ service.name = UtilXml.checkEmpty(serviceElement.getAttribute("name")); service.engineName = UtilXml.checkEmpty(serviceElement.getAttribute("engine")); service.location = UtilXml.checkEmpty(serviceElement.getAttribute("location")); - service.invoke = UtilXml.checkEmpty(serviceElement.getAttribute("invoke")); + service.invoke = UtilXml.checkEmpty(serviceElement.getAttribute("invoke")); + service.semaphore = UtilXml.checkEmpty(serviceElement.getAttribute("semaphore")); service.defaultEntityName = UtilXml.checkEmpty(serviceElement.getAttribute("default-entity-name")); service.fromLoader = isFromURL ? readerURL.toExternalForm() : handler.getLoaderName(); Modified: ofbiz/trunk/framework/service/src/org/ofbiz/service/ServiceDispatcher.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/ServiceDispatcher.java?rev=575074&r1=575073&r2=575074&view=diff ============================================================================== --- ofbiz/trunk/framework/service/src/org/ofbiz/service/ServiceDispatcher.java (original) +++ ofbiz/trunk/framework/service/src/org/ofbiz/service/ServiceDispatcher.java Wed Sep 12 13:58:44 2007 @@ -18,24 +18,11 @@ *******************************************************************************/ package org.ofbiz.service; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -import javax.transaction.Transaction; - import javolution.util.FastList; import javolution.util.FastMap; - import org.apache.commons.collections.map.LRUMap; import org.ofbiz.base.config.GenericConfigException; -import org.ofbiz.base.util.Debug; -import org.ofbiz.base.util.GeneralRuntimeException; -import org.ofbiz.base.util.UtilMisc; -import org.ofbiz.base.util.UtilTimer; -import org.ofbiz.base.util.UtilValidate; -import org.ofbiz.base.util.UtilXml; +import org.ofbiz.base.util.*; import org.ofbiz.entity.GenericDelegator; import org.ofbiz.entity.GenericEntityException; import org.ofbiz.entity.GenericValue; @@ -53,8 +40,15 @@ import org.ofbiz.service.jms.JmsListenerFactory; import org.ofbiz.service.job.JobManager; import org.ofbiz.service.job.JobManagerException; +import org.ofbiz.service.semaphore.ServiceSemaphore; import org.w3c.dom.Element; +import javax.transaction.Transaction; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; + /** * Global Service Dispatcher */ @@ -237,6 +231,13 @@ * @throws GenericServiceException */ public Map runSync(String localName, ModelService modelService, Map context, boolean validateOut) throws ServiceAuthException, ServiceValidationException, GenericServiceException { + // check for semaphore and aquire a lock + ServiceSemaphore lock = null; + if ("wait".equals(modelService.semaphore) || "fail".equals(modelService.semaphore)) { + lock = new ServiceSemaphore(delegator, modelService); + lock.acquire(); + } + long serviceStartTime = System.currentTimeMillis(); boolean debugging = checkDebug(modelService, 1, true); if (Debug.verboseOn()) { @@ -540,6 +541,11 @@ Debug.logTiming("Sync service [" + localName + "/" + modelService.name + "] finished in [" + timeToRun + "] milliseconds", module); } else if (timeToRun > 200) { Debug.logInfo("Sync service [" + localName + "/" + modelService.name + "] finished in [" + timeToRun + "] milliseconds", module); + } + + // release the semaphore lock + if (lock != null) { + lock.release(); } return result; Added: ofbiz/trunk/framework/service/src/org/ofbiz/service/semaphore/SemaphoreFailException.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/semaphore/SemaphoreFailException.java?rev=575074&view=auto ============================================================================== --- ofbiz/trunk/framework/service/src/org/ofbiz/service/semaphore/SemaphoreFailException.java (added) +++ ofbiz/trunk/framework/service/src/org/ofbiz/service/semaphore/SemaphoreFailException.java Wed Sep 12 13:58:44 2007 @@ -0,0 +1,25 @@ +package org.ofbiz.service.semaphore; + +import org.ofbiz.service.GenericServiceException; + +/** + * SemaphoreFailException + */ +public class SemaphoreFailException extends GenericServiceException { + + public SemaphoreFailException() { + super(); + } + + public SemaphoreFailException(String str) { + super(str); + } + + public SemaphoreFailException(String str, Throwable nested) { + super(str, nested); + } + + public SemaphoreFailException(Throwable nested) { + super(nested); + } +} Propchange: ofbiz/trunk/framework/service/src/org/ofbiz/service/semaphore/SemaphoreFailException.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: ofbiz/trunk/framework/service/src/org/ofbiz/service/semaphore/SemaphoreFailException.java ------------------------------------------------------------------------------ svn:keywords = "Date Rev Author URL Id" Propchange: ofbiz/trunk/framework/service/src/org/ofbiz/service/semaphore/SemaphoreFailException.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: ofbiz/trunk/framework/service/src/org/ofbiz/service/semaphore/SemaphoreWaitException.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/semaphore/SemaphoreWaitException.java?rev=575074&view=auto ============================================================================== --- ofbiz/trunk/framework/service/src/org/ofbiz/service/semaphore/SemaphoreWaitException.java (added) +++ ofbiz/trunk/framework/service/src/org/ofbiz/service/semaphore/SemaphoreWaitException.java Wed Sep 12 13:58:44 2007 @@ -0,0 +1,25 @@ +package org.ofbiz.service.semaphore; + +import org.ofbiz.service.GenericServiceException; + +/** + * SemaphoreWaitException + */ +public class SemaphoreWaitException extends GenericServiceException { + + public SemaphoreWaitException() { + super(); + } + + public SemaphoreWaitException(String str) { + super(str); + } + + public SemaphoreWaitException(String str, Throwable nested) { + super(str, nested); + } + + public SemaphoreWaitException(Throwable nested) { + super(nested); + } +} Propchange: ofbiz/trunk/framework/service/src/org/ofbiz/service/semaphore/SemaphoreWaitException.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: ofbiz/trunk/framework/service/src/org/ofbiz/service/semaphore/SemaphoreWaitException.java ------------------------------------------------------------------------------ svn:keywords = "Date Rev Author URL Id" Propchange: ofbiz/trunk/framework/service/src/org/ofbiz/service/semaphore/SemaphoreWaitException.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: ofbiz/trunk/framework/service/src/org/ofbiz/service/semaphore/ServiceSemaphore.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/semaphore/ServiceSemaphore.java?rev=575074&view=auto ============================================================================== --- ofbiz/trunk/framework/service/src/org/ofbiz/service/semaphore/ServiceSemaphore.java (added) +++ ofbiz/trunk/framework/service/src/org/ofbiz/service/semaphore/ServiceSemaphore.java Wed Sep 12 13:58:44 2007 @@ -0,0 +1,155 @@ +package org.ofbiz.service.semaphore; + +import org.ofbiz.base.util.Debug; +import org.ofbiz.base.util.UtilDateTime; +import org.ofbiz.base.util.UtilMisc; +import org.ofbiz.entity.GenericDelegator; +import org.ofbiz.entity.GenericEntityException; +import org.ofbiz.entity.GenericValue; +import org.ofbiz.entity.transaction.GenericTransactionException; +import org.ofbiz.entity.transaction.TransactionUtil; +import org.ofbiz.service.ModelService; + +import javax.transaction.Transaction; +import java.sql.Timestamp; +import java.util.Map; + +/** + * ServiceSemaphore + */ +public class ServiceSemaphore { + + public static final String module = ServiceSemaphore.class.getName(); + public static final int SEMAPHORE_MODE_FAIL = 0; + public static final int SEMAPHORE_MODE_WAIT = 1; + public static final int SEMAPHORE_MODE_NONE = 2; + public static final long MAX_WAIT = 600; + public static final long SLEEP = 500; + + protected GenericDelegator delegator; + protected GenericValue lock; + protected ModelService model; + + protected int wait = 0; + protected int mode = 2; + + public ServiceSemaphore(GenericDelegator delegator, ModelService model) { + this.mode = "wait".equals(model.semaphore) ? 1 : ("fail".equals(model.semaphore) ? 0 : 2); + this.delegator = delegator; + this.model = model; + this.lock = null; + } + + public void acquire() throws SemaphoreWaitException, SemaphoreFailException { + if (mode == SEMAPHORE_MODE_NONE) return; + + String threadName = Thread.currentThread().getName(); + Timestamp lockTime = UtilDateTime.nowTimestamp(); + GenericValue semaphore; + + try { + semaphore = delegator.findByPrimaryKey("ServiceSemaphore", UtilMisc.toMap("serviceName", model.name)); + } catch (GenericEntityException e) { + throw new SemaphoreFailException(e); + } + + if (semaphore == null) { + Map fields = UtilMisc.toMap("serviceName", model.name, "lockThread", threadName, "lockTime", lockTime); + semaphore = delegator.makeValue("ServiceSemaphore", fields); + + // use the special method below so we can reuse the unqiue tx functions + dbWrite(semaphore, false); + } else { + waitOrFail(mode); + } + } + + public void release() throws SemaphoreFailException { + if (mode == SEMAPHORE_MODE_NONE) return; + + // remove the lock file + dbWrite(lock, true); + } + + private void waitOrFail(int mode) throws SemaphoreWaitException, SemaphoreFailException { + switch (mode) { + case SEMAPHORE_MODE_FAIL: + // fail + throw new SemaphoreFailException("Service [" + model.name + "] is locked"); + case SEMAPHORE_MODE_WAIT: + if (wait < MAX_WAIT) { + ++wait; + try { + Thread.sleep(SLEEP); + } catch (InterruptedException e) { + Debug.logInfo(e, "Sleep interrupted: ServiceSemaphone.waitOrFail()", module); + } + + // try again + acquire(); + break; + } else { + throw new SemaphoreWaitException("Service [" + model.name + "] wait timeout exceeded"); + } + case SEMAPHORE_MODE_NONE: + Debug.logWarning("Semaphore mode [none] attempted to aquire a lock; but should not have!", module); + break; + default: + throw new SemaphoreFailException(); + } + } + + private synchronized void dbWrite(GenericValue value, boolean delete) throws SemaphoreFailException { + Transaction parent = null; + boolean beganTx = false; + boolean isError = false; + + try { + // prepare the suspended transaction + parent = TransactionUtil.suspend(); + beganTx = TransactionUtil.begin(); + if (!beganTx) { + throw new SemaphoreFailException("Cannot obtain unique transaction for semaphore logging"); + } + + // store the value + try { + if (delete) { + value.refresh(); + value.remove(); + lock = null; + } else { + lock = value.create(); + } + } catch (GenericEntityException e) { + Debug.logError(e, module); + isError = true; + throw new SemaphoreFailException("Cannot obtain unique transaction for semaphore logging"); + } + } catch (GenericTransactionException e) { + Debug.logError(e, module); + } finally { + if (isError) { + try { + TransactionUtil.rollback(beganTx, "ServiceSemaphore: dbWrite()", new Exception()); + } catch (GenericTransactionException e) { + Debug.logError(e, module); + } + } + if (!isError && beganTx) { + try { + TransactionUtil.commit(beganTx); + } catch (GenericTransactionException e) { + Debug.logError(e, module); + } + } + if (parent != null) { + try { + TransactionUtil.resume(parent); + } catch (GenericTransactionException e) { + Debug.logError(e, module); + } + } + } + } +} Propchange: ofbiz/trunk/framework/service/src/org/ofbiz/service/semaphore/ServiceSemaphore.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: ofbiz/trunk/framework/service/src/org/ofbiz/service/semaphore/ServiceSemaphore.java ------------------------------------------------------------------------------ svn:keywords = "Date Rev Author URL Id" Propchange: ofbiz/trunk/framework/service/src/org/ofbiz/service/semaphore/ServiceSemaphore.java ------------------------------------------------------------------------------ svn:mime-type = text/plain |
Free forum by Nabble | Edit this page |