FileDocCategorySizeDatePackage
CachedConnectionManager.javaAPI DocJBoss 4.2.119610Fri Jul 13 21:01:18 BST 2007org.jboss.resource.connectionmanager

CachedConnectionManager

public class CachedConnectionManager extends org.jboss.system.ServiceMBeanSupport implements CachedConnectionManagerMBean, ServerVMClientUserTransaction.UserTransactionStartedListener
The CachedConnectionManager mbean manages associations between meta-aware objects (those accessed through interceptor chains) and connection handles, and between user transactions and connection handles. Normally there should only be one such mbean. It is called by CachedConnectionInterceptor, UserTransaction, and all BaseConnectionManager2 instances.
author
David Jencks
author
Erwin Guib
author
Adrian Brock
version
$Revision: 57189 $

Fields Summary
private boolean
specCompliant
protected boolean
trace
private boolean
debug
protected boolean
error
private ObjectName
transactionManagerServiceName
private TransactionManager
tm
private final ThreadLocal
currentObjects
ThreadLocal that holds current calling meta-programming aware object, used in case someone is idiotic enough to cache a connection between invocations.and want the spec required behavior of it getting hooked up to an appropriate ManagedConnection on each method invocation.
private final Map
objectToConnectionManagerMap
The variable objectToConnectionManagerMap holds the map of meta-aware object to set of connections it holds, used by the idiot spec compliant behavior.
private Map
connectionStackTraces
Connection stacktraces
Constructors Summary
public CachedConnectionManager()
Default CachedConnectionManager managed constructor for mbeans. Remember that this mbean should be a singleton.

jmx.managed-constructor


                      
    
   
      super();
      trace = log.isTraceEnabled();
   
Methods Summary
private booleancloseAll(java.util.Map cmToConnectionsMap)

      if (debug == false)
         return false;

      boolean unclosed = false;

      Collection connections = cmToConnectionsMap.values();
      if (connections.size() != 0)
      {
         for (Iterator i = connections.iterator(); i.hasNext();)
         {
            Collection conns = (Collection) i.next();
            for (Iterator j = conns.iterator(); j.hasNext();)
            {
               Object c = ((ConnectionRecord) j.next()).connection;
               CloseConnectionSynchronization cas = getCloseConnectionSynchronization(true);
               if (cas == null)
               {
                  unclosed = true;
                  closeConnection(c);
               }
               else
                  cas.add(c);
            }
         }
      }
      
      return unclosed;
   
private voidcloseConnection(java.lang.Object c)

      try
      {
         Throwable e;
         synchronized (connectionStackTraces)
         {
            e = (Throwable) connectionStackTraces.remove(c);
         }
         Method m = c.getClass().getMethod("close", new Class[]{});
         try
         {
            if (e != null)
               log.info("Closing a connection for you.  Please close them yourself: " + c, e);
            else
               log.info("Closing a connection for you.  Please close them yourself: " + c);
            m.invoke(c, new Object[]{});
         }
         catch (Throwable t)
         {
            log.info("Throwable trying to close a connection for you, please close it yourself", t);
         }
      }
      catch (NoSuchMethodException nsme)
      {
         log.info("Could not find a close method on alleged connection objects.  Please close your own connections.");
      }
   
private voiddisconnect(org.jboss.resource.connectionmanager.CachedConnectionManager$KeyConnectionAssociation key, java.util.Set unsharableResources)

      Map cmToConnectionsMap = key.getCMToConnectionsMap();
      if (!cmToConnectionsMap.isEmpty())
      {
         synchronized (objectToConnectionManagerMap)
         {
            objectToConnectionManagerMap.put(key, cmToConnectionsMap);
         }
         for (Iterator i = cmToConnectionsMap.keySet().iterator(); i.hasNext();)
         {
            ConnectionCacheListener cm = (ConnectionCacheListener) i.next();
            Collection conns = (Collection) cmToConnectionsMap.get(cm);
            cm.disconnect(conns, unsharableResources);
         }
      }
   
private org.jboss.resource.connectionmanager.CachedConnectionManager$CloseConnectionSynchronizationgetCloseConnectionSynchronization(boolean createIfNotFound)

      try
      {
         Transaction tx = tm.getTransaction();
         if (TxUtils.isActive(tx))
         {
            TransactionSynchronizer.lock(tx);
            try
            {
               CloseConnectionSynchronization cas = (CloseConnectionSynchronization) TransactionSynchronizer.getCCMSynchronization(tx);
               if (cas == null && createIfNotFound)
               {
                  cas = new CloseConnectionSynchronization();
                  TransactionSynchronizer.registerCCMSynchronization(tx, cas);
               }
               return cas;
            }
            finally
            {
               TransactionSynchronizer.unlock(tx);
            }
         }
      }
      catch (Throwable t)
      {
         log.debug("Unable to synchronize with transaction", t);
      }
      return null;
   
public intgetInUseConnections()

      synchronized (connectionStackTraces)
      {
         return connectionStackTraces.size();
      }
   
public org.jboss.resource.connectionmanager.CachedConnectionManagergetInstance()

      return this;
   
public javax.management.ObjectNamegetTransactionManagerServiceName()

      return transactionManagerServiceName;
   
public booleanisDebug()

      return debug;
   
public booleanisError()

      return error;
   
public booleanisSpecCompliant()

      return specCompliant;
   
public java.util.MaplistInUseConnections()

      synchronized (connectionStackTraces)
      {
         HashMap result = new HashMap();
         for (Iterator i = connectionStackTraces.entrySet().iterator(); i.hasNext();)
         {
            Map.Entry entry = (Map.Entry) i.next();
            Throwable stackTrace = (Throwable) entry.getValue();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            PrintStream ps = new PrintStream(baos);
            stackTrace.printStackTrace(ps);
            result.put(entry.getKey().toString(), baos.toString());
         }
         return result;
      }
   
org.jboss.resource.connectionmanager.CachedConnectionManager$KeyConnectionAssociationpeekMetaAwareObject()

      LinkedList stack = (LinkedList) currentObjects.get();
      if (stack == null)
         return null;
      if (!stack.isEmpty())
         return (KeyConnectionAssociation) stack.getLast();
      else
         return null;
   
public voidpopMetaAwareObject(java.util.Set unsharableResources)
Describe popMetaAwareObject method here. PUBLIC for TESTING PURPOSES ONLY!

exception
ResourceException if an error occurs

      LinkedList stack = (LinkedList) currentObjects.get();
      KeyConnectionAssociation oldKey = (KeyConnectionAssociation) stack.removeLast();
      if (trace)
         log.trace("popped object: " + Strings.defaultToString(oldKey));
      if (specCompliant)
      {
         if (!stack.contains(oldKey))
         {
            disconnect(oldKey, unsharableResources);
         } // end of if ()
      }
      else if (debug)
      {
         if (closeAll(oldKey.getCMToConnectionsMap()) && error)
            throw new ResourceException("Some connections were not closed, see the log for the allocation stacktraces");
      }

      //At one time I attempted to recycle connections held over method calls.
      //This caused problems if the other method call started a new transaction.
      //To assure optimal use of connections, close them before calling out.
   
public voidpushMetaAwareObject(java.lang.Object rawKey, java.util.Set unsharableResources)
Describe pushMetaAwareObject method here. PUBLIC for TESTING PURPOSES ONLY!

param
rawKey an Object value
param
unsharableResources the unsharable resources
exception
ResourceException if an error occurs

      LinkedList stack = (LinkedList) currentObjects.get();
      if (stack == null)
      {
         if (trace)
            log.trace("new stack for key: " + Strings.defaultToString(rawKey));
         stack = new LinkedList();
         currentObjects.set(stack);
      } // end of if ()
      else
      {
         if (trace)
            log.trace("old stack for key: " + Strings.defaultToString(rawKey));
         //At one time I attempted to recycle connections held over method calls.
         //This caused problems if the other method call started a new transaction.
         //To assure optimal use of connections, close them before calling out.
      } // end of else
      //check for reentrancy, reconnect if not reentrant.
      //wrap key to be based on == rather than equals
      KeyConnectionAssociation key = new KeyConnectionAssociation(rawKey);
      if (specCompliant && !stack.contains(key))
      {
         reconnect(key, unsharableResources);
      }
      stack.addLast(key);
   
private voidreconnect(org.jboss.resource.connectionmanager.CachedConnectionManager$KeyConnectionAssociation key, java.util.Set unsharableResources)
The reconnect method gets the cmToConnectionsMap from objectToConnectionManagerMap, copies it to the key, and reconnects all the connections in it.

param
key a KeyConnectionAssociation value
param
unsharableResources a Set value
exception
ResourceException if an error occurs

      Map cmToConnectionsMap = null;
      synchronized (objectToConnectionManagerMap)
      {
         cmToConnectionsMap = (Map) objectToConnectionManagerMap.get(key);
         if (cmToConnectionsMap == null)
            return;
      }
      key.setCMToConnectionsMap(cmToConnectionsMap);
      for (Iterator i = cmToConnectionsMap.keySet().iterator(); i.hasNext();)
      {
         ConnectionCacheListener cm = (ConnectionCacheListener) i.next();
         Collection conns = (Collection) cmToConnectionsMap.get(cm);
         cm.reconnect(conns, unsharableResources);
      }
   
voidregisterConnection(ConnectionCacheListener cm, ConnectionListener cl, java.lang.Object connection, javax.resource.spi.ConnectionRequestInfo cri)

      if (debug)
      {
         synchronized (connectionStackTraces)
         {
            connectionStackTraces.put(connection, new Throwable("STACKTRACE"));
         }
      }

      KeyConnectionAssociation key = peekMetaAwareObject();
      if (trace)
         log.trace("registering connection from " + cm + ", connection : " + connection + ", key: " + key);
      if (key == null)
         return; //not participating properly in this management scheme.

      ConnectionRecord cr = new ConnectionRecord(cl, connection, cri);
      Map cmToConnectionsMap = key.getCMToConnectionsMap();
      Collection conns = (Collection) cmToConnectionsMap.get(cm);
      if (conns == null)
      {
         conns = new ArrayList();
         cmToConnectionsMap.put(cm, conns);
      }
      conns.add(cr);
   
public voidsetDebug(boolean value)

      this.debug = value;
   
public voidsetError(boolean value)

      this.error = value;
   
public voidsetSpecCompliant(boolean specCompliant)

      if (specCompliant)
         log.warn("THE SpecCompliant ATTRIBUTE IS MISNAMED SEE http://jira.jboss.com/jira/browse/JBAS-1662");
      this.specCompliant = specCompliant;
   
public voidsetTransactionManagerServiceName(javax.management.ObjectName transactionManagerServiceName)

      this.transactionManagerServiceName = transactionManagerServiceName;
   
protected voidstartService()

      tm = (TransactionManager) getServer().getAttribute(transactionManagerServiceName,
              "TransactionManager");
      TransactionSynchronizer.setTransactionManager(tm);
      ServerVMClientUserTransaction.getSingleton().registerTxStartedListener(this);
      EnterpriseContext.setUserTransactionStartedListener(this);
   
protected voidstopService()

      ServerVMClientUserTransaction.getSingleton().unregisterTxStartedListener(this);
      EnterpriseContext.setUserTransactionStartedListener(null);
   
voidunregisterConnection(ConnectionCacheListener cm, java.lang.Object c)

      if (debug)
      {
         CloseConnectionSynchronization cas = getCloseConnectionSynchronization(false);
         if (cas != null)
            cas.remove(c);
         synchronized (connectionStackTraces)
         {
            connectionStackTraces.remove(c);
         }
      }

      KeyConnectionAssociation key = peekMetaAwareObject();
      if (trace)
         log.trace("unregistering connection from " + cm + ", object: " + c + ", key: " + key);
      if (key == null)
         return; //not participating properly in this management scheme.

      Map cmToConnectionsMap = key.getCMToConnectionsMap();
      Collection conns = (Collection) cmToConnectionsMap.get(cm);
      if (conns == null)
         return; // Can happen if connections are "passed" between contexts
      for (Iterator i = conns.iterator(); i.hasNext();)
      {
         if (((ConnectionRecord) i.next()).connection == c)
         {
            i.remove();
            return;
         }
      }
      throw new IllegalStateException("Trying to return an unknown connection2! " + c);
   
voidunregisterConnectionCacheListener(ConnectionCacheListener cm)
Describe unregisterConnectionCacheListener method here. This is a shutdown method called by a connection manager. It will remove all reference to that connection manager from the cache, so cached connections from that manager will never be recoverable. Possibly this method should not exist.

param
cm a ConnectionCacheListener value

      if (trace)
         log.trace("unregisterConnectionCacheListener: " + cm);
      synchronized (objectToConnectionManagerMap)
      {
         for (Iterator i = objectToConnectionManagerMap.values().iterator(); i.hasNext();)
         {
            Map cmToConnectionsMap = (Map) i.next();
            if (cmToConnectionsMap != null)
               cmToConnectionsMap.remove(cm);
         }
      }
   
public voiduserTransactionStarted()

      KeyConnectionAssociation key = peekMetaAwareObject();
      if (trace)
         log.trace("user tx started, key: " + key);
      if (key == null)
         return; //not participating properly in this management scheme.

      Map cmToConnectionsMap = key.getCMToConnectionsMap();
      for (Iterator i = cmToConnectionsMap.keySet().iterator(); i.hasNext();)
      {
         ConnectionCacheListener cm = (ConnectionCacheListener) i.next();
         Collection conns = (Collection) cmToConnectionsMap.get(cm);
         cm.transactionStarted(conns);
      }