Ok aaron amid his general craziness did raise a problem with the home
exceptions and a missing lock... yes a missplaced else, I just commited the
fix in CVS.
Thank you aaron ;-)
Also in there is the stuff that I saw yesterday at SUN, namely that a notify
will work better,
regards
marc
|-----Original Message-----
|From: [EMAIL PROTECTED]
|[mailto:[EMAIL PROTECTED]]On Behalf Of jBoss CVS
|Development
|Sent: Saturday, October 21, 2000 2:32 PM
|To: [EMAIL PROTECTED]
|Subject: [jBoss-Dev] CVS update:
|jboss/src/main/org/jboss/ejb/pluginsEntitySynchronizationInterceptor.jav
|a EntityInstanceInterceptor.ja
|
|
| User: fleury
| Date: 00/10/21 14:32:10
|
| Modified: src/main/org/jboss/ejb/plugins
| EntitySynchronizationInterceptor.java
| EntityInstanceInterceptor.java
| AbstractInstancePool.java
| Log:
| fix for lock on home exception... the pools notifyAll on free
|
| Revision Changes Path
| 1.27 +384 -384
|jboss/src/main/org/jboss/ejb/plugins/EntitySynchronizationInterceptor.java
|
| Index: EntitySynchronizationInterceptor.java
| ===================================================================
| RCS file:
|/products/cvs/ejboss/jboss/src/main/org/jboss/ejb/plugins/EntitySyn
|chronizationInterceptor.java,v
| retrieving revision 1.26
| retrieving revision 1.27
| diff -u -r1.26 -r1.27
| --- EntitySynchronizationInterceptor.java 2000/10/17 23:47:02 1.26
| +++ EntitySynchronizationInterceptor.java 2000/10/21 21:32:09 1.27
| @@ -48,393 +48,393 @@
| * @see <related>
| * @author Rickard �berg ([EMAIL PROTECTED])
| * @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a>
| -* @version $Revision: 1.26 $
| +* @version $Revision: 1.27 $
| */
| public class EntitySynchronizationInterceptor
| extends AbstractInterceptor
| {
| - // Constants -----------------------------------------------------
| -
| - // Attributes ----------------------------------------------------
| -
| - /**
| - * The current commit option.
| - */
| - protected int commitOption;
| -
| - /**
| - * The container of this interceptor.
| - */
| - protected EntityContainer container;
| -
| - /**
| - * Optional isModified method
| - */
| - protected Method isModified;
| -
| - // Static --------------------------------------------------------
| -
| - // Constructors --------------------------------------------------
| -
| - // Public --------------------------------------------------------
| - public void setContainer(Container container)
| -
| - this.container = (EntityContainer)container;
| - }
| -
| - public void init()
| - throws Exception
| - {
| - commitOption =
|container.getBeanMetaData().getContainerConfiguration().getCommitOption();
| - // Check for isModified method
| - try
| - {
| - isModified =
|container.getBeanClass().getMethod("isModified", new Class[0]);
| - if
|(!isModified.getReturnType().equals(Boolean.TYPE))
| - isModified = null; // Has to have
|"boolean" as return type!
| - } catch (Exception e)
| - {
| - // Ignore
| - }
| - }
| -
| - public Container getContainer()
| - {
| - return container;
| - }
| -
| - /**
| - * Register a transaction synchronization callback with a context.
| - */
| - private void register(EntityEnterpriseContext ctx, Transaction tx)
| - {
| - // Create a new synchronization
| - InstanceSynchronization synch = new
|InstanceSynchronization(tx, ctx);
| -
| - try {
| - // OSH: An extra check to avoid warning.
| - // Can go when we are sure that we no longer get
| - // the JTA violation warning.
| - if (tx.getStatus() ==
|Status.STATUS_MARKED_ROLLBACK) {
| -
| - ctx.setValid(false);
| -
| - return;
| - }
| -
| - // We want to be notified when the
|transaction commits
| - tx.registerSynchronization(synch);
| -
| - } catch (RollbackException e) {
| -
| - // The state in the instance is to be
|discarded, we force a reload of state
| - ctx.setValid(false);
| -
| - } catch (Exception e) {
| -
| - throw new EJBException(e);
| -
| - }
| - }
| -
| - private void deregister(EntityEnterpriseContext ctx)
| - {
| - // MF FIXME: I suspect this is redundant now
| - // (won't the pool clean it up?)
| -
| - // Deassociate ctx with tx
| - // OSH: TxInterceptor seems to do this:
|ctx.setTransaction(null);
| - // OSH: Pool seems to do this: ctx.setInvoked(false);
| - }
| -
| - // Interceptor implementation --------------------------------------
| -
| - public Object invokeHome(MethodInvocation mi)
| - throws Exception
| - {
| - try {
| - return getNext().invokeHome(mi);
| - } finally {
| - // Anonymous was sent in, so if it has an
|id it was created
| - EntityEnterpriseContext ctx =
|(EntityEnterpriseContext)mi.getEnterpriseContext();
| - if (ctx.getId() != null) {
| - Transaction tx = mi.getTransaction();
| -
| - if (tx != null && tx.getStatus() ==
|Status.STATUS_ACTIVE)
| - register(ctx, tx); // Set tx
| -
| - // Currently synched with underlying storage
| - ctx.setValid(true);
| - }
| - }
| - }
| -
| - public Object invoke(MethodInvocation mi)
| - throws Exception
| - {
| - // We are going to work with the context a lot
| - EntityEnterpriseContext ctx =
|(EntityEnterpriseContext)mi.getEnterpriseContext();
| -
| - // The Tx coming as part of the Method Invocation
| - Transaction tx = mi.getTransaction();
| -
| - //Logger.debug("CTX in: isValid():"+ctx.isValid()+"
|isInvoked():"+ctx.isInvoked());
| - //Logger.debug("newTx: "+ tx);
| -
| - // Is my state valid?
| - if (!ctx.isValid()) {
| -
| - // If not tell the persistence manager to
|load the state
| -
|((EntityContainer)getContainer()).getPersistenceManager().loadEntity(ctx);
| -
| - // Now the state is valid
| - ctx.setValid(true);
| - }
| -
| - // So we can go on with the invocation
| - //DEBUG Logger.debug("Tx is "+ ((tx ==
|null)? "null" : tx.toString()));
| -
| - // Invocation with a running Transaction
| -
| - if (tx != null && tx.getStatus() == Status.STATUS_ACTIVE) {
| -
| - try {
| -
| - //Invoke down the chain
| - return getNext().invoke(mi);
| -
| - }
| -
| - finally {
| -
| - // Do we have a valid bean (not removed)
| - if (ctx.getId() != null) {
| -
| - // If the context was not
|invoked previously...
| - if (!ctx.isInvoked()) {
| -
| - // It is now and
|this will cause ejbStore to be called...
| - ctx.setInvoked(true);
| -
| - // ... on a
|transaction callback that we register here.
| - register(ctx, tx);
| - }
| - }
| -
| - // Entity was removed
| - else {
| -
| - if (ctx.getTransaction() != null) {
| -
| - //DEBUG
|Logger.debug("CTX out: isValid():"+ctx.isValid()+"
|isInvoked():"+ctx.isInvoked());
| - //DEBUG
|Logger.debug("PresentTx:"+tx);
| -
| - // If a ctx still
|has a transaction we would need to deresgister the sync
| - // The simplest is
|to tell the pool to kill the instance if tx is present
| -
| - }
| - }
| - }
| - }
| -
| - //
| - else { // No tx
| - try {
| - Object result = getNext().invoke(mi);
| -
| - // Store after each invocation --
|not on exception though, or removal
| - // And skip reads too ("get" methods)
| - // OSH FIXME: Isn't this
|startsWith("get") optimization a violation of
| - // the EJB specification? Think of
|SequenceBean.getNext().
| - if (ctx.getId() != null)
| - {
| - boolean dirty = true;
| - // Check isModified bean flag
| - if (isModified != null)
| - {
| - dirty =
|((Boolean)isModified.invoke(ctx.getInstance(), new
|Object[0])).booleanValue();
| - }
| -
| - // Store entity
| - if (dirty)
| -
|((EntityContainer)getContainer()).getPersistenceManager().storeEntity(ctx);
| - }
| -
| - return result;
| - } catch (Exception e) {
| - // Exception - force reload on next call
| - ctx.setValid(false);
| - throw e;
| - }
| - }
| - }
| -
| -
| - // Protected ----------------------------------------------------
| -
| - // Inner classes -------------------------------------------------
| -
| - private class InstanceSynchronization
| - implements Synchronization
| - {
| - /**
| - * The transaction we follow.
| - */
| - private Transaction tx;
| -
| - /**
| - * The context we manage.
| - */
| - private EntityEnterpriseContext ctx;
| -
| - /**
| - * Create a new instance synchronization instance.
| - */
| - InstanceSynchronization(Transaction tx,
|EntityEnterpriseContext ctx)
| - {
| - this.tx = tx;
| - this.ctx = ctx;
| - }
| -
| - // Synchronization implementation
|-----------------------------
| -
| - public void beforeCompletion()
| - {
| - // DEBUG Logger.debug("beforeCompletion
|called for ctx "+ctx.hashCode());
| -
| - if (ctx.getId() != null) {
| -
| - // This is an independent point of
|entry. We need to make sure the
| - // thread is associated with the
|right context class loader
| - ClassLoader oldCl =
|Thread.currentThread().getContextClassLoader();
| -
|Thread.currentThread().setContextClassLoader(container.getClassLoader());
| -
| - try {
| -
| - try {
| -
| - // MF FIXME: should
|we throw an exception if lock is present (app error)
| - // it would mean
|that someone is commiting when all the work is not done
| -
| - // Store instance
|if business method was invoked
| - if (ctx.isInvoked()) {
| -
| - //DEBUG
|Logger.debug("EntitySynchronization sync calling store on ctx
|"+ctx.hashCode());
| -
| - // Check
|isModified bean flag
| - boolean
|dirty = true;
| - if
|(isModified != null)
| - {
| - try
| - {
| -
|dirty = ((Boolean)isModified.invoke(ctx.getInstance(), new
|Object[0])).booleanValue();
| - }
|catch (Exception e)
| - {
| -
|// Ignore
| -
|e.printStackTrace();
| - }
| - }
| -
| - if (dirty)
| -
|container.getPersistenceManager().storeEntity(ctx);
| - }
| - } catch (NoSuchEntityException e) {
| - // Object has been
|removed -- ignore
| - }
| - }
| - catch (RemoteException e) {
| - Logger.exception(e);
| -
| - // Store failed -> rollback!
| - try {
| - tx.setRollbackOnly();
| - } catch (SystemException ex) {
| - // DEBUG
|ex.printStackTrace();
| - } catch (IllegalStateException ex) {
| - // DEBUG
|ex.printStackTrace();
| - }
| - }
| - finally {
| -
| -
|Thread.currentThread().setContextClassLoader(oldCl);
| - }
| - }
| - }
| -
| -
| - public void afterCompletion(int status)
| - {
| -
| - // This is an independent point of entry.
|We need to make sure the
| - // thread is associated with the right
|context class loader
| - ClassLoader oldCl =
|Thread.currentThread().getContextClassLoader();
| -
|Thread.currentThread().setContextClassLoader(container.getClassLoader());
| -
| - try
| - {
| -
| - //DEBUG
|Logger.debug("afterCompletion called for ctx "+ctx.hashCode());
| -
| - // If rolled back -> invalidate instance
| - // If removed -> send back to the pool
| - if (status ==
|Status.STATUS_ROLLEDBACK || ctx.getId() == null)
| -
| - try
| -
| - // finish the
|transaction association
| - ctx.setTransaction(null);
| -
| - // remove from the cache
| -
|container.getInstanceCache().remove(ctx.getCacheKey());
| -
| - // return to pool
| -
|container.getInstancePool().free(ctx);
| -
| - } catch (Exception e) {
| - // Ignore
| - }
| -
| - } else
| -
| - // We are afterCompletion
|so the invoked can be set to false (db sync is done)
| - ctx.setInvoked(false);
| -
| - switch (commitOption)
| - // Keep instance
|cached after tx commit
| - case
|ConfigurationMetaData.A_COMMIT_OPTION:
| - // The
|state is still valid (only point of access is us)
| - ctx.setValid(true);
| - break;
| -
| - // Keep instance
|active, but invalidate state
| - case
|ConfigurationMetaData.B_COMMIT_OPTION:
| - //
|Invalidate state (there might be other points of entry)
| -
|ctx.setValid(false);
| - break;
| -
| - // Invalidate
|everything AND Passivate instance
| - case
|ConfigurationMetaData.C_COMMIT_OPTION:
| - try
| -
|container.getInstanceCache().release(ctx);
| - } catch
|(Exception e)
| -
|Logger.debug(e);
| - }
| - break;
| - }
| -
| - // finish the transaction
|association
| - ctx.setTransaction(null);
| - }
| - }
| -
| - finally
| -
| -
|Thread.currentThread().setContextClassLoader(oldCl);
| -
| - // Notify all who are waiting for
|this tx to end, they are waiting since the locking logic
| - synchronized (ctx) {ctx.notifyAll();}
| - }
| - }
| - }
| + // Constants -----------------------------------------------------
| +
| + // Attributes ----------------------------------------------------
| +
| + /**
| + * The current commit option.
| + */
| + protected int commitOption;
| +
| + /**
| + * The container of this interceptor.
| + */
| + protected EntityContainer container;
| +
| + /**
| + * Optional isModified method
| + */
| + protected Method isModified;
| +
| + // Static --------------------------------------------------------
| +
| + // Constructors --------------------------------------------------
| +
| + // Public --------------------------------------------------------
| + public void setContainer(Container container)
| +
| + this.container = (EntityContainer)container;
| + }
| +
| + public void init()
| + throws Exception
| + {
| + commitOption =
|container.getBeanMetaData().getContainerConfiguration().getCommitOption();
| + // Check for isModified method
| + try
| + {
| + isModified =
|container.getBeanClass().getMethod("isModified", new Class[0]);
| + if (!isModified.getReturnType().equals(Boolean.TYPE))
| + isModified = null; // Has to have "boolean" as return type!
| + } catch (Exception e)
| + {
| + // Ignore
| + }
| + }
| +
| + public Container getContainer()
| + {
| + return container;
| + }
| +
| + /**
| + * Register a transaction synchronization callback with a context.
| + */
| + private void register(EntityEnterpriseContext ctx, Transaction tx)
| + {
| + // Create a new synchronization
| + InstanceSynchronization synch = new
|InstanceSynchronization(tx, ctx);
| +
| + try {
| + // OSH: An extra check to avoid warning.
| + // Can go when we are sure that we no longer get
| + // the JTA violation warning.
| + if (tx.getStatus() == Status.STATUS_MARKED_ROLLBACK) {
| +
| + ctx.setValid(false);
| +
| + return;
| + }
| +
| + // We want to be notified when the transaction commits
| + tx.registerSynchronization(synch);
| +
| + } catch (RollbackException e) {
| +
| + // The state in the instance is to be discarded, we
|force a reload of state
| + ctx.setValid(false);
| +
| + } catch (Exception e) {
| +
| + throw new EJBException(e);
| +
| + }
| + }
| +
| + private void deregister(EntityEnterpriseContext ctx)
| + {
| + // MF FIXME: I suspect this is redundant now
| + // (won't the pool clean it up?)
| +
| + // Deassociate ctx with tx
| + // OSH: TxInterceptor seems to do this: ctx.setTransaction(null);
| + // OSH: Pool seems to do this: ctx.setInvoked(false);
| + }
| +
| + // Interceptor implementation --------------------------------------
| +
| + public Object invokeHome(MethodInvocation mi)
| + throws Exception
| + {
| + try {
| + return getNext().invokeHome(mi);
| + } finally {
| + // Anonymous was sent in, so if it has an id it was created
| + EntityEnterpriseContext ctx =
|(EntityEnterpriseContext)mi.getEnterpriseContext();
| + if (ctx.getId() != null) {
| + Transaction tx = mi.getTransaction();
| +
| + if (tx != null && tx.getStatus() == Status.STATUS_ACTIVE)
| + register(ctx, tx); // Set tx
| +
| + // Currently synched with underlying storage
| + ctx.setValid(true);
| + }
| + }
| + }
| +
| + public Object invoke(MethodInvocation mi)
| + throws Exception
| + {
| + // We are going to work with the context a lot
| + EntityEnterpriseContext ctx =
|(EntityEnterpriseContext)mi.getEnterpriseContext();
| +
| + // The Tx coming as part of the Method Invocation
| + Transaction tx = mi.getTransaction();
| +
| + //Logger.debug("CTX in: isValid():"+ctx.isValid()+"
|isInvoked():"+ctx.isInvoked());
| + //Logger.debug("newTx: "+ tx);
| +
| + // Is my state valid?
| + if (!ctx.isValid()) {
| +
| + // If not tell the persistence manager to load the state
| +
|((EntityContainer)getContainer()).getPersistenceManager().loadEntity(ctx);
| +
| + // Now the state is valid
| + ctx.setValid(true);
| + }
| +
| + // So we can go on with the invocation
| + //DEBUG Logger.debug("Tx is "+ ((tx ==
|null)? "null" : tx.toString()));
| +
| + // Invocation with a running Transaction
| +
| + if (tx != null && tx.getStatus() == Status.STATUS_ACTIVE) {
| +
| + try {
| +
| + //Invoke down the chain
| + return getNext().invoke(mi);
| +
| + }
| +
| + finally {
| +
| + // Do we have a valid bean (not removed)
| + if (ctx.getId() != null) {
| +
| + // If the context was not invoked previously...
| + if (!ctx.isInvoked()) {
| +
| + // It is now and this will cause ejbStore to
|be called...
| + ctx.setInvoked(true);
| +
| + // ... on a transaction callback that we register here.
| + register(ctx, tx);
| + }
| + }
| +
| + // Entity was removed
| + else {
| +
| + if (ctx.getTransaction() != null) {
| +
| + //DEBUG Logger.debug("CTX out:
|isValid():"+ctx.isValid()+" isInvoked():"+ctx.isInvoked());
| + //DEBUG Logger.debug("PresentTx:"+tx);
| +
| + // If a ctx still has a transaction we would
|need to deresgister the sync
| + // The simplest is to tell the pool to kill
|the instance if tx is present
| +
| + }
| + }
| + }
| + }
| +
| + //
| + else { // No tx
| + try {
| + Object result = getNext().invoke(mi);
| +
| + // Store after each invocation -- not on exception
|though, or removal
| + // And skip reads too ("get" methods)
| + // OSH FIXME: Isn't this startsWith("get")
|optimization a violation of
| + // the EJB specification? Think of SequenceBean.getNext().
| + if (ctx.getId() != null)
| + {
| + boolean dirty = true;
| + // Check isModified bean flag
| + if (isModified != null)
| + {
| + dirty =
|((Boolean)isModified.invoke(ctx.getInstance(), new
|Object[0])).booleanValue();
| + }
| +
| + // Store entity
| + if (dirty)
| +
|((EntityContainer)getContainer()).getPersistenceManager().storeEntity(ctx);
| + }
| +
| + return result;
| + } catch (Exception e) {
| + // Exception - force reload on next call
| + ctx.setValid(false);
| + throw e;
| + }
| + }
| + }
| +
| +
| + // Protected ----------------------------------------------------
| +
| + // Inner classes -------------------------------------------------
| +
| + private class InstanceSynchronization
| + implements Synchronization
| + {
| + /**
| + * The transaction we follow.
| + */
| + private Transaction tx;
| +
| + /**
| + * The context we manage.
| + */
| + private EntityEnterpriseContext ctx;
| +
| + /**
| + * Create a new instance synchronization instance.
| + */
| + InstanceSynchronization(Transaction tx,
|EntityEnterpriseContext ctx)
| + {
| + this.tx = tx;
| + this.ctx = ctx;
| + }
| +
| + // Synchronization implementation -----------------------------
| +
| + public void beforeCompletion()
| + {
| + // DEBUG Logger.debug("beforeCompletion called for ctx
|"+ctx.hashCode());
| +
| + if (ctx.getId() != null) {
| +
| + // This is an independent point of entry. We need to
|make sure the
| + // thread is associated with the right context class loader
| + ClassLoader oldCl =
|Thread.currentThread().getContextClassLoader();
| +
|Thread.currentThread().setContextClassLoader(container.getClassLoader());
| +
| + try {
| +
| + try {
| +
| + // MF FIXME: should we throw an exception if
|lock is present (app error)
| + // it would mean that someone is commiting
|when all the work is not done
| +
| + // Store instance if business method was invoked
| + if (ctx.isInvoked()) {
| +
| + //DEBUG Logger.debug("EntitySynchronization
|sync calling store on ctx "+ctx.hashCode());
| +
| + // Check isModified bean flag
| + boolean dirty = true;
| + if (isModified != null)
| + {
| + try
| + {
| + dirty =
|((Boolean)isModified.invoke(ctx.getInstance(), new
|Object[0])).booleanValue();
| + } catch (Exception e)
| + {
| + // Ignore
| + e.printStackTrace();
| + }
| + }
| +
| + if (dirty)
| + container.getPersistenceManager().storeEntity(ctx);
| + }
| + } catch (NoSuchEntityException e) {
| + // Object has been removed -- ignore
| + }
| + }
| + catch (RemoteException e) {
| + Logger.exception(e);
| +
| + // Store failed -> rollback!
| + try {
| + tx.setRollbackOnly();
| + } catch (SystemException ex) {
| + // DEBUG ex.printStackTrace();
| + } catch (IllegalStateException ex) {
| + // DEBUG ex.printStackTrace();
| + }
| + }
| + finally {
| +
| + Thread.currentThread().setContextClassLoader(oldCl);
| + }
| + }
| + }
| +
| +
| + public void afterCompletion(int status)
| + {
| +
| + // This is an independent point of entry. We need to
|make sure the
| + // thread is associated with the right context class loader
| + ClassLoader oldCl =
|Thread.currentThread().getContextClassLoader();
| +
|Thread.currentThread().setContextClassLoader(container.getClassLoader());
| +
| + try
| + {
| +
| + //DEBUG Logger.debug("afterCompletion called for ctx
|"+ctx.hashCode());
| +
| + // If rolled back -> invalidate instance
| + // If removed -> send back to the pool
| + if (status == Status.STATUS_ROLLEDBACK || ctx.getId()
|== null)
| +
| + try
| +
| + // finish the transaction association
| + ctx.setTransaction(null);
| +
| + // remove from the cache
| + container.getInstanceCache().remove(ctx.getCacheKey());
| +
| + // return to pool
| + container.getInstancePool().free(ctx);
| +
| + } catch (Exception e) {
| + // Ignore
| + }
| +
| + } else
| +
| + // We are afterCompletion so the invoked can be
|set to false (db sync is done)
| + ctx.setInvoked(false);
| +
| + switch (commitOption)
| + // Keep instance cached after tx commit
| + case ConfigurationMetaData.A_COMMIT_OPTION:
| + // The state is still valid (only point of
|access is us)
| + ctx.setValid(true);
| + break;
| +
| + // Keep instance active, but invalidate state
| + case ConfigurationMetaData.B_COMMIT_OPTION:
| + // Invalidate state (there might be other
|points of entry)
| + ctx.setValid(false);
| + break;
| +
| + // Invalidate everything AND Passivate instance
| + case ConfigurationMetaData.C_COMMIT_OPTION:
| + try
| + container.getInstanceCache().release(ctx);
| + } catch (Exception e)
| + Logger.debug(e);
| + }
| + break;
| + }
| +
| + // finish the transaction association
| + ctx.setTransaction(null);
| + }
| + }
| +
| + finally
| +
| + Thread.currentThread().setContextClassLoader(oldCl);
| +
| + // Notify next waiting for this tx to end, they
|are waiting since the locking logic
| + synchronized (ctx) {ctx.notify();}
| + }
| + }
| + }
| }
|
|
|
|
| 1.23 +30 -16
|jboss/src/main/org/jboss/ejb/plugins/EntityInstanceInterceptor.java
|
| Index: EntityInstanceInterceptor.java
| ===================================================================
| RCS file:
|/products/cvs/ejboss/jboss/src/main/org/jboss/ejb/plugins/EntityIns
|tanceInterceptor.java,v
| retrieving revision 1.22
| retrieving revision 1.23
| diff -u -r1.22 -r1.23
| --- EntityInstanceInterceptor.java 2000/10/20 03:11:43 1.22
| +++ EntityInstanceInterceptor.java 2000/10/21 21:32:10 1.23
| @@ -44,7 +44,7 @@
| * @author Rickard �berg ([EMAIL PROTECTED])
| * @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a>
| * @author <a
|href="mailto:[EMAIL PROTECTED]">Sebastien Alborini</a>
| -* @version $Revision: 1.22 $
| +* @version $Revision: 1.23 $
| */
| public class EntityInstanceInterceptor
| extends AbstractInterceptor
| @@ -89,18 +89,22 @@
| // Always unlock, no matter what
| ctx.unlock();
|
| - // Still free? Not free if create() was called successfully
| - if (ctx.getId() == null)
| - {
| - container.getInstancePool().free(ctx);
| - }
| - else
| - {
| - // DEBUG Logger.debug("Entity was
|created; not returned to pool");
| - synchronized (ctx) {
| + synchronized (ctx) {
| +
| + // Still free? Not free if create() was called
|successfully
| + if (ctx.getId() == null)
| + {
| + container.getInstancePool().free(ctx);
| +
| + // the pool will notify all everyone
| + }
| + else
| + {
| + // DEBUG Logger.debug("Entity was
|created; not returned to pool");
|
| - //Let the waiters know
| - ctx.notifyAll();
| + //Let one waiter know
| + ctx.notify();
| +
| }
| }
| }
| @@ -146,7 +150,7 @@
| Logger.debug("LOCKING-WAITING
|(TRANSACTION) for id "+ctx.getId()+" ctx.hash "+ctx.hashCode()+"
|tx:"+((tx == null) ? "null" : tx.toString()));
|
| try {
| - ctx.wait();
| + ctx.wait(5000);
| } catch (InterruptedException ie) {}
|
| // Try your luck again
| @@ -173,7 +177,7 @@
| Logger.debug("LOCKING-WAITING
|(CTX) for id "+ctx.getId()+" ctx.hash "+ctx.hashCode());
|
| try{
| - ctx.wait();
| + ctx.wait(5000);
| } catch (InterruptedException ie) {}
|
| // Try your luck again
| @@ -240,11 +244,21 @@
|
| // It has been removed -> send to the pool
| container.getInstancePool().free(ctx);
| +
| + // The pool will notify everyone waiting on this
| +
| }
| }
|
| - // notify the thread waiting on ctx
| - synchronized (ctx) { ctx.notifyAll();}
| + else {
| +
| + // MF FIXME for speed reason I use notify
| + // however we would need to lock on the tx
|and ctx so we can
| + // notify the right population, slightly
|more complicated...
| +
| + // notify the next thread waiting on ctx
| + synchronized (ctx) { ctx.notify();}
| + }
| }
| }
| }
|
|
|
| 1.7 +15 -12
|jboss/src/main/org/jboss/ejb/plugins/AbstractInstancePool.java
|
| Index: AbstractInstancePool.java
| ===================================================================
| RCS file:
|/products/cvs/ejboss/jboss/src/main/org/jboss/ejb/plugins/AbstractI
|nstancePool.java,v
| retrieving revision 1.6
| retrieving revision 1.7
| diff -u -r1.6 -r1.7
| --- AbstractInstancePool.java 2000/10/09 20:15:36 1.6
| +++ AbstractInstancePool.java 2000/10/21 21:32:10 1.7
| @@ -31,7 +31,7 @@
| *
| * @see <related>
| * @author Rickard �berg ([EMAIL PROTECTED])
| - * @version $Revision: 1.6 $
| + * @version $Revision: 1.7 $
| */
| public abstract class AbstractInstancePool
| implements InstancePool, XmlLoadable
| @@ -128,8 +128,11 @@
| // Pool it
| //DEBUG Logger.debug("Free
|instance:"+ctx.getId()+"#"+ctx.getTransaction());
|
| - ctx.clear();
| + ctx.clear();
|
| + // Free everyone waiting on that ctx
| + synchronized (ctx) {ctx.notifyAll();}
| +
| if (pool.size() < maxSize)
| {
| pool.push(ctx);
| @@ -153,16 +156,16 @@
|
| // Z implementation ----------------------------------------------
|
| - // XmlLoadable implementation
| - public void importXml(Element element) throws DeploymentException {
| - String maximumSize =
|MetaData.getElementContent(MetaData.getUniqueChild(element,
|"MaximumSize"));
| - try {
| - maxSize = Integer.parseInt(maximumSize);
| - } catch (NumberFormatException e) {
| - throw new DeploymentException("Invalid
|MaximumSize value for instance pool configuration");
| - }
| - }
| -
| + // XmlLoadable implementation
| + public void importXml(Element element) throws DeploymentException {
| + String maximumSize =
|MetaData.getElementContent(MetaData.getUniqueChild(element,
|"MaximumSize"));
| + try {
| + maxSize = Integer.parseInt(maximumSize);
| + } catch (NumberFormatException e) {
| + throw new DeploymentException("Invalid MaximumSize
|value for instance pool configuration");
| + }
| + }
| +
| // Package protected ---------------------------------------------
|
| // Protected -----------------------------------------------------
|
|
|
|
|