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