User: danch   
  Date: 01/06/18 07:34:27

  Modified:    src/main/org/jboss/ejb/plugins/jaws/jdbc JDBCCommand.java
                        JDBCCommandFactory.java JDBCFindByCommand.java
                        JDBCFindEntitiesCommand.java
  Log:
  Use SoftReferences for the preloaded data; also, patch #418196 (creating finders of 
nested CMP-fields)
  
  Revision  Changes    Path
  1.33      +2 -2      jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCCommand.java
  
  Index: JDBCCommand.java
  ===================================================================
  RCS file: 
/cvsroot/jboss/jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCCommand.java,v
  retrieving revision 1.32
  retrieving revision 1.33
  diff -u -r1.32 -r1.33
  --- JDBCCommand.java  2001/06/06 01:07:40     1.32
  +++ JDBCCommand.java  2001/06/18 14:34:27     1.33
  @@ -57,7 +57,7 @@
    *
    * @author <a href="mailto:[EMAIL PROTECTED]";>Justin Forder</a>
    * @author <a href="mailto:[EMAIL PROTECTED]";>Dirk Zimmermann</a>
  - * @version $Revision: 1.32 $
  + * @version $Revision: 1.33 $
    */
   public abstract class JDBCCommand
   {
  @@ -386,7 +386,7 @@
       protected Object getResultObject(ResultSet rs, int idx, Class destination)
           throws SQLException{
   
  -log.debug("getting a "+destination.getName()+" from resultset at index "+idx);
  +// log.debug("getting a "+destination.getName()+" from resultset at index "+idx);
           Object result = null;
   
           Method method = (Method)rsTypes.get(destination.getName());
  
  
  
  1.10      +142 -58   
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.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- JDBCCommandFactory.java   2001/06/13 06:52:17     1.9
  +++ JDBCCommandFactory.java   2001/06/18 14:34:27     1.10
  @@ -8,11 +8,15 @@
   package org.jboss.ejb.plugins.jaws.jdbc;
   
   import java.lang.reflect.Method;
  +import java.lang.ref.SoftReference;
  +import java.lang.ref.WeakReference;
  +import java.lang.ref.ReferenceQueue;
   import java.util.Map;
   import java.util.HashMap;
   import java.util.List;
   import java.util.LinkedList;
   import java.util.Iterator;
  +import java.util.WeakHashMap;
   
   import javax.naming.Context;
   import javax.naming.InitialContext;
  @@ -46,13 +50,25 @@
   
   import org.jboss.logging.Log;
   import org.jboss.util.FinderResults;
  +import org.jboss.util.TimerTask;
  +import org.jboss.util.TimerQueue;
   
   /**
  - * JAWSPersistenceManager JDBCCommandFactory
  + * Command factory for the JAWS JDBC layer. This class is primarily responsible
  + * 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 
  + * 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 
  + * 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.
    *
    * @author <a href="mailto:[EMAIL PROTECTED]";>Justin Forder</a>
    * @author <a href="[EMAIL PROTECTED]">danch (Dan Christopherson</a>
  - * @version $Revision: 1.9 $
  + * @version $Revision: 1.10 $
    */
   public class JDBCCommandFactory implements JPMCommandFactory
   {
  @@ -63,7 +79,15 @@
      private JawsEntityMetaData metadata;
      private Log log;
      private boolean debug = false;
  +
  +   /** 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. 
  @@ -81,7 +105,13 @@
      // These support singletons (within the scope of this factory)
      private JDBCBeanExistsCommand beanExistsCommand;
      private JPMFindEntitiesCommand findEntitiesCommand;
  -   
  +
  +   //static initializer to kick off our softRefhandler 
  +   static {
  +      softRefHandler = new TimerQueue("JAWS Preload reference handler");
  +      softRefHandler.start();
  +   }
  +      
      // Constructors --------------------------------------------------
      
      public JDBCCommandFactory(EntityContainer container,
  @@ -93,24 +123,26 @@
          
         this.javaCtx = (Context)new InitialContext().lookup("java:comp/env");
         
  -       String ejbName = container.getBeanMetaData().getEjbName();
  -       ApplicationMetaData amd = 
container.getBeanMetaData().getApplicationMetaData();
  -       JawsApplicationMetaData jamd = 
(JawsApplicationMetaData)amd.getPluginData("JAWS");
  -       
  -       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(), log);
  -       jamd = jfl.load();
  -              amd.addPluginData("JAWS", jamd);
  -       }
  -     debug = jamd.getDebug();
  -               
  -       metadata = jamd.getBeanByEjbName(ejbName);
  -       if (metadata == null) {
  -               throw new DeploymentException("No metadata found for bean " + 
ejbName);
  -       }
  +      String ejbName = container.getBeanMetaData().getEjbName();
  +      ApplicationMetaData amd = 
container.getBeanMetaData().getApplicationMetaData();
  +      JawsApplicationMetaData jamd = 
(JawsApplicationMetaData)amd.getPluginData("JAWS");
  +           
  +      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(), log);
  +         jamd = jfl.load();
  +         amd.addPluginData("JAWS", jamd);
  +      }
  +      debug = jamd.getDebug();
  +              
  +      metadata = jamd.getBeanByEjbName(ejbName);
  +      if (metadata == null) {
  +         throw new DeploymentException("No metadata found for bean " + ejbName);
  +      }
  +            
  +      tm = (TransactionManager) container.getTransactionManager();
         
  -     tm = (TransactionManager) container.getTransactionManager();
  +      softRefHandler.schedule(new PreloadRefQueueHandlerTask(), 50);
      }
      
      // Public --------------------------------------------------------
  @@ -262,10 +294,10 @@
         try {
            trans = tm.getTransaction();
         } catch (javax.transaction.SystemException sysE) {
  -         log.warning("System exception getting transaction for preload - can't get 
preloaded data for "+entityKey);
  +         log.warning("System exception getting transaction for preload - can't 
preload data for "+entityKey);
            return;
         }
  -//log.debug("PRELOAD: adding preload for "+entityKey+" in transaction "+(trans != 
null ? trans.toString() : "NONE"));
  +//log.debug("PRELOAD: adding preload for "+entityKey+" in transaction "+(trans != 
null ? trans.toString() : "NONE")+" entityData="+entityData);
         
         if (trans != null) {
            synchronized (preloadedData) {
  @@ -283,11 +315,13 @@
                  entitiesInTransaction = new HashMap();
                  preloadedData.put(trans, entitiesInTransaction);
               }
  -            entitiesInTransaction.put(entityKey, entityData);
  +            PreloadData preloadData = new PreloadData(trans, entityKey, entityData, 
preloadRefQueue);
  +            entitiesInTransaction.put(entityKey, preloadData);
            }
         } else {
            synchronized (nonTransactionalPreloadData) {
  -            nonTransactionalPreloadData.put(entityKey, entityData);
  +            PreloadData preloadData = new PreloadData(null, entityKey, entityData, 
preloadRefQueue);
  +            nonTransactionalPreloadData.put(entityKey, preloadData);
            }
         }
      }
  @@ -306,19 +340,36 @@
         }
         
         Object[] result = null;
  +      PreloadData preloadData = null;
         if (trans != null) {
  -         synchronized (preloadedData) {
  -            Map entitiesInTransaction = (Map)preloadedData.get(trans);
  -            if (entitiesInTransaction != null)
  -               result = (Object[])entitiesInTransaction.get(entityKey);
  -            //remove it now?
  +         Map entitiesInTransaction = null;
  +         // 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 
  +         //    method), and who cares if another is added/removed?
  +//         synchronized (preloadedData) {
  +            entitiesInTransaction = (Map)preloadedData.get(trans);
  +//         }
  +         if (entitiesInTransaction != null) {
  +            synchronized (entitiesInTransaction) {
  +               preloadData = (PreloadData)entitiesInTransaction.get(entityKey);
  +               entitiesInTransaction.remove(entityKey);
  +            }
            }
         } else {
            synchronized (nonTransactionalPreloadData) {
  -            result = (Object[])nonTransactionalPreloadData.get(entityKey);
  +            preloadData = (PreloadData)nonTransactionalPreloadData.get(entityKey);
  +            nonTransactionalPreloadData.remove(entityKey);
            }
         }
  -//log.debug("PRELOAD: returning "+result+" as preload for "+entityKey);
  +      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;
      }
      
  @@ -333,38 +384,71 @@
      
      
      // Private -------------------------------------------------------
  -   /** an inner class used to key the FinderResults by their finder method and
  -    *  the transaction they're invoked within
  +   
  +   /** 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 {
  +     public void execute() throws Exception {
  +         PreloadData preloadData = (PreloadData)preloadRefQueue.poll();
  +         int handled = 0;
  +         while (preloadData != null && handled < 10) {
  +            log.debug("PRELOAD: clearing "+preloadData.getKey());
  +            if (preloadData.getTransaction() != null) {
  +               Map entitiesInTransaction = null;
  +               // 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 
  +               //    method), and who cares if another is added/removed?
  +      //         synchronized (preloadedData) {
  +                  entitiesInTransaction = 
(Map)preloadedData.get(preloadData.getTransaction());
  +      //         }
  +               if (entitiesInTransaction != null) {
  +                  synchronized (entitiesInTransaction) {
  +                     entitiesInTransaction.remove(preloadData.getKey());
  +                  }
  +               }
  +            } else {
  +               synchronized (nonTransactionalPreloadData) {
  +                  nonTransactionalPreloadData.remove(preloadData.getKey());
  +               }
  +            }
  +            preloadData.empty();
  +            handled++;
  +            
  +            preloadData = (PreloadData)preloadRefQueue.poll();
  +         }
  +      }
  +   }
  +   /** 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 static class PreloadDataKey {
  -      private Object entityKey;
  -      private Transaction transaction;
  -      
  -      private int hashCode;
  +   private class PreloadData extends SoftReference {
  +      private Object key;
  +      private Transaction trans;
         
  -      public PreloadDataKey(Object entityKey, Transaction transaction) {
  -         this.entityKey = entityKey;
  -         this.transaction = transaction;
  -         
  -         //accumulate the hashcode. 
  -         /** @todo investigate ways of combining these that will give the least 
collisions */
  -         this.hashCode = entityKey.hashCode();
  -         if (transaction != null)
  -            this.hashCode += transaction.hashCode();
  +      PreloadData(Transaction trans, Object key, Object[] data, ReferenceQueue 
queue) {
  +         super(data, queue);
  +         this.trans = trans;
  +         this.key = key;
         }
         
  -      public int hashCode() {
  -         return hashCode;
  +      Transaction getTransaction() {
  +         return trans;
         }
  -      public boolean equals(Object o) {
  -         if (o instanceof PreloadDataKey) {
  -            PreloadDataKey other = (PreloadDataKey)o;
  -            return (other.entityKey.equals(this.entityKey)) &&
  -                   ( (other.transaction == null && this.transaction == null) ||
  -                     ( (other.transaction != null && this.transaction != null) &&
  -                       (other.transaction.equals(this.transaction)) ) );
  -         }
  -         return false;
  +      Object getKey() {
  +         return key;
  +      }
  +      Object[] getData() {
  +         return (Object[])get();
  +      }
  +      
  +      /** Named empty to not collide with superclass clear */
  +      public void empty() {
  +         key = null;
  +         trans = null;
         }
      }
      
  
  
  
  1.10      +5 -2      
jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCFindByCommand.java
  
  Index: JDBCFindByCommand.java
  ===================================================================
  RCS file: 
/cvsroot/jboss/jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCFindByCommand.java,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- JDBCFindByCommand.java    2001/06/13 06:52:17     1.9
  +++ JDBCFindByCommand.java    2001/06/18 14:34:27     1.10
  @@ -27,7 +27,8 @@
    * @author <a href="mailto:[EMAIL PROTECTED]";>Joe Shevland</a>
    * @author <a href="mailto:[EMAIL PROTECTED]";>Justin Forder</a>
    * @author <a href="mailto:[EMAIL PROTECTED]";>danch (Dan Christopherson)</a>
  - * @version $Revision: 1.9 $
  + * @author <a href="mailto:[EMAIL PROTECTED]";>Torben Jäger</a>
  + * @version $Revision: 1.10 $
    */
   public class JDBCFindByCommand extends JDBCFinderCommand
   {
  @@ -55,7 +56,9 @@
         {
            CMPFieldMetaData fi = (CMPFieldMetaData)iter.next();
            
  -         if (cmpFieldName.equals(fi.getName().toLowerCase()))
  +         String lastComponentOfName = 
  +            CMPFieldMetaData.getLastComponent(fi.getName()).toLowerCase();
  +         if (cmpFieldName.equals(lastComponentOfName))
            {
               cmpField = fi;
            }
  
  
  
  1.10      +3 -2      
jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCFindEntitiesCommand.java
  
  Index: JDBCFindEntitiesCommand.java
  ===================================================================
  RCS file: 
/cvsroot/jboss/jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCFindEntitiesCommand.java,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- JDBCFindEntitiesCommand.java      2001/05/27 00:49:15     1.9
  +++ JDBCFindEntitiesCommand.java      2001/06/18 14:34:27     1.10
  @@ -33,7 +33,7 @@
    * @author <a href="mailto:[EMAIL PROTECTED]";>Marc Fleury</a>
    * @author <a href="mailto:[EMAIL PROTECTED]";>Joe Shevland</a>
    * @author <a href="mailto:[EMAIL PROTECTED]";>Justin Forder</a>
  - * @version $Revision: 1.9 $
  + * @version $Revision: 1.10 $
    */
   public class JDBCFindEntitiesCommand implements JPMFindEntitiesCommand
   {
  @@ -74,7 +74,8 @@
                         }
                  }
          } catch (Exception e) {
  -             // for some reason, this failed; try to use defined or automatic 
instead
  +        // for some reason, this failed; try to use defined or automatic instead
  +        factory.getLog().warning("Error initializing custom finder 
"+e.getMessage());
          }
   
         // Make commands for the defined finders
  
  
  

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

Reply via email to