Package org.apache.ojb.odmg

Source Code of org.apache.ojb.odmg.J2EETransactionImpl

package org.apache.ojb.odmg;

/* Copyright 2002-2005 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import javax.transaction.Status;
import javax.transaction.Synchronization;

import org.apache.ojb.broker.PersistenceBroker;
import org.apache.ojb.broker.accesslayer.ConnectionManagerIF;
import org.apache.ojb.broker.util.logging.Logger;
import org.apache.ojb.broker.util.logging.LoggerFactory;
import org.odmg.LockNotGrantedException;
import org.odmg.ODMGRuntimeException;
import org.odmg.TransactionAbortedException;

/**
* Implementation for use in managed environments.
*
* @author <a href="mailto:mattbaird@yahoo.com">Matthew Baird</a>
* @version $Id: J2EETransactionImpl.java,v 1.25.2.7 2005/12/21 22:29:21 tomdz Exp $
*/
public class J2EETransactionImpl extends TransactionImpl implements Synchronization
{
    private Logger log = LoggerFactory.getLogger(J2EETransactionImpl.class);
    private boolean isInExternTransaction;

    /**
     * beforeCompletion is being called twice in JBoss, so this
     * isPrepared flag prevents code from executing twice.
     * todo: find out why it's being called twice and fix it.
     */
    private boolean beforeCompletionCall = false;
    private boolean afterCompletionCall = false;

    public J2EETransactionImpl(ImplementationImpl implementation)
    {
        super(implementation);
        isInExternTransaction = false;
    }

    public void setInExternTransaction(boolean mode)
    {
        isInExternTransaction = mode;
        }

    public boolean isInExternTransaction()
    {
        return isInExternTransaction;
    }

    public void join()
    {
            throw new UnsupportedOperationException("Not supported in managed enviroment");
        }

    public void leave()
    {
            throw new UnsupportedOperationException("Not supported in managed enviroment");
        }

    public void checkpoint()
    {
            throw new UnsupportedOperationException("Not supported in managed enviroment");
        }

    /**
     * FOR internal use. This method was called after the external transaction was completed.
     *
     * @see javax.transaction.Synchronization
     */
    public void afterCompletion(int status)
    {
        if(afterCompletionCall) return;

        log.info("Method afterCompletion was called");
        try
        {
            switch(status)
            {
                case Status.STATUS_COMMITTED:
                    if(log.isDebugEnabled())
                    {
                        log.debug("Method afterCompletion: Do commit internal odmg-tx, status of JTA-tx is " + TxUtil.getStatusString(status));
                    }
                    commit();
                    break;
                default:
                    log.error("Method afterCompletion: Do abort call on internal odmg-tx, status of JTA-tx is " + TxUtil.getStatusString(status));
                    abort();
            }
        }
        finally
        {
            afterCompletionCall = true;
            log.info("Method afterCompletion finished");
        }
    }

    /**
     * FOR internal use. This method was called before the external transaction was completed.
     *
     * This method was called by the JTA-TxManager before the JTA-tx prepare call. Within this method
     * we prepare odmg for commit and pass all modified persistent objects to DB and release/close the used
     * connection. We have to close the connection in this method, because the TxManager does prepare for commit
     * after this method and all used DataSource-connections have to be closed before.
     *
     * @see javax.transaction.Synchronization
     */
    public void beforeCompletion()
    {
        // avoid redundant calls
        if(beforeCompletionCall) return;

        log.info("Method beforeCompletion was called");
        int status = Status.STATUS_UNKNOWN;
        try
        {
            JTATxManager mgr = (JTATxManager) getImplementation().getTxManager();
            status = mgr.getJTATransaction().getStatus();
            // ensure proper work, check all possible status
            // normally only check for 'STATUS_MARKED_ROLLBACK' is necessary
            if(status == Status.STATUS_MARKED_ROLLBACK
                    || status == Status.STATUS_ROLLEDBACK
                    || status == Status.STATUS_ROLLING_BACK
                    || status == Status.STATUS_UNKNOWN
                    || status == Status.STATUS_NO_TRANSACTION)
            {
                log.error("Synchronization#beforeCompletion: Can't prepare for commit, because tx status was "
                        + TxUtil.getStatusString(status) + ". Do internal cleanup only.");
            }
            else
            {
                if(log.isDebugEnabled())
                {
                    log.debug("Synchronization#beforeCompletion: Prepare for commit");
                }
                // write objects to database
                prepareCommit();
            }
        }
        catch(Exception e)
        {
            log.error("Synchronization#beforeCompletion: Error while prepare for commit", e);
            if(e instanceof LockNotGrantedException)
            {
                throw (LockNotGrantedException) e;
            }
            else if(e instanceof TransactionAbortedException)
            {
                throw (TransactionAbortedException) e;
            }
            else if(e instanceof ODMGRuntimeException)
            {
                throw (ODMGRuntimeException) e;
            }
            else
            {
                throw new ODMGRuntimeException("Method beforeCompletion() fails, status of JTA-tx was "
                        + TxUtil.getStatusString(status) + ", message: " + e.getMessage());
            }

        }
        finally
        {
            beforeCompletionCall = true;
            setInExternTransaction(false);
            internalCleanup();
        }
    }

    /**
     * In managed environment do internal close the used connection
     */
    private void internalCleanup()
    {
        if(hasBroker())
        {
            PersistenceBroker broker = getBroker();
            if(log.isDebugEnabled())
            {
                log.debug("Do internal cleanup and close the internal used connection without" +
                        " closing the used broker");
            }
            ConnectionManagerIF cm = broker.serviceConnectionManager();
            if(cm.isInLocalTransaction())
            {
                /*
                arminw:
                in managed environment this call will be ignored because, the JTA transaction
                manager control the connection status. But to make connectionManager happy we
                have to complete the "local tx" of the connectionManager before release the
                connection
                */
                cm.localCommit();
            }
            cm.releaseConnection();
        }
    }

    public void commit()
    {
        try
        {
            // prepare for commit was done before on 'beforeCompleation' call
            if(log.isDebugEnabled()) log.debug("Commit transaction " + this + ", commit on broker " + broker);
            if(hasBroker())
            {
                getBroker().commitTransaction();
                doClose();
            }
            setStatus(Status.STATUS_COMMITTED);
            // Now, we notify everything the commit is done.
            performTransactionAwareAfterCommit();
        }
        catch(Exception ex)
        {
            // We should not reach this block
            log.error("Unexpected error while do commit on used PB-Instance and close resources", ex);
            abort();
        }
    }

    public void abort()
    {
        if(getStatus() == Status.STATUS_ROLLEDBACK) return;

        try
        {
            try
            {
                doAbort();
            }
            catch(Exception ignore)
            {
                log.error("Failure while do abort call", ignore);
            }

            getImplementation().getTxManager().abortExternalTx(this);

            try
            {
                doClose();
            }
            catch(Exception e)
            {
                log.error("Failure while do abort call", e);
            }
            setStatus(Status.STATUS_ROLLEDBACK);
        }
        finally
        {
            setInExternTransaction(false);
        }
    }
}
TOP

Related Classes of org.apache.ojb.odmg.J2EETransactionImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.