Search in sources :

Example 6 with GenericTransactionException

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;
}
Also used : GenericValue(org.apache.ofbiz.entity.GenericValue) Delegator(org.apache.ofbiz.entity.Delegator) Transaction(javax.transaction.Transaction) GenericEntityException(org.apache.ofbiz.entity.GenericEntityException) GenericTransactionException(org.apache.ofbiz.entity.transaction.GenericTransactionException) NamingException(javax.naming.NamingException) DirContext(javax.naming.directory.DirContext) InitialDirContext(javax.naming.directory.InitialDirContext) InitialDirContext(javax.naming.directory.InitialDirContext) Properties(java.util.Properties) UtilProperties(org.apache.ofbiz.base.util.UtilProperties) EntityUtilProperties(org.apache.ofbiz.entity.util.EntityUtilProperties)

Example 7 with GenericTransactionException

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;
}
Also used : GenericValue(org.apache.ofbiz.entity.GenericValue) SerializeException(org.apache.ofbiz.entity.serialize.SerializeException) EntityCondition(org.apache.ofbiz.entity.condition.EntityCondition) IOException(java.io.IOException) Timestamp(java.sql.Timestamp) LinkedList(java.util.LinkedList) SAXException(org.xml.sax.SAXException) GenericEntity(org.apache.ofbiz.entity.GenericEntity) GenericEntityException(org.apache.ofbiz.entity.GenericEntityException) GenericTransactionException(org.apache.ofbiz.entity.transaction.GenericTransactionException) EntityListIterator(org.apache.ofbiz.entity.util.EntityListIterator) ParserConfigurationException(javax.xml.parsers.ParserConfigurationException)

Example 8 with GenericTransactionException

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;
}
Also used : GenericValue(org.apache.ofbiz.entity.GenericValue) EntityCondition(org.apache.ofbiz.entity.condition.EntityCondition) ArrayList(java.util.ArrayList) EntityQuery(org.apache.ofbiz.entity.util.EntityQuery) Timestamp(java.sql.Timestamp) GenericEntityException(org.apache.ofbiz.entity.GenericEntityException) GenericTransactionException(org.apache.ofbiz.entity.transaction.GenericTransactionException) ModelEntity(org.apache.ofbiz.entity.model.ModelEntity) EntityListIterator(org.apache.ofbiz.entity.util.EntityListIterator)

Example 9 with GenericTransactionException

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;
}
Also used : Locale(java.util.Locale) GenericValue(org.apache.ofbiz.entity.GenericValue) GenericTransactionException(org.apache.ofbiz.entity.transaction.GenericTransactionException)

Example 10 with GenericTransactionException

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;
}
Also used : Locale(java.util.Locale) GenericValue(org.apache.ofbiz.entity.GenericValue) ConcurrentLinkedHashMap(com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap) HashMap(java.util.HashMap) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) SecurityConfigurationException(org.apache.ofbiz.security.SecurityConfigurationException) GeneralRuntimeException(org.apache.ofbiz.base.util.GeneralRuntimeException) GenericConfigException(org.apache.ofbiz.base.config.GenericConfigException) JobManagerException(org.apache.ofbiz.service.job.JobManagerException) GenericTransactionException(org.apache.ofbiz.entity.transaction.GenericTransactionException) GenericEntityException(org.apache.ofbiz.entity.GenericEntityException) DebugXaResource(org.apache.ofbiz.entity.transaction.DebugXaResource) ServiceSemaphore(org.apache.ofbiz.service.semaphore.ServiceSemaphore) Transaction(javax.transaction.Transaction) GenericTransactionException(org.apache.ofbiz.entity.transaction.GenericTransactionException) LinkedList(java.util.LinkedList) List(java.util.List) GenericEngine(org.apache.ofbiz.service.engine.GenericEngine)

Aggregations

GenericTransactionException (org.apache.ofbiz.entity.transaction.GenericTransactionException)49 GenericValue (org.apache.ofbiz.entity.GenericValue)37 GenericEntityException (org.apache.ofbiz.entity.GenericEntityException)35 Delegator (org.apache.ofbiz.entity.Delegator)24 Locale (java.util.Locale)18 EntityListIterator (org.apache.ofbiz.entity.util.EntityListIterator)18 HashMap (java.util.HashMap)14 Timestamp (java.sql.Timestamp)13 GenericServiceException (org.apache.ofbiz.service.GenericServiceException)12 LocalDispatcher (org.apache.ofbiz.service.LocalDispatcher)12 Transaction (javax.transaction.Transaction)11 Map (java.util.Map)10 IOException (java.io.IOException)9 LinkedList (java.util.LinkedList)9 GeneralException (org.apache.ofbiz.base.util.GeneralException)6 EntityCondition (org.apache.ofbiz.entity.condition.EntityCondition)5 ModelEntity (org.apache.ofbiz.entity.model.ModelEntity)5 EntityQuery (org.apache.ofbiz.entity.util.EntityQuery)5 HttpSession (javax.servlet.http.HttpSession)4 List (java.util.List)3