org.eclipse.ecr.core.event.tx.EventBundleTransactionHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.ecr.core.event.tx.EventBundleTransactionHandler.java

Source

/*
 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Thierry Delprat
 *     Florent Guillaume
 */

package org.eclipse.ecr.core.event.tx;

import static javax.transaction.Status.STATUS_ACTIVE;
import static javax.transaction.Status.STATUS_COMMITTED;
import static javax.transaction.Status.STATUS_MARKED_ROLLBACK;
import static javax.transaction.Status.STATUS_ROLLEDBACK;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.transaction.Status;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.ecr.runtime.transaction.TransactionHelper;

/**
 * Helper class to encapsulate Transaction management.
 *
 * @author Thierry Delprat
 * @author Florent Guillaume
 */
public class EventBundleTransactionHandler {

    private static final Log log = LogFactory.getLog(EventBundleTransactionHandler.class);

    protected UserTransaction tx;

    protected boolean disabled;

    public void beginNewTransaction() {
        beginNewTransaction(null);
    }

    public void beginNewTransaction(Integer transactionTimeout) {
        if (disabled) {
            return;
        }
        if (tx != null) {
            throw new UnsupportedOperationException("There is already an uncommited transaction running");
        }
        tx = createUT(transactionTimeout);
        if (tx == null) {
            log.debug("No TransactionManager");
            disabled = true;
            return;
        }
        try {
            if (tx.getStatus() == STATUS_COMMITTED) {
                log.error("Transaction is already commited, try to begin anyway");
            }
            tx.begin();
        } catch (Exception e) {
            log.error("Unable to start transaction", e);
        }
    }

    protected UserTransaction createUT(Integer transactionTimeout) {
        return createUT(transactionTimeout, false);
    }

    protected UserTransaction createUT(Integer transactionTimeout, boolean retry) {
        try {
            new InitialContext();
        } catch (Exception e) {
            disabled = true;
            return null;
        }

        UserTransaction ut;
        try {
            ut = TransactionHelper.lookupUserTransaction();
        } catch (NamingException e) {
            disabled = true;
            return null;
        }

        try {
            int txStatus = ut.getStatus();
            if (txStatus != Status.STATUS_NO_TRANSACTION && !retry) {
                // if previous tx in this thread aborted in TimeOut
                // Ajuna may have failed to dissociate tx from thread context
                // => force rollback to avoid reusing a dead tx
                log.warn(
                        "Transaction was not properly cleanup up from thread context, rolling back before getting a new tx");
                try {
                    ut.rollback();
                } catch (Throwable t) {
                    log.warn("error during tx rollback", t);
                }
                return createUT(transactionTimeout, true);
            }
        } catch (Exception se) {
            log.warn("Error while getting TX status", se);
        }

        if (transactionTimeout != null) {
            try {
                ut.setTransactionTimeout(transactionTimeout);
            } catch (SystemException e) {
                log.error("Error while setting transaction timeout to " + transactionTimeout, e);
            }
        }
        return ut;
    }

    protected boolean isUTTransactionActive() {
        try {
            return tx.getStatus() == STATUS_ACTIVE;
        } catch (SystemException e) {
            log.error("Error while getting tx status", e);
            return false;
        }
    }

    private boolean isUTTransactionMarkedRollback() {
        try {
            int status = tx.getStatus();
            return status == STATUS_MARKED_ROLLBACK || status == STATUS_ROLLEDBACK;
        } catch (SystemException e) {
            log.error("Error while getting tx status", e);
            return false;
        }
    }

    public void rollbackTransaction() {
        if (disabled || tx == null) {
            return;
        }
        try {
            if (!isUTTransactionMarkedRollback()) {
                tx.setRollbackOnly();
            }
            commitOrRollbackTransaction();
        } catch (Exception e) {
            log.error("Error while marking tx for rollback", e);
        } finally {
            tx = null;
        }
    }

    public void commitOrRollbackTransaction() {
        if (disabled || tx == null) {
            return;
        }
        try {
            if (isUTTransactionActive()) {
                try {
                    tx.commit();
                } catch (Exception e) {
                    log.error("Error during commit", e);
                }
            } else {
                try {
                    log.debug("Rolling back transaction");
                    tx.rollback();
                } catch (Exception e) {
                    // if the transaction was already rolledback due to
                    // transaction timeout, we must still call tx.rollback but
                    // this causes a spurious error message, so log at debug
                    // level
                    log.debug("Error during rollback", e);
                }
            }
        } finally {
            tx = null;
        }
    }

}