Search in sources :

Example 6 with TransactionField

use of org.jaffa.transaction.domain.TransactionField in project jaffa-framework by jaffa-projects.

the class TransactionConsumer method process.

/**
 * This method is invoked directly when processing a Transaction synchronously.
 * It'll invoke the handler associated with the input transaction's payload, as obtained from the transaction configuration file.
 * In case of an error, the status of the transaction will be set to 'E'.
 *
 * @param uow                the provided uow.
 * @param transactionId      the transaction ID.
 * @param unsavedTransaction the transaction if available, otherwise null.
 */
public UOW process(UOW uow, String transactionId, Transaction unsavedTransaction) throws Exception {
    if (log.isDebugEnabled()) {
        log.debug("Processing Transaction " + transactionId);
    }
    // Update Transaction status to I
    Boolean postImmediate = Parser.parseBoolean((String) ContextManagerFactory.instance().getProperty(Transaction.RULE_POST_IMMEDIATE));
    // If the postImmediate is true then we shall make the update to the transaction within same scope of the UOW as this must be synchronous transaction
    if (postImmediate != null && postImmediate.booleanValue()) {
        if (unsavedTransaction == null) {
            // This transaction must already be in the database.
            TransactionEngine.getInstance().updateTransactionStatusToInProcess(uow, transactionId);
        } else {
            uow.flush();
            unsavedTransaction.setStatus(Transaction.Status.I.name());
        }
    } else {
        TransactionEngine.getInstance().updateTransactionStatusToInProcess(transactionId);
    }
    boolean createdLoggingContext = false;
    try {
        Transaction transaction = unsavedTransaction != null ? unsavedTransaction : Transaction.findByPK(uow, transactionId);
        Object dataBean = transaction.getTransactionPayloadObject() != null ? transaction.getTransactionPayloadObject().moldInternalPayload() : null;
        TransactionInfo transactionInfo = null;
        if (dataBean != null) {
            // Load transaction configuration
            transactionInfo = ConfigurationService.getInstance().getTransactionInfo(dataBean);
            // Sets Log4J's MDC to enable BusinessEventLogging
            LoggingService.setLoggingContext(dataBean, transactionInfo, transaction);
            createdLoggingContext = true;
            if (log.isInfoEnabled()) {
                log.info(MessageHelper.findMessage("label.Jaffa.Transaction.TransactionConsumer.start", null));
            }
            int retryLimit = readRule(RULE_RETRY_LIMIT, DEFAULT_RETRY_LIMIT);
            int retrySleepTimeInMillis = readRule(RULE_RETRY_SLEEP_TIME, DEFAULT_RETRY_SLEEP_TIME);
            int retryCount = 0;
            while (true) {
                try {
                    // Invokes the handler as specified by the 'toClass and toMethod' combination in the transaction configuration
                    invokeHandler(uow, transactionInfo, dataBean);
                    break;
                } catch (Exception e) {
                    if (postImmediate == null || !postImmediate.booleanValue()) {
                        // Retry only if the exception is listed as a retryable exception
                        String[] exceptions = readRule(RETRY_EXCEPTION_RULE, DEFAULT_RETRY_EXCEPTIONS);
                        Exception ex = null;
                        Class<Exception> clazz = null;
                        for (String exceptionName : exceptions) {
                            if (log.isDebugEnabled()) {
                                log.debug("Exception: " + exceptionName + " defined as a retryable exception.");
                            }
                            clazz = (Class<Exception>) Class.forName(exceptionName);
                            ex = clazz.cast(ExceptionHelper.extractException(e, clazz));
                            if (ex != null) {
                                break;
                            }
                        }
                        if (ex != null && ++retryCount <= retryLimit) {
                            if (log.isDebugEnabled()) {
                                log.debug(clazz.getSimpleName() + " encountered. Will sleep for " + retrySleepTimeInMillis + " milliseconds and then retry", e);
                            }
                            uow.rollback();
                            Thread.sleep(retrySleepTimeInMillis);
                            uow = new UOW();
                            if (log.isDebugEnabled()) {
                                log.debug("Retry#" + retryCount);
                            }
                        } else {
                            throw e;
                        }
                    } else {
                        throw e;
                    }
                }
            }
            if (log.isInfoEnabled()) {
                log.info(MessageHelper.findMessage("label.Jaffa.Transaction.TransactionConsumer.success", null));
            }
        } else {
            if (log.isDebugEnabled()) {
                log.debug("There is no payload for the Transaction. Hence nothing to process.");
            }
        }
        TransactionField[] transactionFields = transaction.getTransactionFieldArray();
        boolean keep = false;
        if (transactionFields != null) {
            for (TransactionField tField : transactionFields) {
                if (KEEP.equals(tField.getFieldName()) && Boolean.parseBoolean(tField.getValue())) {
                    keep = true;
                    break;
                }
            }
        }
        if (log.isDebugEnabled()) {
            log.info("Finished with transaction: " + transactionId);
        }
        // Commit the UOW if it isn't a post immediate to catch any exceptions that might occur
        if (postImmediate == null || !postImmediate.booleanValue()) {
            if (keep) // Update Transaction status to S
            {
                TransactionEngine.getInstance().updateTransactionStatusToSatisfied(uow, transactionId);
            } else // Delete Transaction Record
            {
                TransactionEngine.getInstance().deleteTransaction(uow, transactionId);
            }
            try {
                uow.commit();
            } catch (Exception e) {
                log.error("Error committing UOW in TransactionConsumer.process", e);
                throw e;
            }
        } else {
            uow.flush();
            TransactionMessageDAOFactory.getTransactionMessageDAO().delete(uow, transaction);
        }
        if (log.isDebugEnabled()) {
            log.debug("Successfully processed Transaction " + transaction);
        }
    } catch (Exception e) {
        // Update Transaction status to E
        if (log.isInfoEnabled()) {
            log.info(MessageHelper.findMessage("label.Jaffa.Transaction.TransactionConsumer.error", null));
        }
        // Rollback the UOW if there is an error
        if (postImmediate == null || !postImmediate.booleanValue()) {
            try {
                uow.rollback();
            } catch (Exception exception) {
                log.error("Error rolling back UOW in transaction consumer");
            }
        }
        // Only need to update the transaction if the process is being run asynchronously.
        if (postImmediate == null || !postImmediate.booleanValue()) {
            // release the UOWs connection before creating a new one to move this transaction to the error state
            uow.rollback();
            // Update Transaction status to E
            TransactionEngine.getInstance().updateTransactionStatusToError(transactionId, e);
            log.error(MessageHelper.findMessage("label.Jaffa.Transaction.TransactionConsumer.error", null), e);
        }
        throw e;
    } finally {
        // Unset the Logging context
        if (createdLoggingContext) {
            LoggingService.unsetLoggingContext();
        }
    }
    return uow;
}
Also used : Transaction(org.jaffa.transaction.domain.Transaction) TransactionInfo(org.jaffa.transaction.services.configdomain.TransactionInfo) TransactionField(org.jaffa.transaction.domain.TransactionField) UOW(org.jaffa.persistence.UOW)

Example 7 with TransactionField

use of org.jaffa.transaction.domain.TransactionField in project jaffa-framework by jaffa-projects.

the class TransactionMessagingEngine method processTransactions.

/**
 * Any internally queued {@link Transaction} needs a corresponding JMS message submitted.
 * Prior versions did this in the postAdd() of the Transaction domain object.
 * <p/>
 * This location is now one of a few places that should be using the JmsClientHelper.send() method.
 * The other place(s) are:
 * - In the drl files for sending messages to topic queues (resources/rules/jaffa/soa/SOAEventService.drl)
 */
private void processTransactions() throws FrameworkException, ApplicationExceptions {
    log.debug("Need to Write JMS for buffered Transactions. BufferSize=" + m_transactions.size());
    // send each transaction to the JmsClientHelper
    for (Transaction transaction : m_transactions.values()) {
        // if the transaction is not defined, skip it
        if (transaction == null) {
            continue;
        }
        // if the direction is not "IN", skip this transaction
        if ((transaction.getDirection() != null) && !Direction.IN.toString().equals(transaction.getDirection())) {
            log.debug("Transaction: " + transaction.getId() + " is not an IN transaction, it will be skipped.");
            continue;
        }
        // if the status is not "O", skip this transaction
        if ((transaction.getStatus() != null) && !Status.O.toString().equals(transaction.getStatus())) {
            log.debug("Transaction: " + transaction.getId() + " is not OPEN, it will be skipped.");
            continue;
        }
        // try to submit the transaction
        try {
            // see if a scheduled ID is defined for this transaction
            String scheduledId = null;
            TransactionField[] transactionFields = transaction.getTransactionFieldArray();
            if (transactionFields != null) {
                for (TransactionField field : transaction.getTransactionFieldArray()) {
                    if ("JaffaTransactionInvokerScheduledTaskId".equals(field.getFieldName())) {
                        scheduledId = field.getValue();
                        break;
                    }
                }
            }
            // send the transaction to the JMS queue to be consumed
            getSender().send(new TransactionMessage(transaction), transaction.getCreatedBy(), scheduledId, null);
        } catch (Exception e) {
            // If there is a failure to put the transaction in the JMS queue, set the transaction to error
            Boolean postImmediate = Parser.parseBoolean((String) ContextManagerFactory.instance().getProperty(Transaction.RULE_POST_IMMEDIATE));
            if (postImmediate == null || !postImmediate.booleanValue()) {
                TransactionEngine.getInstance().updateTransactionStatusToError(transaction.getId(), e);
            }
            // Handle case where an application exception caused the issue
            ApplicationExceptions appExps = ExceptionHelper.extractApplicationExceptions(e);
            if (appExps != null) {
                log.error(MessageHelper.findMessage("exception.org.jaffa.modules.messaging.services.JaffaMessagingFrameworkException.jmsTransactionError", new Object[] { transaction }), appExps);
                TransactionEngine.getInstance().updateTransactionStatusToError(transaction.getId(), appExps);
                throw appExps;
            }
            // If the originating exception is not an application exception log it
            log.error(MessageHelper.findMessage("exception.org.jaffa.modules.messaging.services.JaffaMessagingFrameworkException.jmsTransactionError", new Object[] { transaction }), e);
            // Create a framework exception and rethrow
            FrameworkException frameworkException = new JaffaMessagingFrameworkException(JaffaMessagingFrameworkException.JMS_TRANSACTION_ERROR, new Object[] { transaction }, e);
            if (postImmediate == null || !postImmediate.booleanValue()) {
                TransactionEngine.getInstance().updateTransactionStatusToError(transaction.getId(), frameworkException);
            }
            // Throw the framework exception and exit
            throw frameworkException;
        }
    }
}
Also used : ApplicationExceptions(org.jaffa.exceptions.ApplicationExceptions) Transaction(org.jaffa.transaction.domain.Transaction) FrameworkException(org.jaffa.exceptions.FrameworkException) JaffaMessagingFrameworkException(org.jaffa.modules.messaging.services.JaffaMessagingFrameworkException) JaffaMessagingFrameworkException(org.jaffa.modules.messaging.services.JaffaMessagingFrameworkException) TransactionField(org.jaffa.transaction.domain.TransactionField) FrameworkException(org.jaffa.exceptions.FrameworkException) JaffaMessagingFrameworkException(org.jaffa.modules.messaging.services.JaffaMessagingFrameworkException)

Example 8 with TransactionField

use of org.jaffa.transaction.domain.TransactionField in project jaffa-framework by jaffa-projects.

the class JaffaTransactionMessageService method getTransactionFields.

/**
 * Gets the TransactionField collection of the Transaction with the input ID.
 *
 * @param transactionId the ID of the Transaction to return the TransactionFields of
 * @return the TransactionFields of the Transaction with the input ID
 * @throws FrameworkException
 */
@Override
public Collection<TransactionField> getTransactionFields(String transactionId) throws FrameworkException {
    UOW uow = null;
    List<TransactionField> results = new ArrayList<TransactionField>();
    try {
        uow = new UOW();
        Criteria criteria = new Criteria();
        criteria.setTable(TransactionFieldMeta.getName());
        criteria.addCriteria(TransactionFieldMeta.TRANSACTION_ID, transactionId);
        for (Object result : uow.query(criteria)) {
            results.add((TransactionField) result);
        }
    } finally {
        if (uow != null) {
            uow.close();
        }
    }
    return results;
}
Also used : ArrayList(java.util.ArrayList) TransactionField(org.jaffa.transaction.domain.TransactionField) Criteria(org.jaffa.persistence.Criteria) TransactionFieldCriteria(org.jaffa.transaction.apis.data.TransactionFieldCriteria) AtomicCriteria(org.jaffa.persistence.AtomicCriteria) TransactionCriteria(org.jaffa.transaction.apis.data.TransactionCriteria) UOW(org.jaffa.persistence.UOW)

Example 9 with TransactionField

use of org.jaffa.transaction.domain.TransactionField in project jaffa-framework by jaffa-projects.

the class LoggingService method setLoggingContext.

/**
 * Adds the appropriate elements to the Message Driven Context (MDC) of Log4J, as specified in the input transaction config.
 * @param payload Any serializable object.
 * @param transactionInfo the corresponding TransactionInfo object, as specified in the configuration file.
 */
public static void setLoggingContext(Object payload, TransactionInfo transactionInfo, Transaction transaction) {
    // Push the current MDC context into the thread-level stack
    Map<String, Object> currentLoggingContext = MDC.getContext() != null ? new HashMap<String, Object>(MDC.getContext()) : new HashMap<String, Object>();
    Stack<Map<String, Object>> stack = t_loggingContext.get();
    if (stack == null) {
        stack = new Stack<Map<String, Object>>();
        t_loggingContext.set(stack);
    }
    stack.push(currentLoggingContext);
    // If not passed, determine the transactionInfo based on the payload
    if (transactionInfo == null && payload != null)
        transactionInfo = ConfigurationService.getInstance().getTransactionInfo(payload);
    // Add elements to the MDC, based on the presence of loggingNames in the header information of the transaction configuration
    if (transactionInfo != null && transactionInfo.getHeader() != null && transactionInfo.getHeader().getParam() != null) {
        for (Param param : transactionInfo.getHeader().getParam()) {
            if (param.getLoggingName() != null) {
                String key = param.getLoggingName().value();
                try {
                    Object value = TransactionEngine.obtainParamValue(param, payload);
                    if (value != null)
                        MDC.put(key, value);
                    else
                        MDC.remove(key);
                } catch (Exception e) {
                    if (log.isDebugEnabled())
                        log.debug("Error in obtaining value for the LoggingName " + key, e);
                }
            }
        }
    }
    // Add some standard elements to the MDC
    if (MDC.get(BusinessEventLogMeta.CORRELATION_TYPE) == null && transaction != null && transaction.getId() != null) {
        MDC.put(BusinessEventLogMeta.CORRELATION_TYPE, DEFAULT_CORRELATION_TYPE);
        MDC.put(BusinessEventLogMeta.CORRELATION_KEY1, transaction.getId());
        if (transaction.getType() != null)
            MDC.put(BusinessEventLogMeta.CORRELATION_KEY2, transaction.getType());
        if (transaction.getSubType() != null)
            MDC.put(BusinessEventLogMeta.CORRELATION_KEY3, transaction.getSubType());
        if (transaction.getCreatedBy() != null)
            MDC.put(BusinessEventLogMeta.LOGGED_BY, transaction.getCreatedBy());
    }
    // Add transactionId as the message id
    if (transaction != null && transaction.getId() != null)
        MDC.put(BusinessEventLogMeta.MESSAGE_ID, transaction.getId());
    try {
        // Add in scheduledTaskId to MDC if it has been passed in as TransactionField
        if (transaction.getTransactionFieldArray() != null) {
            for (TransactionField tField : transaction.getTransactionFieldArray()) {
                if ("JaffaTransactionInvokerScheduledTaskId".equals(tField.getFieldName()))
                    MDC.put(BusinessEventLogMeta.SCHEDULED_TASK_ID, tField.getValue());
            }
        }
    } catch (Exception e) {
        if (log.isDebugEnabled())
            log.debug("Unable to fetch transaction field array from transaction", e);
    }
}
Also used : Param(org.jaffa.transaction.services.configdomain.Param) TransactionField(org.jaffa.transaction.domain.TransactionField) Map(java.util.Map) HashMap(java.util.HashMap)

Aggregations

TransactionField (org.jaffa.transaction.domain.TransactionField)9 UOW (org.jaffa.persistence.UOW)5 AtomicCriteria (org.jaffa.persistence.AtomicCriteria)3 Criteria (org.jaffa.persistence.Criteria)3 TransactionCriteria (org.jaffa.transaction.apis.data.TransactionCriteria)3 TransactionFieldCriteria (org.jaffa.transaction.apis.data.TransactionFieldCriteria)3 TransactionInfo (org.jaffa.transaction.services.configdomain.TransactionInfo)3 HashMap (java.util.HashMap)2 LinkedHashMap (java.util.LinkedHashMap)2 Map (java.util.Map)2 FrameworkException (org.jaffa.exceptions.FrameworkException)2 JaffaMessagingFrameworkException (org.jaffa.modules.messaging.services.JaffaMessagingFrameworkException)2 Transaction (org.jaffa.transaction.domain.Transaction)2 Param (org.jaffa.transaction.services.configdomain.Param)2 Method (java.lang.reflect.Method)1 ArrayList (java.util.ArrayList)1 LinkedList (java.util.LinkedList)1 ApplicationException (org.jaffa.exceptions.ApplicationException)1 ApplicationExceptions (org.jaffa.exceptions.ApplicationExceptions)1 IllegalPersistentStateRuntimeException (org.jaffa.persistence.exceptions.IllegalPersistentStateRuntimeException)1