Package org.jpox

Source Code of org.jpox.ConnectionManagerImpl

/**********************************************************************
Copyright (c) 2007 Erik Bengtson and others. All rights reserved.
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.

Contributors:
2007 Andy Jefferson - javadocs, formatted, copyrighted
2007 Andy Jefferson - added lock/unlock/hasConnection/hasLockedConnection and enlisting
    ...
**********************************************************************/
package org.jpox;

import java.util.HashMap;
import java.util.Map;

import javax.transaction.xa.XAResource;

import org.jpox.exceptions.JPOXUserException;
import org.jpox.management.ManagementServer;
import org.jpox.management.runtime.ConnectionManagerRuntime;
import org.jpox.transaction.Transaction;
import org.jpox.util.ClassUtils;
import org.jpox.util.JPOXLogger;
import org.jpox.util.Localiser;

/**
* Manager of connections for an OMF, allowing ManagedConnection pooling, enlistment in transaction.
* The pool caches one connection per ObjectManager.
* The "allocate" method can create connections and enlist them (like most normal persistence operations need)
* or create a connection and return it.
*
* @version $Revision: 1.17 $
*/
public class ConnectionManagerImpl implements ConnectionManager
{
    /** Localisation of messages. */
    protected static final Localiser LOCALISER=Localiser.getInstance("org.jpox.Localisation",
        ObjectManagerFactoryImpl.class.getClassLoader());

    /** OMFContext for this connection manager. */
    OMFContext omfContext;
   
    ManagedConnectionPool connectionPool = new ManagedConnectionPool();

    /** Connection Runtime. Used when providing management of services. */
    ConnectionManagerRuntime connMgrRuntime = null;

    /**
     * Constructor.
     * @param omfContext OMFContext for this manager.
     */
    public ConnectionManagerImpl(OMFContext omfContext)
    {
        this.omfContext = omfContext;

        if (omfContext.getManagement() != null)
        {
            // register MBean in MbeanServer
            ManagementServer mgmtServer = this.omfContext.getManagement().getManagementServer();
            connMgrRuntime = new ConnectionManagerRuntime();
            String mbeanName = omfContext.getDomainName() + ":InstanceName=" + omfContext.getInstanceName() +
                ",Type=" + ClassUtils.getClassNameForClass(connMgrRuntime.getClass()) +
                ",Name=ConnectionManagerRuntime";
            mgmtServer.registerMBean(connMgrRuntime, mbeanName);
        }
    }

    /**
     * Pool of managed connections for an ObjectManager.
     * Each ObjectManager has its own pool of ManagedConnection's
     */
    class ManagedConnectionPool
    {
        /**
         * Connection pool keeps a reference to a connection for each ObjectManager (and so the connection
         * used by each transaction).
         * This permits reuse of connections in the same transaction, but not at same time!!!
         * ManagedConnection must be released to return to pool.
         * On transaction commit/rollback, connection pool is cleared
         *
         * For each combination of ObjectManager-ConnectionFactory there is 0 or 1 ManagedConnection:
         * Map<ObjectManager, Map<ConnectionFactory,ManagedConnection>>
         */
        Map connectionsPool = new HashMap();
       
        /**
         * Remove from pool
         * @param factory The factory is the nested key
         * @param om The om is the key for the ManagedConnection
         */
        public void removeManagedConnection(ConnectionFactory factory, ObjectManager om)
        {
            synchronized (connectionsPool)
            {
                Map connectionsForOM = (Map) connectionsPool.get(om);
                if (connectionsForOM != null)
                {
                    if (connectionsForOM.remove(factory) != null && connMgrRuntime != null)
                    {
                        connMgrRuntime.decrementActiveConnections();
                    }

                    if (connectionsForOM.size() == 0)
                    {
                        // No connections remaining for this OM so remove the entry for the ObjectManager
                        connectionsPool.remove(om);
                    }
                }
            }
        }

        /**
         * Object a ManagedConnection from pool
         * @param factory
         * @param om
         * @return
         */
        public ManagedConnection getManagedConnection(ConnectionFactory factory, ObjectManager om)
        {
            synchronized (connectionsPool)
            {
                Map connectionsForOM = (Map) connectionsPool.get(om);
                if (connectionsForOM == null)
                {
                    return null;
                }
                //obtain a ManagedConnection for an specific ConnectionFactory
                ManagedConnection mconn = (ManagedConnection) connectionsForOM.get(factory);
                if (mconn != null)
                {
                    if (mconn.isLocked())
                    {
                        // Enlisted connection that is locked so throw exception
                        throw new JPOXUserException(LOCALISER.msg("009000"));
                    }                       
                    // Already registered enlisted connection present so return it
                    return mconn;
                }
            }
            return null;
        }
       
        public void putManagedConnection(ConnectionFactory factory, ObjectManager om, ManagedConnection mconn)
        {
            synchronized (connectionsPool)
            {
                Map connectionsForOM = (Map) connectionsPool.get(om);
                if (connectionsForOM == null)
                {
                    connectionsForOM = new HashMap();
                    connectionsPool.put(om, connectionsForOM);
                }
                if (connectionsForOM.put(factory, mconn) == null && connMgrRuntime != null)
                {
                    connMgrRuntime.incrementActiveConnections();
                }
            }
        }
    }

    /**
     * Method to return a connection for this ObjectManager.
     * If a connection for the ObjectManager exists in the cache will return it.
     * If no connection exists will create a new one using the ConnectionFactory.
     * @param factory ConnectionFactory it relates to
     * @param om The ObjectManager
     * @param options Options for the connection (e.g isolation). These will override those of the txn itself
     * @return The ManagedConnection
     */
    public ManagedConnection allocateConnection(final ConnectionFactory factory, final ObjectManager om, Map options)
    {
        if (om != null)
        {
            ManagedConnection mconnFromPool = connectionPool.getManagedConnection(factory, om);
            if (mconnFromPool != null)
            {
                if (JPOXLogger.CONNECTION.isDebugEnabled())
                {
                    JPOXLogger.CONNECTION.debug("Connection found in the pool : "+mconnFromPool);
                }
                // Already registered enlisted connection present so return it
                return mconnFromPool;
            }
        }

        // Create new connection
        Map txOptions = options;
        if (options == null && om != null)
        {
            txOptions = om.getTransaction().getOptions();
        }
        ManagedConnection mconn = factory.createManagedConnection(om, txOptions);
        configureManagedConnectionListener(om, mconn, factory);

        // Enlist the connection in this transaction
        if (om != null )
        {
            if( om.getTransaction().isActive())
            {
                configureTransactionEventListener(om,mconn);
                Transaction tx = omfContext.getTransactionManager().getTransaction(om);
                //must be set before getting the XAResource
                mconn.setManagedResource();
                enlistResource(mconn, tx, options);
            }
            // Register this connection against the ObjectManager - connection is valid
            if (JPOXLogger.CONNECTION.isDebugEnabled())
            {
                JPOXLogger.CONNECTION.debug("Connection added to the pool : "+mconn);
            }
            connectionPool.putManagedConnection(factory, om, mconn);
        }

        return mconn;
    }

    private void configureManagedConnectionListener(final ObjectManager om, final ManagedConnection mconn, final ConnectionFactory factory)
    {
        mconn.addListener(new ManagedConnectionResourceListener()
        {
            public void managedConnectionPostClose()
            {
                if (om != null)
                {
                    if (JPOXLogger.CONNECTION.isDebugEnabled())
                    {
                        JPOXLogger.CONNECTION.debug("Connection removed from the pool : "+mconn);
                    }
                    connectionPool.removeManagedConnection(factory, om); // Connection closed so remove 
                }
            }

            public void managedConnectionPreClose() {}
            public void managedConnectionFlushed() {}
            public void resourcePostClose() {}
        });
    }

    /**
     * Configure a TransactionEventListener that closes the managed connection when a
     * transaction commits or rolls back
     * @param om
     * @param mconn
     */
    private void configureTransactionEventListener(final ObjectManager om, final ManagedConnection mconn)
    {
        // Add handler for any enlisted connection to the transaction so we know when to close it
        om.getTransaction().addTransactionEventListener(
            new TransactionEventListener()
            {
                public void transactionStarted() {}

                public void transactionRolledBack()
                {
                    try
                    {
                        mconn.close();
                    }
                    finally
                    {
                        om.getTransaction().removeTransactionEventListener(this);
                    }
                }

                public void transactionCommitted()
                {
                    try
                    {
                        mconn.close();
                    }
                    finally
                    {
                        om.getTransaction().removeTransactionEventListener(this);
                    }
                }

                public void transactionEnded()
                {
                    try
                    {
                        mconn.close();
                    }
                    finally
                    {
                        om.getTransaction().removeTransactionEventListener(this);
                    }
                }

                public void transactionPreCommit()
                {
                    if (mconn.isLocked())
                    {
                        // Enlisted connection that is locked so throw exception
                        throw new JPOXUserException(LOCALISER.msg("009000"));
                    }
                }

                public void transactionPreRollBack()
                {
                    if (mconn.isLocked())
                    {
                        // Enlisted connection that is locked so throw exception
                        throw new JPOXUserException(LOCALISER.msg("009000"));
                    }  
                }

                public void transactionFlushed()
                {
                    mconn.flush();
                }
            });
    }
   
    /**
     * Enlist the mconn in the transaction if using JPOX's transaction manager
     * @param mconn
     * @param tx
     * @param options
     */
    private void enlistResource(ManagedConnection mconn, Transaction tx, Map options)
    {
        XAResource res = mconn.getXAResource();
        if (res != null)
        {
            // Enlist the connection resource if has enlistable resource
            boolean enlistInLocalTM = true;
            if (options != null && options.get("resource-type") != null &&
                    ResourceType.JTA.toString().equalsIgnoreCase((String)options.get("resource-type")))
            {
                //XAResource will be enlisted in an external JTA container,
                //so we dont enlist it in the internal Transaction Manager
                enlistInLocalTM = false;
            }
            if (enlistInLocalTM)
            {
                tx.enlistResource(res);
            }
        }
    }
}
TOP

Related Classes of org.jpox.ConnectionManagerImpl

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.