User: starksm 
  Date: 02/04/14 12:43:07

  Modified:    src/main/org/jboss/ejb/plugins/jaws/jdbc
                        JDBCCommandFactory.java
  Log:
  Make the PreloadRefQueueHandlerTask inner class a static as its reference
  to the container was preventing the container from being GCd.
  
  Revision  Changes    Path
  1.19      +143 -93   
jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCCommandFactory.java
  
  Index: JDBCCommandFactory.java
  ===================================================================
  RCS file: 
/cvsroot/jboss/jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCCommandFactory.java,v
  retrieving revision 1.18
  retrieving revision 1.19
  diff -u -r1.18 -r1.19
  --- JDBCCommandFactory.java   8 Mar 2002 20:37:06 -0000       1.18
  +++ JDBCCommandFactory.java   14 Apr 2002 19:43:07 -0000      1.19
  @@ -46,13 +46,13 @@
   
   /**
    * Command factory for the JAWS JDBC layer. This class is primarily responsible
  - * for creating instances of the JDBC implementations for the various JPM 
  + * for creating instances of the JDBC implementations for the various JPM
    * commands so that the JAWSPersistenceManager (actually an persistence store)
    * can delegate to them in a decoupled manner.
  - * <p>This class also acts as the manager for the read-ahead buffer added in 
  + * <p>This class also acts as the manager for the read-ahead buffer added in
    * version 2.3/2.4. In order to manage this buffer, it must register itself
  - * with any transaction that is active when a finder is called so that the 
  - * data that was read ahead can be discarded before completion of the 
  + * with any transaction that is active when a finder is called so that the
  + * data that was read ahead can be discarded before completion of the
    * transaction. The read ahead buffer is managed using Soft references, with
    * a ReferenceQueue being used to tell when the VM has garbage collected an
    * object so that we can keep the hashtables clean.
  @@ -60,11 +60,11 @@
    * @author <a href="mailto:[EMAIL PROTECTED]";>Justin Forder</a>
    * @author <a href="[EMAIL PROTECTED]">danch (Dan Christopherson)</a>
    * @author <a href="[EMAIL PROTECTED]">Bill Burke</a>
  - * @version $Revision: 1.18 $
  + * @version $Revision: 1.19 $
    *
    *   <p><b>Revisions:</b>
    *
  - *   <p><b>20010621 Bill Burke:</b> 
  + *   <p><b>20010621 Bill Burke:</b>
    *   <ul>
    *   <li>createDefinedFinderCommand creates different objects
    *    based on the read-head flag of the FinderMetaData.
  @@ -72,7 +72,7 @@
    *
    *   <p><b>20010621 danch:</b>
    *   <ul>
  - *   <li>extended Bill's change to work on other finder types; 
  + *   <li>extended Bill's change to work on other finder types;
    *    removed stale todos.
    *   </ul>
    *
  @@ -89,15 +89,15 @@
      private EntityContainer container;
      private JawsEntityMetaData metadata;
      private final Logger log = Logger.getLogger(this.getClass());
  -
  +   
      /** Timer queue used to time polls on the preloadRefQueue on all JAWS
       *  handled entities
       */
      private static TimerQueue softRefHandler;
  -
  +   
      /** Timer queue used to get references to preload data who've been GC'ed */
      private ReferenceQueue preloadRefQueue = new ReferenceQueue();
  -
  +   
      /** a map of data preloaded within some transaction for some entity. This map
       *  is keyed by Transaction and the data are hashmaps with key = entityKey and
       *  data = Object[] containing the entity data.  */
  @@ -106,55 +106,60 @@
       *  data = Object[] containing entity data
       */
      private Map nonTransactionalPreloadData = new HashMap();
  -
  +   
      /** a Transaction manager so that we can link preloaded data to a transaction */
      private TransactionManager tm;
  -
  +   
      // These support singletons (within the scope of this factory)
      private JDBCBeanExistsCommand beanExistsCommand;
      private JPMFindEntitiesCommand findEntitiesCommand;
  -
  +   
      //static initializer to kick off our softRefhandler
  -   static {
  +   static
  +   {
         softRefHandler = new TimerQueue("JAWS Preload reference handler");
         softRefHandler.start();
      }
  -
  +   
      // Constructors --------------------------------------------------
  -
  +   
      public JDBCCommandFactory(EntityContainer container)
  -      throws Exception
  +   throws Exception
      {
         this.container = container;
  -
  +      
         String ejbName = container.getBeanMetaData().getEjbName();
         ApplicationMetaData amd = 
container.getBeanMetaData().getApplicationMetaData();
         JawsApplicationMetaData jamd = 
(JawsApplicationMetaData)amd.getPluginData("JAWS");
  -
  -      if (jamd == null) {
  +      
  +      if (jamd == null)
  +      {
            // we are the first cmp entity to need jaws. Load jaws.xml for the whole 
application
            JawsXmlFileLoader jfl = new JawsXmlFileLoader(amd, 
container.getClassLoader(), container.getLocalClassLoader());
            jamd = jfl.load();
            amd.addPluginData("JAWS", jamd);
         }
  -
  +      
         metadata = jamd.getBeanByEjbName(ejbName);
  -      if (metadata == null) {
  +      if (metadata == null)
  +      {
            throw new DeploymentException("No metadata found for bean " + ejbName);
         }
  -
  +      
         tm = (TransactionManager) container.getTransactionManager();
   
  -      softRefHandler.schedule(new PreloadRefQueueHandlerTask());
  +      PreloadRefQueueHandlerTask reqQue = new 
PreloadRefQueueHandlerTask(preloadRefQueue,
  +         preloadedData, nonTransactionalPreloadData);
  +      softRefHandler.schedule(reqQue);
      }
  -
  +   
      // Public --------------------------------------------------------
  -
  +   
      public EntityContainer getContainer()
      {
         return container;
      }
  -
  +   
      public JawsEntityMetaData getMetaData()
      {
         return metadata;
  @@ -163,7 +168,7 @@
      // Additional Command creation
      
      /**
  -    * Singleton: multiple callers get references to the 
  +    * Singleton: multiple callers get references to the
       * same command instance.
       */
      public JDBCBeanExistsCommand createBeanExistsCommand()
  @@ -182,7 +187,7 @@
         {
            return new JDBCPreloadFinderCommand(this, new JDBCFindAllCommand(this, f));
         }
  -      else 
  +      else
         {
            return new JDBCFindAllCommand(this, f);
         }
  @@ -201,13 +206,13 @@
      }
      
      public JPMFindEntitiesCommand createFindByCommand(Method finderMethod, 
FinderMetaData f)
  -      throws IllegalArgumentException
  +   throws IllegalArgumentException
      {
         if (f.hasReadAhead())
         {
            return new JDBCPreloadFinderCommand(this, new JDBCFindByCommand(this, 
finderMethod, f));
         }
  -      else 
  +      else
         {
            return new JDBCFindByCommand(this, finderMethod, f);
         }
  @@ -245,7 +250,7 @@
      }
      
      /**
  -    * Singleton: multiple callers get references to the 
  +    * Singleton: multiple callers get references to the
       * same command instance.
       */
      public JPMFindEntitiesCommand createFindEntitiesCommand()
  @@ -297,27 +302,35 @@
      
      
      /** Add preloaded data for an entity within the scope of a transaction */
  -   /*package*/ void addPreloadData(Object entityKey, Object[] entityData) 
  +   /*package*/ void addPreloadData(Object entityKey, Object[] entityData)
      {
         Transaction trans = null;
  -      try {
  +      try
  +      {
            trans = tm.getTransaction();
  -      } catch (javax.transaction.SystemException sysE) {
  +      } catch (javax.transaction.SystemException sysE)
  +      {
            log.warn("System exception getting transaction for preload - can't preload 
data for "+entityKey, sysE);
            return;
         }
  -//log.debug("PRELOAD: adding preload for "+entityKey+" in transaction "+(trans != 
null ? trans.toString() : "NONE")+" entityData="+entityData);
  +      //log.debug("PRELOAD: adding preload for "+entityKey+" in transaction 
"+(trans != null ? trans.toString() : "NONE")+" entityData="+entityData);
         
  -      if (trans != null) {
  -         synchronized (preloadedData) {
  +      if (trans != null)
  +      {
  +         synchronized (preloadedData)
  +         {
               Map entitiesInTransaction = (Map)preloadedData.get(trans);
  -            if (entitiesInTransaction == null) {
  -               try {
  +            if (entitiesInTransaction == null)
  +            {
  +               try
  +               {
                     trans.registerSynchronization(new PreloadClearSynch(trans));
  -               } catch (javax.transaction.SystemException se) {
  +               } catch (javax.transaction.SystemException se)
  +               {
                     log.warn("System exception getting transaction for preload - 
can't get preloaded data for "+entityKey, se);
                     return;
  -               } catch (javax.transaction.RollbackException re) {
  +               } catch (javax.transaction.RollbackException re)
  +               {
                     log.warn("Rollback exception getting transaction for preload - 
can't get preloaded data for "+entityKey, re);
                     return;
                  }
  @@ -327,66 +340,77 @@
               PreloadData preloadData = new PreloadData(trans, entityKey, entityData, 
preloadRefQueue);
               entitiesInTransaction.put(entityKey, preloadData);
            }
  -      } else {
  -         synchronized (nonTransactionalPreloadData) {
  +      } else
  +      {
  +         synchronized (nonTransactionalPreloadData)
  +         {
               PreloadData preloadData = new PreloadData(null, entityKey, entityData, 
preloadRefQueue);
               nonTransactionalPreloadData.put(entityKey, preloadData);
            }
         }
      }
      
  -   /** get data that we might have preloaded for an entity in a transaction - 
  +   /** get data that we might have preloaded for an entity in a transaction -
       *  may return null!
       */
  -   /*package*/ Object[] getPreloadData(Object entityKey) 
  +   /*package*/ Object[] getPreloadData(Object entityKey)
      {
         Transaction trans = null;
  -      try {
  +      try
  +      {
            trans = tm.getTransaction();
  -      } catch (javax.transaction.SystemException sysE) {
  +      } catch (javax.transaction.SystemException sysE)
  +      {
            log.warn("System exception getting transaction for preload - not 
preloading "+entityKey, sysE);
            return null;
         }
         
         Object[] result = null;
         PreloadData preloadData = null;
  -      if (trans != null) {
  +      if (trans != null)
  +      {
            Map entitiesInTransaction = null;
  -         // Do we really need this to be syncrhonized? What is the effect of 
  +         // Do we really need this to be syncrhonized? What is the effect of
            //    another thread trying to modify this map? It won't be to remove
  -         //    our transaction (we're in it here!, trying to call a business 
  +         //    our transaction (we're in it here!, trying to call a business
            //    method), and who cares if another is added/removed?
  -//         synchronized (preloadedData) {
  -            entitiesInTransaction = (Map)preloadedData.get(trans);
  -//         }
  -         if (entitiesInTransaction != null) {
  -            synchronized (entitiesInTransaction) {
  +         //         synchronized (preloadedData) {
  +         entitiesInTransaction = (Map)preloadedData.get(trans);
  +         //         }
  +         if (entitiesInTransaction != null)
  +         {
  +            synchronized (entitiesInTransaction)
  +            {
                  preloadData = (PreloadData)entitiesInTransaction.get(entityKey);
                  entitiesInTransaction.remove(entityKey);
               }
            }
  -      } else {
  -         synchronized (nonTransactionalPreloadData) {
  +      } else
  +      {
  +         synchronized (nonTransactionalPreloadData)
  +         {
               preloadData = (PreloadData)nonTransactionalPreloadData.get(entityKey);
               nonTransactionalPreloadData.remove(entityKey);
            }
         }
  -      if (preloadData != null) {
  +      if (preloadData != null)
  +      {
            result = preloadData.getData();
         } /*else {
            log.debug("PRELOAD: preloadData == null for "+entityKey);
         }
   if (result == null)
      log.debug("PRELOAD: returning null as preload for "+entityKey);
  -   */
  +       */
         return result;
      }
      
      /** clear out any data we have preloaded for any entity in this transaction */
  -   /*package*/ void clearPreloadForTrans(Transaction trans) 
  +   /*package*/ void clearPreloadForTrans(Transaction trans)
      {
  -//log.debug("PRELOAD: clearing preload for transaction "+trans.toString());
  -      synchronized (preloadedData) {
  +      //log.debug("PRELOAD: clearing preload for transaction "+trans.toString());
  +      synchronized (preloadedData)
  +      {
            preloadedData.remove(trans);
         }
      }
  @@ -394,35 +418,51 @@
      
      // Private -------------------------------------------------------
      
  -   /** Inner class that handles our reference queue. I didn't think this would 
  -    *  be neccessary, but for some reason the VM won't call an override of 
  -    *  Reference.clear() 
  -   */
  -   private class PreloadRefQueueHandlerTask extends TimerTask {
  -      PreloadRefQueueHandlerTask() {
  +   /** Static class that handles our reference queue. It is a static class
  +    to avoid a strong reference to the container instance variable as this
  +    prevents GC of the container.
  +    */
  +   private static class PreloadRefQueueHandlerTask extends TimerTask
  +   {
  +      ReferenceQueue preloadRefQueue;
  +      Map preloadedData;
  +      Map nonTransactionalPreloadData;
  +      PreloadRefQueueHandlerTask(ReferenceQueue preloadRefQueue,
  +         Map preloadedData, Map nonTransactionalPreloadData)
  +      {
            super(50);
  +         this.preloadRefQueue = preloadRefQueue;
  +         this.preloadedData = preloadedData;
  +         this.nonTransactionalPreloadData = nonTransactionalPreloadData;
         }
  -      
  -      public void execute() throws Exception {
  +
  +      public void execute() throws Exception
  +      {
            PreloadData preloadData = (PreloadData)preloadRefQueue.poll();
            int handled = 0;
  -         while (preloadData != null && handled < 10) {
  -            if (preloadData.getTransaction() != null) {
  +         while (preloadData != null && handled < 10)
  +         {
  +            if (preloadData.getTransaction() != null)
  +            {
                  Map entitiesInTransaction = null;
  -               // Do we really need this to be syncrhonized? What is the effect of 
  +               // Do we really need this to be syncrhonized? What is the effect of
                  //    another thread trying to modify this map? It won't be to remove
  -               //    our transaction (we're in it here!, trying to call a business 
  +               //    our transaction (we're in it here!, trying to call a business
                  //    method), and who cares if another is added/removed?
  -      //         synchronized (preloadedData) {
  -                  entitiesInTransaction = 
(Map)preloadedData.get(preloadData.getTransaction());
  -      //         }
  -               if (entitiesInTransaction != null) {
  -                  synchronized (entitiesInTransaction) {
  +               //         synchronized (preloadedData) {
  +               entitiesInTransaction = 
(Map)preloadedData.get(preloadData.getTransaction());
  +               //         }
  +               if (entitiesInTransaction != null)
  +               {
  +                  synchronized (entitiesInTransaction)
  +                  {
                        entitiesInTransaction.remove(preloadData.getKey());
                     }
                  }
  -            } else {
  -               synchronized (nonTransactionalPreloadData) {
  +            } else
  +            {
  +               synchronized (nonTransactionalPreloadData)
  +               {
                     nonTransactionalPreloadData.remove(preloadData.getKey());
                  }
               }
  @@ -434,46 +474,56 @@
         }
      }
      
  -   /** Inner class used in the preload Data hashmaps so that we can wrap a 
  +   /** Inner class used in the preload Data hashmaps so that we can wrap a
       *  SoftReference around the data and still have enough information to remove
       *  the reference from the appropriate hashMap.
       */
  -   private class PreloadData extends SoftReference {
  +   private class PreloadData extends SoftReference
  +   {
         private Object key;
         private Transaction trans;
         
  -      PreloadData(Transaction trans, Object key, Object[] data, ReferenceQueue 
queue) {
  +      PreloadData(Transaction trans, Object key, Object[] data, ReferenceQueue 
queue)
  +      {
            super(data, queue);
            this.trans = trans;
            this.key = key;
         }
         
  -      Transaction getTransaction() {
  +      Transaction getTransaction()
  +      {
            return trans;
         }
  -      Object getKey() {
  +      Object getKey()
  +      {
            return key;
         }
  -      Object[] getData() {
  +      Object[] getData()
  +      {
            return (Object[])get();
         }
         
         /** Named empty to not collide with superclass clear */
  -      public void empty() {
  +      public void empty()
  +      {
            key = null;
            trans = null;
         }
      }
      
  -   private class PreloadClearSynch implements javax.transaction.Synchronization{
  +   private class PreloadClearSynch implements javax.transaction.Synchronization
  +   {
         private Transaction forTrans;
  -      public PreloadClearSynch(Transaction forTrans) {
  +      public PreloadClearSynch(Transaction forTrans)
  +      {
            this.forTrans = forTrans;
         }
  -      public void afterCompletion(int p0) {
  +      public void afterCompletion(int p0)
  +      {
            clearPreloadForTrans(forTrans);
         }
  -      public void beforeCompletion() {
  +      public void beforeCompletion()
  +      {
            //no-op
         }
      }
  
  
  

_______________________________________________
Jboss-development mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/jboss-development

Reply via email to