All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.drools.persistence.jta.JtaTransactionManager Maven / Gradle / Ivy

There is a newer version: 9.44.0.Final
Show newest version
/*
 * Copyright 2011 JBoss Inc
 *
 * 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.
 */
package org.drools.persistence.jta;

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

import org.drools.persistence.TransactionManager;
import org.drools.persistence.TransactionSynchronization;
import org.drools.persistence.TransactionSynchronizationRegistryHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class JtaTransactionManager
    implements
    TransactionManager {

    Logger                               logger                                            = LoggerFactory.getLogger( getClass() );

    public static final String           DEFAULT_USER_TRANSACTION_NAME                     = "java:comp/UserTransaction";

    public static final String[]         FALLBACK_TRANSACTION_MANAGER_NAMES                = new String[]{"java:comp/TransactionManager", "java:appserver/TransactionManager", "java:pm/TransactionManager", "java:/TransactionManager", System.getProperty("jbpm.tm.jndi.lookup")};

    /**
     * Standard Java EE 5 JNDI location for the JTA TransactionSynchronizationRegistry.
     * Autodetected when available.
     */
    public static final String           DEFAULT_TRANSACTION_SYNCHRONIZATION_REGISTRY_NAME = "java:comp/TransactionSynchronizationRegistry";

    private static final String          TRANSACTION_SYNCHRONIZATION_REGISTRY_CLASS_NAME   = "javax.transaction.TransactionSynchronizationRegistry";

    private static Class< ? >            transactionSynchronizationRegistryClass;

    static {
        ClassLoader cl = JtaTransactionManager.class.getClassLoader();
        try {
            transactionSynchronizationRegistryClass = cl.loadClass( TRANSACTION_SYNCHRONIZATION_REGISTRY_CLASS_NAME );
        } catch ( ClassNotFoundException e ) {
            // JTA 1.1 API not available... simply proceed the JTA 1.0 way.
        }
    }

    UserTransaction                      ut;
    Object                               tsr;
    javax.transaction.TransactionManager tm;
    
    public JtaTransactionManager(Object ut,
                                 Object tsr,
                                 Object tm) {
        if ( ut instanceof UserTransaction ) {
            this.ut = ( UserTransaction ) ut;
        } else {
            this.ut = ( UserTransaction ) ( (ut != null) ? ut : findUserTransaction() );
        }
        
        if ( tm instanceof javax.transaction.TransactionManager ) {
            this.tm = ( javax.transaction.TransactionManager ) tm;
        } else {
            this.tm = ( javax.transaction.TransactionManager ) ( (tm != null) ? tm : findTransactionManager( this.ut ) );
        }
        this.tsr = (tsr != null) ? tsr : findTransactionSynchronizationRegistry( this.ut,
                                                                                 this.tm );
    }

    protected javax.transaction.TransactionManager findTransactionManager(UserTransaction ut) {
        if ( ut instanceof TransactionManager ) {
            logger.debug( "JTA UserTransaction object [{}] implements TransactionManager",
                          ut );
            return (javax.transaction.TransactionManager) ut;
        }

        InitialContext context = null;

        try {
            context = new InitialContext();
        } catch ( NamingException ex ) {
            logger.debug( "Could not initialise JNDI InitialContext",
                          ex );
            return null;
        }

        // Check fallback JNDI locations.
        for ( String jndiName : FALLBACK_TRANSACTION_MANAGER_NAMES ) {
            if (jndiName == null) {
                continue;
            }
            try {
                javax.transaction.TransactionManager tm = (javax.transaction.TransactionManager) context.lookup( jndiName );
                logger.debug( "JTA TransactionManager found at fallback JNDI location [{}]",
                              jndiName );
                return tm;
            } catch ( NamingException ex ) {
                logger.debug( "No JTA TransactionManager found at fallback JNDI location [{}]",
                              jndiName,
                              ex );
            }
        }

        // OK, so no JTA TransactionManager is available...
        return null;
    }

    protected UserTransaction findUserTransaction() {
        try {
            InitialContext context = new InitialContext();
            return (UserTransaction) context.lookup( DEFAULT_USER_TRANSACTION_NAME );
        } catch ( NamingException ex ) {
            logger.debug( "No UserTransaction found at JNDI location [{}]", DEFAULT_USER_TRANSACTION_NAME, ex );
            // no user transaction found in default location try alternative ones
            // on some app servers access to default UT is not allowed from non manged thread, e.g. timers
            try {
                return InitialContext.doLookup(System.getProperty("jbpm.ut.jndi.lookup", "java:jboss/UserTransaction"));
            } catch (Exception e1) {
                throw new IllegalStateException("Unable to find transaction: " + ex.getMessage(), ex);
            }

        }
    }

    protected Object findTransactionSynchronizationRegistry(UserTransaction ut,
                                                            javax.transaction.TransactionManager tm) {

        if ( transactionSynchronizationRegistryClass == null ) {
            // JTA 1.1 API not present - skip.
            logger.debug( "JTA 1.1 [{}] API not available",
                          TRANSACTION_SYNCHRONIZATION_REGISTRY_CLASS_NAME );
            return null;
        }

        String jndiName = DEFAULT_TRANSACTION_SYNCHRONIZATION_REGISTRY_NAME;
        try {
            InitialContext context = new InitialContext();
            Object tsrObject = context.lookup( jndiName );
            logger.debug( "JTA TransactionSynchronizationRegistry found at default JNDI location [{}]",
                          jndiName );
            return tsrObject;
        } catch ( NamingException ex ) {
            logger.debug( "No JTA TransactionSynchronizationRegistry found at default JNDI location [{}]",
                          jndiName,
                          ex );
        }
        // Check whether the UserTransaction or TransactionManager implements it...
        if ( transactionSynchronizationRegistryClass.isInstance( ut ) ) {
            return ut;
        }
        if ( transactionSynchronizationRegistryClass.isInstance( tm ) ) {
            return tm;
        }
        // OK, so no JTA 1.1 TransactionSynchronizationRegistry is available,
        // despite the API being present...
        return null;
    }

    public boolean begin() {
        if ( getStatus() == TransactionManager.STATUS_NO_TRANSACTION ) {
            try {
                this.ut.begin();
                return true;
            } catch ( Exception e ) {
                logger.warn( "Unable to begin transaction", e);
                throw new RuntimeException( "Unable to begin transaction",
                                            e );
            }
        } 
        return false;
    }

    public void commit(boolean transactionOwner) {
        if ( transactionOwner ) {
            try {
                this.ut.commit();
            } catch ( Exception e ) {
                logger.warn( "Unable to commit transaction", e);
                throw new RuntimeException( "Unable to commit transaction",
                                            e );
            }
        } 
    }
    
    public void rollback(boolean transactionOwner) {
        try {
        	if (transactionOwner) {
        		// transaction can be already rolled back,
        		// exception thrown during beforeCompletion cycle can cause transaction rollback
        		if (ut.getStatus() != Status.STATUS_NO_TRANSACTION) {
            		this.ut.rollback();
        		}
        	} else {
        		this.ut.setRollbackOnly();
        	}
        } catch ( Exception e ) {
            logger.warn( "Unable to rollback transaction", e);
            throw new RuntimeException( "Unable to rollback transaction",
                                        e );
        }
    }

    public int getStatus() {
        int s;
        try {
            s = this.ut.getStatus();
        } catch ( SystemException e ) {
            throw new RuntimeException( "Unable to get status for transaction",
                                        e );
        }

        switch ( s ) {
            case Status.STATUS_COMMITTED :
                return TransactionManager.STATUS_COMMITTED;
            case Status.STATUS_ROLLEDBACK :
                return TransactionManager.STATUS_ROLLEDBACK;
            case Status.STATUS_NO_TRANSACTION :
                return TransactionManager.STATUS_NO_TRANSACTION;
            default :
                return TransactionManager.STATUS_UNKNOWN;
        }
    }

    public void registerTransactionSynchronization(final TransactionSynchronization ts) {
        if ( this.tsr != null ) {
            TransactionSynchronizationRegistryHelper.registerTransactionSynchronization( this.tsr,
                                                                                         ts );
        } else if ( this.tm != null ) {
            try {
                this.tm.getTransaction().registerSynchronization( new JtaTransactionSynchronizationAdapter( ts ) );
            } catch ( Exception e ) {
                // No JTA TransactionManager available - log a warning.
                logger.warn( "Participating in existing JTA transaction, but no JTA TransactionManager or TransactionSychronizationRegistry available: ",
                             e );

            }
        } else {
            // No JTA TransactionManager available - log a warning.
            logger.warn( "Participating in existing JTA transaction, but no JTA TransactionManager or TransactionSychronizationRegistry available: " );
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy