use of org.apache.ofbiz.entity.transaction.GenericTransactionException in project ofbiz-framework by apache.
the class LdapAuthenticationServices method userLogin.
public static boolean userLogin(DispatchContext ctx, Map<String, ?> context) {
if (Debug.verboseOn())
Debug.logVerbose("Starting LDAP authentication", module);
Properties env = UtilProperties.getProperties("jndiLdap");
String username = (String) context.get("login.username");
if (username == null) {
username = (String) context.get("username");
}
String password = (String) context.get("login.password");
if (password == null) {
password = (String) context.get("password");
}
String dn = null;
Delegator delegator = ctx.getDelegator();
boolean isServiceAuth = context.get("isServiceAuth") != null && ((Boolean) context.get("isServiceAuth")).booleanValue();
GenericValue userLogin = null;
try {
userLogin = EntityQuery.use(delegator).from("UserLogin").where("userLoginId", username).cache(isServiceAuth).queryOne();
} catch (GenericEntityException e) {
Debug.logWarning(e, "", module);
}
if (userLogin != null) {
dn = userLogin.getString("userLdapDn");
}
if (UtilValidate.isEmpty(dn)) {
String dnTemplate = (String) env.get("ldap.dn.template");
if (dnTemplate != null) {
dn = dnTemplate.replace("%u", username);
}
if (Debug.verboseOn())
Debug.logVerbose("Using DN template: " + dn, module);
} else {
if (Debug.verboseOn())
Debug.logVerbose("Using UserLogin.userLdapDn: " + dn, module);
}
env.put(Context.SECURITY_PRINCIPAL, dn);
env.put(Context.SECURITY_CREDENTIALS, password);
try {
// Create initial context
DirContext ldapCtx = new InitialDirContext(env);
ldapCtx.close();
} catch (NamingException e) {
if (Debug.verboseOn())
Debug.logVerbose("LDAP authentication failed: " + e.getMessage(), module);
return false;
}
if (Debug.verboseOn())
Debug.logVerbose("LDAP authentication succeeded", module);
if (!"true".equals(env.get("ldap.synchronize.passwords"))) {
return true;
}
// Synchronize user's OFBiz password with user's LDAP password
if (userLogin != null) {
boolean useEncryption = "true".equals(EntityUtilProperties.getPropertyValue("security", "password.encrypt", delegator));
String currentPassword = userLogin.getString("currentPassword");
boolean samePassword;
if (useEncryption) {
samePassword = HashCrypt.comparePassword(currentPassword, LoginServices.getHashType(), password);
} else {
samePassword = currentPassword.equals(password);
}
if (!samePassword) {
if (Debug.verboseOn())
Debug.logVerbose("Starting password synchronization", module);
userLogin.set("currentPassword", useEncryption ? HashCrypt.cryptUTF8(LoginServices.getHashType(), null, password) : password, false);
Transaction parentTx = null;
boolean beganTransaction = false;
try {
try {
parentTx = TransactionUtil.suspend();
} catch (GenericTransactionException e) {
Debug.logError(e, "Could not suspend transaction: " + e.getMessage(), module);
}
try {
beganTransaction = TransactionUtil.begin();
userLogin.store();
} catch (GenericEntityException e) {
Debug.logError(e, "Error saving UserLogin", module);
try {
TransactionUtil.rollback(beganTransaction, "Error saving UserLogin", e);
} catch (GenericTransactionException e2) {
Debug.logError(e2, "Could not rollback nested transaction: " + e2.getMessage(), module);
}
} finally {
try {
TransactionUtil.commit(beganTransaction);
if (Debug.verboseOn())
Debug.logVerbose("Password synchronized", module);
} catch (GenericTransactionException e) {
Debug.logError(e, "Could not commit nested transaction: " + e.getMessage(), module);
}
}
} finally {
if (parentTx != null) {
try {
TransactionUtil.resume(parentTx);
if (Debug.verboseOn())
Debug.logVerbose("Resumed the parent transaction.", module);
} catch (GenericTransactionException e) {
Debug.logError(e, "Could not resume parent nested transaction: " + e.getMessage(), module);
}
}
}
}
}
return true;
}
use of org.apache.ofbiz.entity.transaction.GenericTransactionException in project ofbiz-framework by apache.
the class EntitySyncContext method assembleKeysToRemove.
public LinkedList<GenericEntity> assembleKeysToRemove() throws SyncDataErrorException {
// get all removed items from the given time range, add to list for those
LinkedList<GenericEntity> keysToRemove = new LinkedList<GenericEntity>();
if (this.nextRemoveTxTime != null && (this.nextRemoveTxTime.equals(currentRunEndTime) || this.nextRemoveTxTime.after(currentRunEndTime))) {
// this means that for all entities in this pack we found on the last pass that there would be nothing for this one, so just return nothing...
return keysToRemove;
}
// Debug.logInfo("Getting keys to remove; currentRunStartTime=" + currentRunStartTime + ", currentRunEndTime=" + currentRunEndTime, module);
boolean beganTransaction = false;
try {
beganTransaction = TransactionUtil.begin(7200);
} catch (GenericTransactionException e) {
throw new SyncDataErrorException("Unable to begin JTA transaction", e);
}
try {
// find all instances of this entity with the STAMP_TX_FIELD != null, sort ascending to get lowest/oldest value first, then grab first and consider as candidate currentRunStartTime
EntityCondition findValCondition = EntityCondition.makeCondition(EntityCondition.makeCondition(ModelEntity.STAMP_TX_FIELD, EntityOperator.GREATER_THAN_EQUAL_TO, currentRunStartTime), EntityCondition.makeCondition(ModelEntity.STAMP_TX_FIELD, EntityOperator.LESS_THAN, currentRunEndTime));
EntityListIterator removeEli = EntityQuery.use(delegator).from("EntitySyncRemove").where(findValCondition).orderBy(ModelEntity.STAMP_TX_FIELD, ModelEntity.STAMP_FIELD).queryIterator();
GenericValue entitySyncRemove = null;
while ((entitySyncRemove = removeEli.next()) != null) {
// pull the PK from the EntitySyncRemove in the primaryKeyRemoved field, de-XML-serialize it
String primaryKeyRemoved = entitySyncRemove.getString("primaryKeyRemoved");
GenericEntity pkToRemove = null;
try {
pkToRemove = (GenericEntity) XmlSerializer.deserialize(primaryKeyRemoved, delegator);
} catch (IOException e) {
String errorMsg = "Error deserializing GenericPK to remove in Entity Sync Data for entitySyncId [" + entitySyncId + "] and entitySyncRemoveId [" + entitySyncRemove.getString("entitySyncRemoveId") + "]: " + e.toString();
Debug.logError(e, errorMsg, module);
throw new SyncDataErrorException(errorMsg, e);
} catch (SAXException e) {
String errorMsg = "Error deserializing GenericPK to remove in Entity Sync Data for entitySyncId [" + entitySyncId + "] and entitySyncRemoveId [" + entitySyncRemove.getString("entitySyncRemoveId") + "]: " + e.toString();
Debug.logError(e, errorMsg, module);
throw new SyncDataErrorException(errorMsg, e);
} catch (ParserConfigurationException e) {
String errorMsg = "Error deserializing GenericPK to remove in Entity Sync Data for entitySyncId [" + entitySyncId + "] and entitySyncRemoveId [" + entitySyncRemove.getString("entitySyncRemoveId") + "]: " + e.toString();
Debug.logError(e, errorMsg, module);
throw new SyncDataErrorException(errorMsg, e);
} catch (SerializeException e) {
String errorMsg = "Error deserializing GenericPK to remove in Entity Sync Data for entitySyncId [" + entitySyncId + "] and entitySyncRemoveId [" + entitySyncRemove.getString("entitySyncRemoveId") + "]: " + e.toString();
Debug.logError(e, errorMsg, module);
throw new SyncDataErrorException(errorMsg, e);
}
// set the stamp fields for future reference
pkToRemove.set(ModelEntity.STAMP_TX_FIELD, entitySyncRemove.get(ModelEntity.STAMP_TX_FIELD));
pkToRemove.set(ModelEntity.STAMP_FIELD, entitySyncRemove.get(ModelEntity.STAMP_FIELD));
pkToRemove.set(ModelEntity.CREATE_STAMP_TX_FIELD, entitySyncRemove.get(ModelEntity.CREATE_STAMP_TX_FIELD));
pkToRemove.set(ModelEntity.CREATE_STAMP_FIELD, entitySyncRemove.get(ModelEntity.CREATE_STAMP_FIELD));
if (this.entityNameToUseSet.contains(pkToRemove.getEntityName())) {
keysToRemove.add(pkToRemove);
}
}
removeEli.close();
// if we didn't find anything for this entity, find the next value's Timestamp and keep track of it
if (keysToRemove.size() == 0) {
EntityCondition findNextCondition = EntityCondition.makeCondition(ModelEntity.STAMP_TX_FIELD, EntityOperator.GREATER_THAN_EQUAL_TO, currentRunEndTime);
EntityListIterator eliNext = EntityQuery.use(delegator).from("EntitySyncRemove").where(findNextCondition).orderBy(ModelEntity.STAMP_TX_FIELD).queryIterator();
// get the first element and it's tx time value...
GenericValue firstVal = eliNext.next();
eliNext.close();
if (firstVal != null) {
Timestamp nextTxTime = firstVal.getTimestamp(ModelEntity.STAMP_TX_FIELD);
if (this.nextRemoveTxTime == null || nextTxTime.before(this.nextRemoveTxTime)) {
this.nextRemoveTxTime = nextTxTime;
}
}
}
} catch (GenericEntityException e) {
try {
TransactionUtil.rollback(beganTransaction, "Entity Engine error in assembleKeysToRemove", e);
} catch (GenericTransactionException e2) {
Debug.logWarning(e2, "Unable to call rollback()", module);
}
throw new SyncDataErrorException("Error getting keys to remove from the datasource", e);
} catch (Throwable t) {
try {
TransactionUtil.rollback(beganTransaction, "General error in assembleKeysToRemove", t);
} catch (GenericTransactionException e2) {
Debug.logWarning(e2, "Unable to call rollback()", module);
}
throw new SyncDataErrorException("Caught runtime error while getting keys to remove", t);
}
try {
TransactionUtil.commit(beganTransaction);
} catch (GenericTransactionException e) {
throw new SyncDataErrorException("Commit transaction failed", e);
}
// TEST SECTION: leave false for normal use
boolean logValues = false;
if (logValues && keysToRemove.size() > 0) {
StringBuilder toRemoveInfo = new StringBuilder();
for (GenericEntity keyToRemove : keysToRemove) {
toRemoveInfo.append("\n-->[");
toRemoveInfo.append(keyToRemove.get(ModelEntity.STAMP_TX_FIELD));
toRemoveInfo.append(":");
toRemoveInfo.append(keyToRemove.get(ModelEntity.STAMP_FIELD));
toRemoveInfo.append("] ");
toRemoveInfo.append(keyToRemove);
}
Debug.logInfo(toRemoveInfo.toString(), module);
}
// this calculation is false, so it needs to be nullified
if (keysToRemove.size() > 0) {
this.nextRemoveTxTime = null;
}
return keysToRemove;
}
use of org.apache.ofbiz.entity.transaction.GenericTransactionException in project ofbiz-framework by apache.
the class EntitySyncContext method assembleValuesToCreate.
public ArrayList<GenericValue> assembleValuesToCreate() throws SyncDataErrorException {
// first grab all values inserted in the date range, then get the updates (leaving out all values inserted in the data range)
// make it an ArrayList to easily merge in sorted lists
ArrayList<GenericValue> valuesToCreate = new ArrayList<GenericValue>();
if (this.nextCreateTxTime != null && (this.nextCreateTxTime.equals(currentRunEndTime) || this.nextCreateTxTime.after(currentRunEndTime))) {
// this means that for all entities in this pack we found on the last pass that there would be nothing for this one, so just return nothing...
return valuesToCreate;
}
// Debug.logInfo("Getting values to create; currentRunStartTime=" + currentRunStartTime + ", currentRunEndTime=" + currentRunEndTime, module);
int entitiesSkippedForKnownNext = 0;
// iterate through entities, get all records with tx stamp in the current time range, put all in a single list
for (ModelEntity modelEntity : entityModelToUseList) {
int insertBefore = 0;
// first test to see if we know that there are no records for this entity in this time period...
Timestamp knownNextCreateTime = this.nextEntityCreateTxTime.get(modelEntity.getEntityName());
if (knownNextCreateTime != null && (knownNextCreateTime.equals(currentRunEndTime) || knownNextCreateTime.after(currentRunEndTime))) {
// Debug.logInfo("In assembleValuesToCreate found knownNextCreateTime [" + knownNextCreateTime + "] after currentRunEndTime [" + currentRunEndTime + "], so skipping time per period for entity [" + modelEntity.getEntityName() + "]", module);
entitiesSkippedForKnownNext++;
continue;
}
boolean beganTransaction = false;
try {
beganTransaction = TransactionUtil.begin(7200);
} catch (GenericTransactionException e) {
throw new SyncDataErrorException("Unable to begin JTA transaction", e);
}
try {
EntityCondition findValCondition = EntityCondition.makeCondition(EntityCondition.makeCondition(ModelEntity.CREATE_STAMP_TX_FIELD, EntityOperator.GREATER_THAN_EQUAL_TO, currentRunStartTime), EntityCondition.makeCondition(ModelEntity.CREATE_STAMP_TX_FIELD, EntityOperator.LESS_THAN, currentRunEndTime));
EntityQuery eq = EntityQuery.use(delegator).from(modelEntity.getEntityName()).where(findValCondition).orderBy(ModelEntity.CREATE_STAMP_TX_FIELD, ModelEntity.CREATE_STAMP_FIELD);
long valuesPerEntity = 0;
try (EntityListIterator eli = eq.queryIterator()) {
// get the values created within the current time range
GenericValue nextValue = null;
while ((nextValue = eli.next()) != null) {
// find first value in valuesToCreate list, starting with the current insertBefore value, that has a CREATE_STAMP_TX_FIELD after the nextValue.CREATE_STAMP_TX_FIELD, then do the same with CREATE_STAMP_FIELD
while (insertBefore < valuesToCreate.size() && valuesToCreate.get(insertBefore).getTimestamp(ModelEntity.CREATE_STAMP_TX_FIELD).before(nextValue.getTimestamp(ModelEntity.CREATE_STAMP_TX_FIELD))) {
insertBefore++;
}
while (insertBefore < valuesToCreate.size() && valuesToCreate.get(insertBefore).getTimestamp(ModelEntity.CREATE_STAMP_FIELD).before(nextValue.getTimestamp(ModelEntity.CREATE_STAMP_FIELD))) {
insertBefore++;
}
valuesToCreate.add(insertBefore, nextValue);
valuesPerEntity++;
}
} catch (GenericEntityException e) {
try {
TransactionUtil.rollback(beganTransaction, "Entity Engine error in assembleValuesToCreate", e);
} catch (GenericTransactionException e2) {
Debug.logWarning(e2, "Unable to call rollback()", module);
}
throw new SyncDataErrorException("Error getting values to create from the datasource", e);
}
// if we didn't find anything for this entity, find the next value's Timestamp and keep track of it
if (valuesPerEntity == 0) {
Timestamp startCheckStamp = new Timestamp(System.currentTimeMillis() - syncEndBufferMillis);
EntityCondition findNextCondition = EntityCondition.makeCondition(EntityCondition.makeCondition(ModelEntity.CREATE_STAMP_TX_FIELD, EntityOperator.NOT_EQUAL, null), EntityCondition.makeCondition(ModelEntity.CREATE_STAMP_TX_FIELD, EntityOperator.GREATER_THAN_EQUAL_TO, currentRunEndTime));
eq = EntityQuery.use(delegator).from(modelEntity.getEntityName()).where(findNextCondition).orderBy(ModelEntity.CREATE_STAMP_TX_FIELD);
GenericValue firstVal = null;
try (EntityListIterator eliNext = eq.queryIterator()) {
// get the first element and it's tx time value...
firstVal = eliNext.next();
} catch (GenericEntityException e) {
try {
TransactionUtil.rollback(beganTransaction, "Entity Engine error in assembleValuesToCreate", e);
} catch (GenericTransactionException e2) {
Debug.logWarning(e2, "Unable to call rollback()", module);
}
throw new SyncDataErrorException("Error getting values to create from the datasource", e);
}
Timestamp nextTxTime;
if (firstVal != null) {
nextTxTime = firstVal.getTimestamp(ModelEntity.CREATE_STAMP_TX_FIELD);
} else {
// no results? well, then it's safe to say that up to the pre-querytime (minus the buffer, as usual) we are okay
nextTxTime = startCheckStamp;
}
if (this.nextCreateTxTime == null || nextTxTime.before(this.nextCreateTxTime)) {
this.nextCreateTxTime = nextTxTime;
Debug.logInfo("EntitySync: Set nextCreateTxTime to [" + nextTxTime + "]", module);
}
Timestamp curEntityNextTxTime = this.nextEntityCreateTxTime.get(modelEntity.getEntityName());
if (curEntityNextTxTime == null || nextTxTime.before(curEntityNextTxTime)) {
this.nextEntityCreateTxTime.put(modelEntity.getEntityName(), nextTxTime);
Debug.logInfo("EntitySync: Set nextEntityCreateTxTime to [" + nextTxTime + "] for the entity [" + modelEntity.getEntityName() + "]", module);
}
}
} catch (Throwable t) {
try {
TransactionUtil.rollback(beganTransaction, "Throwable error in assembleValuesToCreate", t);
} catch (GenericTransactionException e2) {
Debug.logWarning(e2, "Unable to call rollback()", module);
}
throw new SyncDataErrorException("Caught runtime error while getting values to create", t);
}
try {
TransactionUtil.commit(beganTransaction);
} catch (GenericTransactionException e) {
throw new SyncDataErrorException("Commit transaction failed", e);
}
}
if (entitiesSkippedForKnownNext > 0) {
if (Debug.infoOn())
Debug.logInfo("In assembleValuesToCreate skipped [" + entitiesSkippedForKnownNext + "/" + entityModelToUseList + "] entities for the time period ending at [" + currentRunEndTime + "] because of next known create times", module);
}
// TEST SECTION: leave false for normal use
boolean logValues = false;
if (logValues && valuesToCreate.size() > 0) {
StringBuilder toCreateInfo = new StringBuilder();
for (GenericValue valueToCreate : valuesToCreate) {
toCreateInfo.append("\n-->[");
toCreateInfo.append(valueToCreate.get(ModelEntity.CREATE_STAMP_TX_FIELD));
toCreateInfo.append(":");
toCreateInfo.append(valueToCreate.get(ModelEntity.CREATE_STAMP_FIELD));
toCreateInfo.append("] ");
toCreateInfo.append(valueToCreate.getPrimaryKey());
}
Debug.logInfo(toCreateInfo.toString(), module);
}
// this calculation is false, so it needs to be nullified
if (valuesToCreate.size() > 0) {
this.nextCreateTxTime = null;
}
return valuesToCreate;
}
use of org.apache.ofbiz.entity.transaction.GenericTransactionException in project ofbiz-framework by apache.
the class SimpleMethod method exec.
/**
* Execute the Simple Method operations
*/
public String exec(MethodContext methodContext) throws MiniLangException {
if (methodContext.isTraceOn()) {
outputTraceMessage(methodContext, "Begin simple-method. Script is running as " + (methodContext.getMethodType() == MethodContext.EVENT ? "an event." : "a service."));
}
Locale locale = methodContext.getLocale();
GenericValue userLogin = methodContext.getUserLogin();
if (loginRequired) {
if (userLogin == null) {
Map<String, Object> messageMap = UtilMisc.<String, Object>toMap("shortDescription", shortDescription);
String errMsg = UtilProperties.getMessage(SimpleMethod.err_resource, "simpleMethod.must_logged_process", messageMap, locale) + ".";
if (methodContext.isTraceOn()) {
outputTraceMessage(methodContext, "login-required attribute set to \"true\" but UserLogin GenericValue was not found, returning error message:", errMsg);
}
return returnError(methodContext, errMsg);
}
}
if (userLogin != null) {
methodContext.putEnv(getUserLoginEnvName(), userLogin);
}
methodContext.putEnv("nullField", GenericEntity.NULL_FIELD);
methodContext.putEnv(getDelegatorEnvName(), methodContext.getDelegator());
methodContext.putEnv(getSecurityEnvName(), methodContext.getSecurity());
methodContext.putEnv(getDispatcherEnvName(), methodContext.getDispatcher());
methodContext.putEnv("locale", locale);
methodContext.putEnv(getParameterMapName(), methodContext.getParameters());
if (methodContext.getMethodType() == MethodContext.EVENT) {
methodContext.putEnv(eventRequestName, methodContext.getRequest());
methodContext.putEnv(eventSessionName, methodContext.getRequest().getSession());
methodContext.putEnv(eventResponseName, methodContext.getResponse());
}
methodContext.putEnv("simpleMethod", this);
methodContext.putEnv("methodName", this.getMethodName());
methodContext.putEnv("methodShortDescription", this.getShortDescription());
// if using transaction, try to start here
boolean beganTransaction = false;
if (useTransaction) {
if (methodContext.isTraceOn()) {
outputTraceMessage(methodContext, "use-transaction attribute set to \"true\", beginning transaction.");
}
try {
beganTransaction = TransactionUtil.begin();
} catch (GenericTransactionException e) {
String errMsg = UtilProperties.getMessage(SimpleMethod.err_resource, "simpleMethod.error_begin_transaction", locale) + ": " + e.getMessage();
if (methodContext.isTraceOn()) {
outputTraceMessage(methodContext, "An exception was thrown while beginning a transaction, returning error message:", errMsg);
}
return returnError(methodContext, errMsg);
}
}
// declare errorMsg here just in case transaction ops fail
String errorMsg = "";
boolean finished = false;
try {
if (methodContext.isTraceOn()) {
outputTraceMessage(methodContext, "Begin running sub-elements.");
}
finished = runSubOps(methodOperations, methodContext);
} catch (Throwable t) {
// make SURE nothing gets thrown through
String errMsg = UtilProperties.getMessage(SimpleMethod.err_resource, "simpleMethod.error_running", locale) + ": " + t.getMessage();
if (methodContext.isTraceOn()) {
outputTraceMessage(methodContext, "An exception was thrown while running sub-elements, error message was:", errMsg);
}
finished = false;
errorMsg += errMsg;
}
if (methodContext.isTraceOn()) {
outputTraceMessage(methodContext, "End running sub-elements.");
}
String returnValue = null;
String response = null;
StringBuilder summaryErrorStringBuffer = new StringBuilder();
if (methodContext.getMethodType() == MethodContext.EVENT) {
boolean forceError = false;
String tempErrorMsg = (String) methodContext.getEnv(eventErrorMessageName);
if (errorMsg.length() > 0 || UtilValidate.isNotEmpty(tempErrorMsg)) {
errorMsg += tempErrorMsg;
methodContext.getRequest().setAttribute("_ERROR_MESSAGE_", errorMsg);
forceError = true;
summaryErrorStringBuffer.append(errorMsg);
}
List<Object> tempErrorMsgList = UtilGenerics.checkList(methodContext.getEnv(eventErrorMessageListName));
if (UtilValidate.isNotEmpty(tempErrorMsgList)) {
methodContext.getRequest().setAttribute("_ERROR_MESSAGE_LIST_", tempErrorMsgList);
forceError = true;
summaryErrorStringBuffer.append("; ");
summaryErrorStringBuffer.append(tempErrorMsgList.toString());
}
String eventMsg = (String) methodContext.getEnv(eventEventMessageName);
if (UtilValidate.isNotEmpty(eventMsg)) {
methodContext.getRequest().setAttribute("_EVENT_MESSAGE_", eventMsg);
}
List<String> eventMsgList = UtilGenerics.checkList(methodContext.getEnv(eventEventMessageListName));
if (UtilValidate.isNotEmpty(eventMsgList)) {
methodContext.getRequest().setAttribute("_EVENT_MESSAGE_LIST_", eventMsgList);
}
response = (String) methodContext.getEnv(eventResponseCodeName);
if (UtilValidate.isEmpty(response)) {
if (forceError) {
// override response code, always use error code
Debug.logInfo("No response code string found, but error messages found so assuming error; returning code [" + defaultErrorCode + "]", module);
response = defaultErrorCode;
} else {
Debug.logInfo("No response code string or errors found, assuming success; returning code [" + defaultSuccessCode + "]", module);
response = defaultSuccessCode;
}
} else if ("null".equalsIgnoreCase(response)) {
response = null;
}
returnValue = response;
} else {
boolean forceError = false;
String tempErrorMsg = (String) methodContext.getEnv(serviceErrorMessageName);
if (errorMsg.length() > 0 || UtilValidate.isNotEmpty(tempErrorMsg)) {
errorMsg += tempErrorMsg;
methodContext.putResult(ModelService.ERROR_MESSAGE, errorMsg);
forceError = true;
summaryErrorStringBuffer.append(errorMsg);
}
List<Object> errorMsgList = UtilGenerics.checkList(methodContext.getEnv(serviceErrorMessageListName));
if (UtilValidate.isNotEmpty(errorMsgList)) {
methodContext.putResult(ModelService.ERROR_MESSAGE_LIST, errorMsgList);
forceError = true;
summaryErrorStringBuffer.append("; ");
summaryErrorStringBuffer.append(errorMsgList.toString());
}
Map<String, Object> errorMsgMap = UtilGenerics.checkMap(methodContext.getEnv(serviceErrorMessageMapName));
if (UtilValidate.isNotEmpty(errorMsgMap)) {
methodContext.putResult(ModelService.ERROR_MESSAGE_MAP, errorMsgMap);
forceError = true;
summaryErrorStringBuffer.append("; ");
summaryErrorStringBuffer.append(errorMsgMap.toString());
}
String successMsg = (String) methodContext.getEnv(serviceSuccessMessageName);
if (UtilValidate.isNotEmpty(successMsg)) {
methodContext.putResult(ModelService.SUCCESS_MESSAGE, successMsg);
}
List<Object> successMsgList = UtilGenerics.checkList(methodContext.getEnv(serviceSuccessMessageListName));
if (UtilValidate.isNotEmpty(successMsgList)) {
methodContext.putResult(ModelService.SUCCESS_MESSAGE_LIST, successMsgList);
}
response = (String) methodContext.getEnv(serviceResponseMessageName);
if (UtilValidate.isEmpty(response)) {
if (forceError) {
// override response code, always use error code
if (Debug.verboseOn())
Debug.logVerbose("No response code string found, but error messages found so assuming error; returning code [" + defaultErrorCode + "]", module);
response = defaultErrorCode;
} else {
if (Debug.verboseOn())
Debug.logVerbose("No response code string or errors found, assuming success; returning code [" + defaultSuccessCode + "]", module);
response = defaultSuccessCode;
}
}
methodContext.putResult(ModelService.RESPONSE_MESSAGE, response);
returnValue = response;
}
// decide whether or not to commit based on the response message, ie only rollback if error is returned and not finished
boolean doCommit = true;
if (!finished && defaultErrorCode.equals(response)) {
doCommit = false;
}
if (doCommit) {
if (methodContext.isTraceOn()) {
outputTraceMessage(methodContext, "Begin commit transaction.");
}
// commit here passing beganTransaction to perform it properly
try {
TransactionUtil.commit(beganTransaction);
} catch (GenericTransactionException e) {
String errMsg = "Error trying to commit transaction, could not process method: " + e.getMessage();
if (methodContext.isTraceOn()) {
outputTraceMessage(methodContext, "An exception was thrown while committing a transaction, returning error message:", errMsg);
}
errorMsg += errMsg;
}
} else {
if (methodContext.isTraceOn()) {
outputTraceMessage(methodContext, "Begin roll back transaction.");
}
// rollback here passing beganTransaction to either rollback, or set rollback only
try {
TransactionUtil.rollback(beganTransaction, "Error in simple-method [" + this.getShortDescription() + "]: " + summaryErrorStringBuffer, null);
} catch (GenericTransactionException e) {
String errMsg = "Error trying to rollback transaction, could not process method: " + e.getMessage();
if (methodContext.isTraceOn()) {
outputTraceMessage(methodContext, "An exception was thrown while rolling back a transaction, returning error message:", errMsg);
}
errorMsg += errMsg;
}
}
if (methodContext.isTraceOn()) {
outputTraceMessage(methodContext, "End simple-method.");
}
return returnValue;
}
use of org.apache.ofbiz.entity.transaction.GenericTransactionException in project ofbiz-framework by apache.
the class ServiceDispatcher method runSync.
/**
* Run the service synchronously and return the result.
* @param localName Name of the context to use.
* @param modelService Service model object.
* @param params Map of name, value pairs composing the parameters.
* @param validateOut Validate OUT parameters
* @return Map of name, value pairs composing the result.
* @throws ServiceAuthException
* @throws ServiceValidationException
* @throws GenericServiceException
*/
public Map<String, Object> runSync(String localName, ModelService modelService, Map<String, ? extends Object> params, boolean validateOut) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
long serviceStartTime = System.currentTimeMillis();
Map<String, Object> result = new HashMap<>();
ServiceSemaphore lock = null;
Map<String, List<ServiceEcaRule>> eventMap = null;
Map<String, Object> ecaContext = null;
RunningService rs = null;
DispatchContext ctx = localContext.get(localName);
GenericEngine engine = null;
Transaction parentTransaction = null;
boolean isFailure = false;
boolean isError = false;
boolean beganTrans = false;
try {
// check for semaphore and acquire a lock
if ("wait".equals(modelService.semaphore) || "fail".equals(modelService.semaphore)) {
lock = new ServiceSemaphore(delegator, modelService);
lock.acquire();
}
if (Debug.verboseOn() || modelService.debug) {
if (Debug.verboseOn())
Debug.logVerbose("[ServiceDispatcher.runSync] : invoking service " + modelService.name + " [" + modelService.location + "/" + modelService.invoke + "] (" + modelService.engineName + ")", module);
}
Map<String, Object> context = new HashMap<>();
if (params != null) {
context.putAll(params);
}
// check the locale
Locale locale = this.checkLocale(context);
// set up the running service log
rs = this.logService(localName, modelService, GenericEngine.SYNC_MODE);
// get eventMap once for all calls for speed, don't do event calls if it is null
eventMap = ServiceEcaUtil.getServiceEventMap(modelService.name);
engine = this.getGenericEngine(modelService.engineName);
modelService.informIfDeprecated();
// set IN attributes with default-value as applicable
modelService.updateDefaultValues(context, ModelService.IN_PARAM);
if (modelService.useTransaction) {
if (TransactionUtil.isTransactionInPlace()) {
// if a new transaction is needed, do it here; if not do nothing, just use current tx
if (modelService.requireNewTransaction) {
parentTransaction = TransactionUtil.suspend();
if (TransactionUtil.isTransactionInPlace()) {
throw new GenericTransactionException("In service " + modelService.name + " transaction is still in place after suspend, status is " + TransactionUtil.getStatusString());
}
// now start a new transaction
beganTrans = TransactionUtil.begin(modelService.transactionTimeout);
}
} else {
beganTrans = TransactionUtil.begin(modelService.transactionTimeout);
}
// enlist for XAResource debugging
if (beganTrans && TransactionUtil.debugResources()) {
DebugXaResource dxa = new DebugXaResource(modelService.name);
try {
dxa.enlist();
} catch (Exception e) {
Debug.logError(e, module);
}
}
}
try {
int lockRetriesRemaining = LOCK_RETRIES;
boolean needsLockRetry = false;
do {
// Ensure this is reset to false on each pass
needsLockRetry = false;
lockRetriesRemaining--;
// setup global transaction ECA listeners to execute later
if (eventMap != null) {
ServiceEcaUtil.evalRules(modelService.name, eventMap, "global-rollback", ctx, context, result, isError, isFailure);
}
if (eventMap != null) {
ServiceEcaUtil.evalRules(modelService.name, eventMap, "global-commit", ctx, context, result, isError, isFailure);
}
// pre-auth ECA
if (eventMap != null) {
ServiceEcaUtil.evalRules(modelService.name, eventMap, "auth", ctx, context, result, isError, isFailure);
}
// check for pre-auth failure/errors
isFailure = ServiceUtil.isFailure(result);
isError = ServiceUtil.isError(result);
context = checkAuth(localName, context, modelService);
GenericValue userLogin = (GenericValue) context.get("userLogin");
if (modelService.auth && userLogin == null) {
throw new ServiceAuthException("User authorization is required for this service: " + modelService.name + modelService.debugInfo());
}
// now that we have authed, if there is a userLogin, set the EE userIdentifier
if (userLogin != null && userLogin.getString("userLoginId") != null) {
GenericDelegator.pushUserIdentifier(userLogin.getString("userLoginId"));
}
// pre-validate ECA
if (eventMap != null) {
ServiceEcaUtil.evalRules(modelService.name, eventMap, "in-validate", ctx, context, result, isError, isFailure);
}
// check for pre-validate failure/errors
isFailure = ServiceUtil.isFailure(result);
isError = ServiceUtil.isError(result);
// validate the context
if (modelService.validate && !isError && !isFailure) {
try {
modelService.validate(context, ModelService.IN_PARAM, locale);
} catch (ServiceValidationException e) {
Debug.logError(e, "Incoming context (in runSync : " + modelService.name + ") does not match expected requirements", module);
throw e;
}
}
// pre-invoke ECA
if (eventMap != null) {
ServiceEcaUtil.evalRules(modelService.name, eventMap, "invoke", ctx, context, result, isError, isFailure);
}
// check for pre-invoke failure/errors
isFailure = ServiceUtil.isFailure(result);
isError = ServiceUtil.isError(result);
// ===== invoke the service =====
if (!isError && !isFailure) {
Map<String, Object> invokeResult = null;
invokeResult = engine.runSync(localName, modelService, context);
engine.sendCallbacks(modelService, context, invokeResult, GenericEngine.SYNC_MODE);
if (invokeResult != null) {
result.putAll(invokeResult);
} else {
Debug.logWarning("Service (in runSync : " + modelService.name + ") returns null result", module);
}
}
// re-check the errors/failures
isFailure = ServiceUtil.isFailure(result);
isError = ServiceUtil.isError(result);
if (beganTrans) {
// crazy stuff here: see if there was a deadlock or other such error and if so retry... which we can ONLY do if we own the transaction!
String errMsg = ServiceUtil.getErrorMessage(result);
// service is written to not ignore it of course!
if (errMsg != null && errMsg.toUpperCase(Locale.getDefault()).indexOf("DEADLOCK") >= 0) {
// it's a deadlock! retry...
String retryMsg = "RETRYING SERVICE [" + modelService.name + "]: Deadlock error found in message [" + errMsg + "]; retry [" + (LOCK_RETRIES - lockRetriesRemaining) + "] of [" + LOCK_RETRIES + "]";
// make sure the old transaction is rolled back, and then start a new one
// if there is an exception in these things, let the big overall thing handle it
TransactionUtil.rollback(beganTrans, retryMsg, null);
beganTrans = TransactionUtil.begin(modelService.transactionTimeout);
// enlist for XAResource debugging
if (beganTrans && TransactionUtil.debugResources()) {
DebugXaResource dxa = new DebugXaResource(modelService.name);
try {
dxa.enlist();
} catch (Exception e) {
Debug.logError(e, module);
}
}
if (!beganTrans) {
// just log and let things roll through, will be considered an error and ECAs, etc will run according to that
Debug.logError("After rollback attempt for lock retry did not begin a new transaction!", module);
} else {
// deadlocks can be resolved by retring immediately as conflicting operations in the other thread will have cleared
needsLockRetry = true;
// reset state variables
result = new HashMap<>();
isFailure = false;
isError = false;
Debug.logWarning(retryMsg, module);
}
// - MySQL ? lock wait timeout string: "Lock wait timeout exceeded; try restarting transaction"
if (errMsg.indexOf("A lock could not be obtained within the time requested") >= 0 || errMsg.indexOf("Lock wait timeout exceeded") >= 0) {
// TODO: add to run after parent tx
}
}
}
} while (needsLockRetry && lockRetriesRemaining > 0);
// create a new context with the results to pass to ECA services; necessary because caller may reuse this context
ecaContext = new HashMap<>();
ecaContext.putAll(context);
// copy all results: don't worry parameters that aren't allowed won't be passed to the ECA services
ecaContext.putAll(result);
// setup default OUT values
modelService.updateDefaultValues(context, ModelService.OUT_PARAM);
// validate the result
if (modelService.validate && validateOut) {
// pre-out-validate ECA
if (eventMap != null) {
ServiceEcaUtil.evalRules(modelService.name, eventMap, "out-validate", ctx, ecaContext, result, isError, isFailure);
}
try {
modelService.validate(result, ModelService.OUT_PARAM, locale);
} catch (ServiceValidationException e) {
throw new GenericServiceException("Outgoing result (in runSync : " + modelService.name + ") does not match expected requirements", e);
}
}
// pre-commit ECA
if (eventMap != null) {
ServiceEcaUtil.evalRules(modelService.name, eventMap, "commit", ctx, ecaContext, result, isError, isFailure);
}
// check for pre-commit failure/errors
isFailure = ServiceUtil.isFailure(result);
isError = ServiceUtil.isError(result);
// global-commit-post-run ECA, like global-commit but gets the context after the service is run
if (eventMap != null) {
ServiceEcaUtil.evalRules(modelService.name, eventMap, "global-commit-post-run", ctx, ecaContext, result, isError, isFailure);
}
// check for failure and log on info level; this is used for debugging
if (isFailure) {
Debug.logWarning("Service Failure [" + modelService.name + "]: " + ServiceUtil.getErrorMessage(result), module);
}
} catch (Throwable t) {
if (Debug.timingOn()) {
UtilTimer.closeTimer(localName + " / " + modelService.name, "Sync service failed...", module);
}
String errMsg = "Service [" + modelService.name + "] threw an unexpected exception/error";
engine.sendCallbacks(modelService, context, t, GenericEngine.SYNC_MODE);
try {
TransactionUtil.rollback(beganTrans, errMsg, t);
} catch (GenericTransactionException te) {
Debug.logError(te, "Cannot rollback transaction", module);
}
rs.setEndStamp();
if (t instanceof ServiceAuthException) {
throw (ServiceAuthException) t;
} else if (t instanceof ServiceValidationException) {
throw (ServiceValidationException) t;
} else if (t instanceof GenericServiceException) {
throw (GenericServiceException) t;
} else {
throw new GenericServiceException("Service [" + modelService.name + "] Failed" + modelService.debugInfo(), t);
}
} finally {
// if there was an error, rollback transaction, otherwise commit
if (isError) {
String errMsg = "Error in Service [" + modelService.name + "]: " + ServiceUtil.getErrorMessage(result);
Debug.logError(errMsg, module);
// rollback the transaction
try {
TransactionUtil.rollback(beganTrans, errMsg, null);
} catch (GenericTransactionException e) {
Debug.logError(e, "Could not rollback transaction: " + e.toString(), module);
}
} else {
// commit the transaction
try {
TransactionUtil.commit(beganTrans);
} catch (GenericTransactionException e) {
GenericDelegator.popUserIdentifier();
String errMsg = "Could not commit transaction for service [" + modelService.name + "] call";
Debug.logError(e, errMsg, module);
if (e.getMessage() != null) {
errMsg = errMsg + ": " + e.getMessage();
}
throw new GenericServiceException(errMsg);
}
}
// call notifications -- event is determined from the result (success, error, fail)
modelService.evalNotifications(this.getLocalContext(localName), context, result);
// clear out the EE userIdentifier
GenericDelegator.popUserIdentifier();
}
} catch (GenericTransactionException te) {
Debug.logError(te, "Problems with the transaction", module);
throw new GenericServiceException("Problems with the transaction.", te.getNested());
} finally {
if (lock != null) {
// release the semaphore lock
try {
lock.release();
} catch (GenericServiceException e) {
Debug.logWarning(e, "Exception thrown while unlocking semaphore: ", module);
}
}
// resume the parent transaction
if (parentTransaction != null) {
try {
TransactionUtil.resume(parentTransaction);
} catch (GenericTransactionException ite) {
Debug.logWarning(ite, "Transaction error, not resumed", module);
throw new GenericServiceException("Resume transaction exception, see logs");
}
}
}
// pre-return ECA
if (eventMap != null) {
ServiceEcaUtil.evalRules(modelService.name, eventMap, "return", ctx, ecaContext, result, isError, isFailure);
}
rs.setEndStamp();
long timeToRun = System.currentTimeMillis() - serviceStartTime;
long showServiceDurationThreshold = UtilProperties.getPropertyAsLong("service", "showServiceDurationThreshold", 0);
long showSlowServiceThreshold = UtilProperties.getPropertyAsLong("service", "showSlowServiceThreshold", 1000);
if (Debug.timingOn() && timeToRun > showServiceDurationThreshold) {
Debug.logTiming("Sync service [" + localName + "/" + modelService.name + "] finished in [" + timeToRun + "] milliseconds", module);
} else if (Debug.infoOn() && timeToRun > showSlowServiceThreshold) {
Debug.logTiming("Slow sync service execution detected: service [" + localName + "/" + modelService.name + "] finished in [" + timeToRun + "] milliseconds", module);
}
if ((Debug.verboseOn() || modelService.debug) && timeToRun > 50 && !modelService.hideResultInLog) {
// Sanity check - some service results can be multiple MB in size. Limit message size to 10K.
String resultStr = result.toString();
if (resultStr.length() > 10240) {
resultStr = resultStr.substring(0, 10226) + "...[truncated]";
}
if (Debug.verboseOn())
Debug.logVerbose("Sync service [" + localName + "/" + modelService.name + "] finished with response [" + resultStr + "]", module);
}
if (modelService.metrics != null) {
modelService.metrics.recordServiceRate(1, timeToRun);
}
return result;
}
Aggregations