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

com.atomikos.icatch.standalone.UserTransactionServiceImp Maven / Gradle / Ivy

There is a newer version: 6.0.0
Show newest version
/**
 * Copyright (C) 2000-2010 Atomikos 
 *
 * This code ("Atomikos TransactionsEssentials"), by itself,
 * is being distributed under the
 * Apache License, Version 2.0 ("License"), a copy of which may be found at
 * http://www.atomikos.com/licenses/apache-license-2.0.txt .
 * You may not use this file except in compliance with the License.
 *
 * While the License grants certain patent license rights,
 * those patent license rights only extend to the use of
 * Atomikos TransactionsEssentials by itself.
 *
 * This code (Atomikos TransactionsEssentials) contains certain interfaces
 * in package (namespace) com.atomikos.icatch
 * (including com.atomikos.icatch.Participant) which, if implemented, may
 * infringe one or more patents held by Atomikos.
 * It should be appreciated that you may NOT implement such interfaces;
 * licensing to implement these interfaces must be obtained separately from Atomikos.
 *
 * 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.
 */

package com.atomikos.icatch.standalone;

import static com.atomikos.util.Atomikos.VERSION;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileLock;
import java.nio.channels.OverlappingFileLockException;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Stack;

import javax.naming.Context;
import javax.transaction.UserTransaction;

import com.atomikos.icatch.ExportingTransactionManager;
import com.atomikos.icatch.ImportingTransactionManager;
import com.atomikos.icatch.SysException;
import com.atomikos.icatch.admin.LogAdministrator;
import com.atomikos.icatch.admin.imp.LocalLogAdministrator;
import com.atomikos.icatch.config.TSInitInfo;
import com.atomikos.icatch.config.TSMetaData;
import com.atomikos.icatch.config.UserTransactionService;
import com.atomikos.icatch.config.imp.AbstractUserTransactionServiceFactory;
import com.atomikos.icatch.config.imp.TSInitInfoImp;
import com.atomikos.icatch.config.imp.TSMetaDataImp;
import com.atomikos.icatch.imp.BaseTransactionManager;
import com.atomikos.icatch.imp.thread.TaskManager;
import com.atomikos.icatch.jta.AbstractJtaUserTransactionService;
import com.atomikos.icatch.jta.J2eeUserTransaction;
import com.atomikos.icatch.jta.JTA;
import com.atomikos.icatch.jta.TransactionManagerImp;
import com.atomikos.icatch.jta.UserTransactionServerImp;
import com.atomikos.icatch.system.Configuration;
import com.atomikos.logging.Logger;
import com.atomikos.logging.LoggerFactory;
import com.atomikos.persistence.StateRecoveryManager;
import com.atomikos.persistence.imp.StateRecoveryManagerImp;

/**
 *
 *
 * A standalone implementation of the UserTransactionManager interface.
 */

class UserTransactionServiceImp extends AbstractJtaUserTransactionService
{
	private static final Logger LOGGER = LoggerFactory.createLogger(UserTransactionServiceImp.class);

    private static final String PRODUCT_NAME = "TransactionsEssentials";
    // the product name as it should be in the license.

    // the current release number to be checked in license

    // private StandAloneTransactionManager tm_ = null;
    // the TM to use

    private File lockfile_ = null;
    // the lockfile to guard against double startup

	private FileOutputStream lockfilestream_ = null;
    private FileLock lock_ = null;

    private TSInitInfo info_ = null;
    // the info object that was used

    // private UserTransactionServerImp utxs_ = null;
    // not null if client demarcation allowed

    // REMOVED IN 2.0
    // private UserTransaction utx_ = null;
    // the user tx

    private Properties properties_;



    UserTransactionServiceImp ( Properties properties )
    {

        properties_ = getDefaultProperties ();
        Enumeration enumm = properties.propertyNames ();
        while ( enumm.hasMoreElements () ) {
            String name = (String) enumm.nextElement ();
            String property = properties.getProperty ( name );
            properties_.setProperty ( name, property );
        }

        if ( System
                .getProperty ( com.atomikos.icatch.config.UserTransactionServiceImp.NO_FILE_PROPERTY_NAME ) != null ) {

            enumm = properties_.propertyNames ();
            Stack names = new Stack ();
            while ( enumm.hasMoreElements () ) {
                String name = (String) enumm.nextElement ();
                names.push ( name );
            }
            while ( !names.empty () ) {
                String name = (String) names.pop ();
                if ( System.getProperty ( name ) != null ) {
                    properties_
                            .setProperty ( name, System.getProperty ( name ) );
                }
            }

        }
    }

    /**
     * Get the properties supplied at init time.
     *
     * @return Properties The properties.
     */

    private Properties getProperties ()
    {
        return properties_;

    }

    /**
     * Creates a default TM instance.
     *
     * @param p
     *            The properties to use.
     * @return StandAloneTransactionManager The default instance.
     * @exception IOException
     *                On IO error.
     * @exception FileNotFoundException
     *                If the config file could not be found.
     */

    private StandAloneTransactionManager createDefault ( Properties p )
            throws IOException, FileNotFoundException
    {
        StandAloneTransactionManager ret = null;

        String logname = getTrimmedProperty (
                AbstractUserTransactionServiceFactory.LOG_BASE_NAME_PROPERTY_NAME, p );
        String logdir = getTrimmedProperty (
                AbstractUserTransactionServiceFactory.LOG_BASE_DIR_PROPERTY_NAME, p );
        logdir = findOrCreateFolder ( logdir );

        String recoveryPrefs = getTrimmedProperty (
                AbstractUserTransactionServiceFactory.ENABLE_LOGGING_PROPERTY_NAME, p );
        boolean enableRecovery = true;
        if ( "false".equals ( recoveryPrefs ) )
            enableRecovery = false;

        String threadedCommitPrefs = getTrimmedProperty ( AbstractUserTransactionServiceFactory.THREADED_2PC_PROPERTY_NAME , p );
        boolean threadedCommit = true;
        if ( "false".equals( threadedCommitPrefs )) threadedCommit = false;

        // make sure that no other instance is running with the same log
        // by setting a lock file
        lockfile_ = new File(logdir,logname + ".lck");
        //lockfile_ = new File ( logdir + logname + ".lck" );

        if ( enableRecovery ) {
        	 //ISSUE 10077: don't complain about lock file if no logging
        	try {
        		lockfilestream_ = new FileOutputStream ( lockfile_ );
        		lock_ = lockfilestream_.getChannel().tryLock();
        		lockfile_.deleteOnExit();
        	} catch ( OverlappingFileLockException failedToGetLock ) {
        		//happens on windows
        		lock_ = null;
        	} catch ( IOException failedToGetLock ) {
        		//happens on windows
        		lock_ = null;
        	}
        	if ( lock_ == null ) {
        		 System.err.println ( "ERROR: the specified log seems to be "
                         + "in use already. Make sure that no other instance is "
                         + "running, or kill any pending process if needed." );
                 throw new RuntimeException ( "Log already in use?" );
        	}
        }

        int max = Integer.valueOf( getTrimmedProperty (
                AbstractUserTransactionServiceFactory.MAX_ACTIVES_PROPERTY_NAME, p ) );

        StateRecoveryManager recmgr = new StateRecoveryManagerImp();
        long maxTimeout = Long.valueOf( getTrimmedProperty (
                AbstractUserTransactionServiceFactory.MAX_TIMEOUT_PROPERTY_NAME, p ) );

        long defaultTimeoutInMillis = Long.valueOf( getTrimmedProperty (
                AbstractUserTransactionServiceFactory.DEFAULT_JTA_TIMEOUT_PROPERTY_NAME, p ) );
        int defaultTimeout = 0;

        defaultTimeout = (int) defaultTimeoutInMillis/1000;
        if ( defaultTimeout <= 0 ) {
        	LOGGER.logWarning ( "WARNING: " + AbstractUserTransactionServiceFactory.DEFAULT_JTA_TIMEOUT_PROPERTY_NAME + " should be more than 1000 milliseconds - resetting to 10000 milliseconds instead..." );
        	defaultTimeout = 10;
        }


        TransactionManagerImp.setDefaultTimeout(defaultTimeout);


        String name = getTrimmedProperty (
                AbstractUserTransactionServiceFactory.TM_UNIQUE_NAME_PROPERTY_NAME, p );
        if ( name == null || name.equals ( "" ) )
            throw new SysException (
                    "Property not set: com.atomikos.icatch.tm_unique_name" );
        ret = new StandAloneTransactionManager ( name, recmgr,
                logdir, maxTimeout, max, !threadedCommit );

        // set default serial mode for JTA txs.
        if ( new Boolean ( getTrimmedProperty (
                UserTransactionServiceFactory.SERIAL_JTA_TRANSACTIONS_PROPERTY_NAME, p ) )
                .booleanValue () )
            TransactionManagerImp.setDefaultSerial ( true );

        return ret;
    }



    public void init ( TSInitInfo info ) throws SysException
    {
        // SUPERCALL MOVED TO END IN NEW RECOVERY!!!
        // super.init ( info );
        info_ = info;
        Properties p = info.getProperties ();
        StandAloneTransactionManager tm = null;
        try {

            tm = createDefault ( p );
            tm.init ( info.getProperties() );
            // install composite manager
            Configuration.installCompositeTransactionManager ( tm );
            Configuration.installRecoveryService ( tm.getTransactionService () );
            Configuration
                    .installImportingTransactionManager ( new ImportingTransactionManagerImp (
                            tm.getTransactionService () ) );
            Configuration
                    .installExportingTransactionManager ( new ExportingTransactionManagerImp () );
            Configuration.installLogControl ( tm.getTransactionService ()
                    .getLogControl () );
            Configuration.installTransactionService ( tm
                    .getTransactionService () );

            String autoMode = getTrimmedProperty (
                    AbstractUserTransactionServiceFactory.AUTOMATIC_RESOURCE_REGISTRATION_PROPERTY_NAME, p );
            if ( autoMode != null )
                autoMode = autoMode.trim ();
            boolean autoRegister = "true".equals ( autoMode );
            com.atomikos.icatch.jta.TransactionManagerImp
                    .installTransactionManager ( tm, autoRegister );
            Enumeration admins = info_.getLogAdministrators ();
            while ( admins.hasMoreElements () ) {
                LogAdministrator admin = (LogAdministrator) admins
                        .nextElement ();
                if ( admin instanceof LocalLogAdministrator ) {
                    LocalLogAdministrator ladmin = (LocalLogAdministrator) admin;
                    ladmin.init ( this );
                }


            }

            // lastly, set up UserTransactionServer if client demarcation
            // is allowed
            boolean clientDemarcation = new Boolean ( getTrimmedProperty (
                    AbstractUserTransactionServiceFactory.CLIENT_DEMARCATION_PROPERTY_NAME, p ) )
                    .booleanValue ();

            if ( clientDemarcation ) {

                String name = getTrimmedProperty (
                        AbstractUserTransactionServiceFactory.TM_UNIQUE_NAME_PROPERTY_NAME, p );
                if ( name == null || name.equals ( "" ) )
                    throw new SysException (
                            "Property not set: com.atomikos.icatch.tm_unique_name" );
                UserTransactionServerImp utxs = UserTransactionServerImp
                        .getSingleton ();
                utxs.init ( name, p );

                String factory = getTrimmedProperty (
                        Context.INITIAL_CONTEXT_FACTORY, p );
                String url = getTrimmedProperty ( Context.PROVIDER_URL, p );
                if ( url == null || url.equals ( "" ) ) {
                    throw new SysException ( "Property not set: "
                            + Context.PROVIDER_URL );
                }

            }

            // this will add all resources and recover them
            super.init ( info );

        } catch ( Exception e ) {
            e.printStackTrace ();
            Stack errors = new Stack ();
            errors.push ( e );
            throw (SysException) new SysException ( "Error in init(): " + e.getMessage (),
                    e ).initCause(e);
        }
    }

    public void shutdown ( boolean force ) throws IllegalStateException
    {
        BaseTransactionManager tm = (BaseTransactionManager) Configuration
                .getCompositeTransactionManager ();
        if ( tm == null )
            return;



        try {
            tm.shutdown ( force );
            tm = null;
            // shutdown system executors
            TaskManager exec = TaskManager.getInstance();
            if ( exec != null ) {
            		exec.shutdown();
            }
            // delegate to superclass to ensure resources are delisted.
            super.shutdown ( force );

			 try {
            	if ( lock_ != null ) {
            		lock_.release();
            		//lock_.channel().close();
            	}
            	if ( lockfilestream_ != null ) lockfilestream_.close();
            } catch (IOException e) {
            	// error release lock or shutting down channel
            	System.err.println ( "Error releasing file lock: "
            			+ e.getMessage());
            } finally {
            	lock_ = null;
            }

            if ( lockfile_ != null ) {
                lockfile_.delete ();
                lockfile_ = null;
            }

            info_ = null;

        } catch ( IllegalStateException il ) {
            // happens if active txs and not force
            throw il;
        }
    }

    /**
     * @see UserTransactionService
     */

    public ImportingTransactionManager getImportingTransactionManager ()
    {
        // make sure that the SubTxThread instance is NOT returned.
        return null;
    }

    /**
     * @see UserTransactionService
     */

    public ExportingTransactionManager getExportingTransactionManager ()
    {
        // make sure that the SubTxThread instance is NOT returned.

        return null;
    }

    /**
     * @see UserTransactionService
     */

    public TSInitInfo createTSInitInfo ()
    {

        TSInitInfoImp ret = new TSInitInfoImp ();
        ret.setProperties ( getProperties () );
        return ret;

    }

    /**
     * @see UserTransactionService
     */

    public TSMetaData getTSMetaData ()
    {


        return new TSMetaDataImp ( JTA.version, VERSION, PRODUCT_NAME, false, false );
    }

    /**
     * @see UserTransactionService
     */

    public UserTransaction getUserTransaction ()
    {
        UserTransaction ret = null;
        ret = UserTransactionServerImp.getSingleton ().getUserTransaction ();
        if ( ret == null ) {
            // not exported
            ret = new J2eeUserTransaction ();
        }

        return ret;
    }

    public static Properties getDefaultProperties ()
    {
        Properties ret = new Properties ();
        ret.setProperty ( AbstractUserTransactionServiceFactory.OUTPUT_DIR_PROPERTY_NAME, "."
                + File.separator );
        ret.setProperty ( AbstractUserTransactionServiceFactory.LOG_BASE_DIR_PROPERTY_NAME, "."
                + File.separator );
        ret.setProperty ( AbstractUserTransactionServiceFactory.LOG_BASE_NAME_PROPERTY_NAME, "tmlog" );
        ret.setProperty ( AbstractUserTransactionServiceFactory.MAX_ACTIVES_PROPERTY_NAME, "50" );
        ret.setProperty ( AbstractUserTransactionServiceFactory.MAX_TIMEOUT_PROPERTY_NAME, "300000" );
        ret.setProperty ( AbstractUserTransactionServiceFactory.DEFAULT_JTA_TIMEOUT_PROPERTY_NAME, "10000" );
        ret.setProperty ( AbstractUserTransactionServiceFactory.CHECKPOINT_INTERVAL_PROPERTY_NAME, "500" );
        ret
                .setProperty ( UserTransactionServiceFactory.SERIAL_JTA_TRANSACTIONS_PROPERTY_NAME,
                        "true" );
        // add unique tm name for remote usertx support
        ret.setProperty ( AbstractUserTransactionServiceFactory.TM_UNIQUE_NAME_PROPERTY_NAME,
                UserTransactionServiceFactory.getDefaultName () );
        // indication of whether client tx demarcation is allowed
        ret.setProperty ( AbstractUserTransactionServiceFactory.CLIENT_DEMARCATION_PROPERTY_NAME, "false" );
        ret.setProperty ( Context.INITIAL_CONTEXT_FACTORY,
                "com.sun.jndi.rmi.registry.RegistryContextFactory" );
        ret.setProperty ( Context.PROVIDER_URL, "rmi://localhost:1099" );

        // ADDED IN 2.0: automatic registration
        ret.setProperty (
                AbstractUserTransactionServiceFactory.AUTOMATIC_RESOURCE_REGISTRATION_PROPERTY_NAME, "true" );
        ret.setProperty ( AbstractUserTransactionServiceFactory.ENABLE_LOGGING_PROPERTY_NAME, "true" );



        ret.setProperty ( AbstractUserTransactionServiceFactory.THREADED_2PC_PROPERTY_NAME , "false" );
        ret.setProperty ( AbstractUserTransactionServiceFactory.REGISTER_SHUTDOWN_HOOK_PROPERTY_NAME , "false" );
        ret.setProperty ( AbstractUserTransactionServiceFactory.SERIALIZABLE_LOGGING_PROPERTY_NAME , "true" );
        return ret;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy