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;
}
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;
}
}
}
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;
}
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);
}
}
Aggregations