[prev in list] [next in list] [prev in thread] [next in thread] 

List:       jboss-cvs-commits
Subject:    [jboss-cvs] jbosscx/src/main/org/jboss/resource/connectionmanager CachedConnectionManager.java
From:       Adrian Brock <ejort () users ! sourceforge ! net>
Date:       2003-08-30 15:02:28
[Download RAW message or body]

  User: ejort   
  Date: 03/08/30 08:02:27

  Modified:    src/main/org/jboss/resource/connectionmanager Tag:
                        Branch_3_2 CachedConnectionManager.java
  Log:
  Close unclosed connections at transaction commit/rollback,
  when there is a transaction.
  Add a debug flag so that unclosed connections book-keeping
  can be turned off.
  Don't dump "unknown connection 1", this can happen when the
  connection is passed between contexts.
  When closing an unclosed connection show the allocation
  stack trace.
  
  Revision  Changes    Path
  No                   revision
  
  
  No                   revision
  
  
  1.8.2.8   +180 -45   \
jbosscx/src/main/org/jboss/resource/connectionmanager/CachedConnectionManager.java  
  Index: CachedConnectionManager.java
  ===================================================================
  RCS file: /cvsroot/jboss/jbosscx/src/main/org/jboss/resource/connectionmanager/CachedConnectionManager.java,v
  retrieving revision 1.8.2.7
  retrieving revision 1.8.2.8
  diff -u -r1.8.2.7 -r1.8.2.8
  --- CachedConnectionManager.java	31 Mar 2003 15:28:29 -0000	1.8.2.7
  +++ CachedConnectionManager.java	30 Aug 2003 15:02:27 -0000	1.8.2.8
  @@ -5,29 +5,32 @@
    * See terms of license at gnu.org.
    *
    */
  -
   package org.jboss.resource.connectionmanager;
   
  +import java.lang.reflect.Method;
   
  -import java.lang.NoSuchMethodException;
   import java.util.ArrayList;
   import java.util.Collection;
   import java.util.HashMap;
  +import java.util.HashSet;
   import java.util.Iterator;
   import java.util.LinkedList;
   import java.util.Map;
   import java.util.Set;
  +import java.util.WeakHashMap;
  +
  +import javax.management.ObjectName;
  +import javax.naming.InitialContext;
   import javax.resource.ResourceException;
   import javax.transaction.SystemException;
  +import javax.transaction.Synchronization;
   import javax.transaction.Transaction;
  +import javax.transaction.TransactionManager;
  +
   import org.jboss.ejb.EnterpriseContext; //another UserTx.
   import org.jboss.logging.Logger;
  -import org.jboss.system.Service;
   import org.jboss.system.ServiceMBeanSupport;
   import org.jboss.tm.usertx.client.ServerVMClientUserTransaction;
  -//import org.jboss.tm.ServerVMClientUserTransaction.UserTransactionStartedListener;
                
  -import java.lang.reflect.Method;
  -
   
   /**
    * The CachedConnectionManager mbean manages associations between meta-aware \
objects  @@ -49,9 +52,13 @@
      implements ServerVMClientUserTransaction.UserTransactionStartedListener,
                 CachedConnectionManagerMBean
   {
  -
      private boolean specCompliant;
   
  +   private boolean debug;
  +
  +   private ObjectName transactionManagerServiceName;
  +   private TransactionManager tm;
  +
      /**
       * ThreadLocal that holds current calling meta-programming aware
       * object, used in case someone is idiotic enough to cache a
  @@ -71,7 +78,15 @@
   
      protected final Logger log = Logger.getLogger(getClass());
   
  +   /**
  +    * Unclosed connections by transaction
  +    */
  +   private Map unclosedConnectionsByTransaction = new WeakHashMap();
   
  +   /**
  +    * Connection stacktraces
  +    */
  +   private Map connectionStackTraces = new WeakHashMap();
   
      /**
       * Default CachedConnectionManager managed constructor for mbeans.
  @@ -96,7 +111,7 @@
   
      /**
       * Set the SpecCompliant value.
  -    * @param newSpecCompliant The new SpecCompliant value.
  +    * @param specCompliant The new SpecCompliant value.
       * @jmx.managed-attribute
       */
      public void setSpecCompliant(boolean specCompliant)
  @@ -105,6 +120,47 @@
      }
   
   
  +   /**
  +    * Get the debug value.
  +    * @return the debug value.
  +    * @jmx.managed-attribute access="read-write"
  +    */
  +   public boolean isDebug()
  +   {
  +      return debug;
  +   }
  +
  +   /**
  +    * Set the Debug value.
  +    * @param value The new debug value.
  +    * @jmx.managed-attribute
  +    */
  +   public void setDebug(boolean value)
  +   {
  +      this.debug = value;
  +   }
  +
  +   /**
  +    * Get the TransactionManagerServiceName value.
  +    * @return the TransactionManagerServiceName value.
  +    *
  +    * @jmx:managed-attribute
  +    */
  +   public ObjectName getTransactionManagerServiceName()
  +   {
  +      return transactionManagerServiceName;
  +   }
  +
  +   /**
  +    * Set the TransactionManagerServiceName value.
  +    * @param transactionManagerServiceName The new TransactionManagerServiceName \
value.  +    *
  +    * @jmx:managed-attribute
  +    */
  +   public void setTransactionManagerServiceName(ObjectName \
transactionManagerServiceName)  +   {
  +      this.transactionManagerServiceName = transactionManagerServiceName;
  +   }
   
      /**
       * The Instance attribute simply holds the current instance,
  @@ -121,6 +177,8 @@
      protected void startService()
         throws Exception
      {
  +      tm = (TransactionManager)getServer().getAttribute(transactionManagerServiceName,
  +                                                        "TransactionManager");
         ServerVMClientUserTransaction.getSingleton().registerTxStartedListener(this);
  EnterpriseContext.setUserTransactionStartedListener(this);
      }
  @@ -194,7 +252,7 @@
               disconnect(oldKey, unsharableResources);
            } // end of if ()
         }
  -      else
  +      else if (debug)
         {
            closeAll(oldKey.getCMToConnectionsMap());
         } // end of else
  @@ -225,6 +283,9 @@
   
      void registerConnection(ConnectionCacheListener cm, ConnectionRecord cr)
      {
  +      if (debug)
  +         connectionStackTraces.put(cr.connection, new Exception("STACKTRACE"));
  +
         KeyConnectionAssociation key = peekMetaAwareObject();
         if (log.isTraceEnabled())
         {
  @@ -247,6 +308,13 @@
   
      void unregisterConnection(ConnectionCacheListener cm, Object c)
      {
  +      if (debug)
  +      {
  +         CloseConnectionSynchronization cas = \
getCloseConnectionSynchronization(false);  +         if (cas != null)
  +            cas.remove(c);
  +      }
  +
         KeyConnectionAssociation key = peekMetaAwareObject();
         if (log.isTraceEnabled())
         {
  @@ -260,10 +328,9 @@
         Map cmToConnectionsMap = key.getCMToConnectionsMap();
         Collection conns = (Collection)cmToConnectionsMap.get(cm);
         if (conns == null)
  -      {
  -         throw new IllegalStateException("Trying to return an unknown connection1! \
" + c);  +         return; // Can happen if connections are "passed" between contexts
  +         //throw new IllegalStateException("Trying to return an unknown \
connection1! " + c);  //return;//???shouldn't happen.
  -      } // end of if ()
         for (Iterator i = conns.iterator(); i.hasNext(); )
         {
            if (((ConnectionRecord)i.next()).connection == c)
  @@ -354,42 +421,22 @@
   
      private void closeAll(Map cmToConnectionsMap)
      {
  -      for (Iterator i = cmToConnectionsMap.entrySet().iterator(); i.hasNext(); )
  +      if (debug == false)
  +         return;
  +
  +      for (Iterator i = cmToConnectionsMap.values().iterator(); i.hasNext(); )
         {
  -         Map.Entry e = (Map.Entry)i.next();
  -         ConnectionCacheListener cm = (ConnectionCacheListener)e.getKey();
  -         Collection conns = (Collection)e.getValue();
  -         Method m = null;
  -         try
  +         Collection conns = (Collection) i.next();
  +         for (Iterator j = conns.iterator(); j.hasNext(); )
            {
  -
  -            for (Iterator j = conns.iterator(); j.hasNext(); )
  -            {
  -               Object c = ((ConnectionRecord)j.next()).connection;
  -               if (m == null)
  -               {
  -                  m = c.getClass().getMethod("close", new Class[] {});
  -               } // end of if ()
  -               try
  -               {
  -                  m.invoke(c, new Object[] {});
  -                  log.info("Successfully closed a connection for you.  Please \
                close them yourself: " + c, new Exception("Stack Trace"));
  -               }
  -               catch (Throwable t)
  -               {
  -                  log.info("Throwable trying to close a connection for you, please \
                close it yourself", t);
  -               } // end of try-catch
  -
  -            } // end of for ()
  +            Object c = ((ConnectionRecord)j.next()).connection;
  +            CloseConnectionSynchronization cas = \
getCloseConnectionSynchronization(true);  +            if (cas == null)
  +               closeConnection(c);
  +            else
  +               cas.add(c);
            }
  -         catch (NoSuchMethodException nsme)
  -         {
  -            log.info("Could not find a close method on alleged connection objects. \
                Please close your own connections.", new Exception("Stack Trace"));
  -         } // end of try-catch
  -
  -
  -
  -      } // end of for ()
  +      }
      }
   
      //shutdown method for ConnectionManager
  @@ -465,6 +512,94 @@
            return cmToConnectionsMap;
         }
   
  +   }
  +
  +   private void closeConnection(Object c)
  +   {
  +      try
  +      {
  +         Exception e = (Exception) 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.");  +      } // end of try-catch
  +   }
  +
  +   private CloseConnectionSynchronization \
getCloseConnectionSynchronization(boolean createIfNotFound)  +   {
  +      try
  +      {
  +         Transaction tx = tm.getTransaction();
  +         if (tx != null)
  +         {
  +            synchronized (unclosedConnectionsByTransaction)
  +            {
  +               CloseConnectionSynchronization cas = \
(CloseConnectionSynchronization) unclosedConnectionsByTransaction.get(tx);  +         \
if (cas == null && createIfNotFound)  +               {
  +                  cas = new CloseConnectionSynchronization(tx);
  +                  tx.registerSynchronization(cas);
  +                  unclosedConnectionsByTransaction.put(tx, cas);
  +               }
  +               return cas;
  +            }
  +         }
  +      }
  +      catch (Throwable t)
  +      {
  +         log.debug("Unable to determine transaction", t);
  +      }
  +      return null;
  +   }
  +
  +   private class CloseConnectionSynchronization
  +      implements Synchronization
  +   {
  +      Transaction tx;
  +      HashSet connections = new HashSet();
  +
  +      public CloseConnectionSynchronization(Transaction tx)
  +      {
  +         this.tx = tx;
  +      }
  +
  +      public void add(Object c)
  +      {
  +         connections.add(c);
  +      }
  +
  +      public void remove(Object c)
  +      {
  +         connections.remove(c);
  +      }
  +
  +      public void beforeCompletion()
  +      {
  +         synchronized (unclosedConnectionsByTransaction)
  +         {
  +            unclosedConnectionsByTransaction.remove(tx);
  +         }
  +         for (Iterator i = connections.iterator(); i.hasNext();)
  +            closeConnection(i.next());
  +      }
  +
  +      public void afterCompletion(int status)
  +      {
  +      }
      }
   
   }// CachedConnectionManager
  
  
  


-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf
_______________________________________________
jboss-cvs-commits mailing list
jboss-cvs-commits@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jboss-cvs-commits


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic