User: fleury
Date: 00/08/09 21:24:02
Modified: src/main/org/jboss/ejb/plugins
EntitySynchronizationInterceptor.java
Log:
fixing the store bug (tx==null) should read (tx!=null)
Revision Changes Path
1.8 +304 -302
jboss/src/main/org/jboss/ejb/plugins/EntitySynchronizationInterceptor.java
Index: EntitySynchronizationInterceptor.java
===================================================================
RCS file:
/products/cvs/ejboss/jboss/src/main/org/jboss/ejb/plugins/EntitySynchronizationInterceptor.java,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- EntitySynchronizationInterceptor.java 2000/07/28 00:25:18 1.7
+++ EntitySynchronizationInterceptor.java 2000/08/10 04:24:02 1.8
@@ -1,9 +1,9 @@
/*
- * jBoss, the OpenSource EJB server
- *
- * Distributable under GPL license.
- * See terms of license at gnu.org.
- */
+* jBoss, the OpenSource EJB server
+*
+* Distributable under GPL license.
+* See terms of license at gnu.org.
+*/
package org.jboss.ejb.plugins;
import java.lang.reflect.Method;
@@ -38,40 +38,41 @@
import org.jboss.logging.Logger;
/**
- * This container filter takes care of EntityBean persistance.
- * Specifically, it calls ejbStore at appropriate times
- *
- * Possible options:
- * After each call
- * On tx commit
- *
- * @see <related>
- * @author Rickard �berg ([EMAIL PROTECTED])
- * @version $Revision: 1.7 $
- */
+* This container filter takes care of EntityBean persistance.
+* Specifically, it calls ejbStore at appropriate times
+*
+* Possible options:
+* After each call
+* On tx commit
+*
+* @see <related>
+* @author Rickard �berg ([EMAIL PROTECTED])
+* @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a>
+* @version $Revision: 1.8 $
+*/
public class EntitySynchronizationInterceptor
- extends AbstractInterceptor
+extends AbstractInterceptor
{
- // Constants -----------------------------------------------------
- public static final int TIMEOUT = 10000;
+ // Constants -----------------------------------------------------
+ public static final int TIMEOUT = 10000;
// Commit time options
- public static final int A = 0; // Keep instance cached
- public static final int B = 1; // Invalidate state
- public static final int C = 2; // Passivate
-
- // Attributes ----------------------------------------------------
- HashMap synchs = new HashMap(); // tx -> synch
+ public static final int A = 0; // Keep instance cached
+ public static final int B = 1; // Invalidate state
+ public static final int C = 2; // Passivate
+ // Attributes ----------------------------------------------------
+ HashMap synchs = new HashMap(); // tx -> synch
+
int commitOption = A;
protected EntityContainer container;
-
- // Static --------------------------------------------------------
-
- // Constructors --------------------------------------------------
-
- // Public --------------------------------------------------------
+
+ // Static --------------------------------------------------------
+
+ // Constructors --------------------------------------------------
+
+ // Public --------------------------------------------------------
public void setContainer(Container container)
{
this.container = (EntityContainer)container;
@@ -92,306 +93,307 @@
return commitOption;
}
- public void register(EnterpriseContext ctx, Transaction tx)
- {
- // Associate ctx with tx
- synchronized (synchs)
- {
- // Get synchronization for this tx - create if there is none
- InstanceSynchronization synch = (InstanceSynchronization)synchs.get(tx);
- if (synch == null)
- {
- // Register new synch with current tx
- synch = new InstanceSynchronization(tx);
- synchs.put(tx, synch);
-
- try
- {
- tx.registerSynchronization(synch);
- } catch (Exception e)
- {
- throw new EJBException(e);
- }
- }
-
- synch.add(ctx);
- ((EntityEnterpriseContext)ctx).setTransaction(tx);
- }
- }
-
- public void deregister(EntityEnterpriseContext ctx, Transaction tx)
- {
- // Deassociate ctx with tx
- synchronized (synchs)
- {
- // Get synchronization for this tx
- InstanceSynchronization synch = (InstanceSynchronization)synchs.get(tx);
- if (synch == null)
- {
- return;
- }
-
- synch.remove(ctx);
- ctx.setTransaction(null);
- 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
+ public void register(EnterpriseContext ctx, Transaction tx)
+ {
+ // Associate ctx with tx
+ synchronized (synchs)
+ {
+ // Get synchronization for this tx - create if there is none
+ InstanceSynchronization synch =
(InstanceSynchronization)synchs.get(tx);
+ if (synch == null)
+ {
+ // Register new synch with current tx
+ synch = new InstanceSynchronization(tx);
+ synchs.put(tx, synch);
+
+ try
+ {
+ tx.registerSynchronization(synch);
+ } catch (Exception e)
+ {
+ throw new EJBException(e);
+ }
+ }
+
+ synch.add(ctx);
+ ((EntityEnterpriseContext)ctx).setTransaction(tx);
+ }
+ }
+
+ public void deregister(EntityEnterpriseContext ctx, Transaction tx)
+ {
+ // Deassociate ctx with tx
+ synchronized (synchs)
+ {
+ // Get synchronization for this tx
+ InstanceSynchronization synch =
(InstanceSynchronization)synchs.get(tx);
+ if (synch == null)
+ {
+ return;
+ }
+
+ synch.remove(ctx);
+ ctx.setTransaction(null);
+ 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
EnterpriseContext ctx = mi.getEnterpriseContext();
- if (ctx.getId() != null)
- {
+ if (ctx.getId() != null)
+ {
if (mi.getTransaction() != null &&
- mi.getTransaction().getStatus() ==
Status.STATUS_ACTIVE)
+ mi.getTransaction().getStatus() ==
Status.STATUS_ACTIVE)
{
// Set tx
register(ctx, mi.getTransaction());
}
-
- // Currently synched with underlying storage
- ((EntityEnterpriseContext)ctx).setSynchronized(true);
- }
- }
- }
-
- public Object invoke(MethodInvocation mi)
- throws Exception
- {
- EntityEnterpriseContext ctx =
(EntityEnterpriseContext)mi.getEnterpriseContext();
-
-
- Transaction tx = ctx.getTransaction();
- Transaction current = mi.getTransaction();
-
-//DEBUG Logger.debug("TX:"+(current.getStatus() == Status.STATUS_ACTIVE));
-
- if (current != null &&
- current.getStatus() == Status.STATUS_ACTIVE)
- {
- // Synchronize with DB
- if (!ctx.isSynchronized())
- {
-//DEBUG Logger.debug("SYNCH");
-
((EntityContainer)getContainer()).getPersistenceManager().loadEntity(ctx);
- ctx.setSynchronized(true);
- }
-
- try
- {
- return getNext().invoke(mi);
- } finally
- {
- if (ctx.getId() != null)
- {
- // Associate ctx with tx
- if (tx == null)
- {
- ctx.setInvoked(true); // This causes ejbStore to be invoked on tx
commit
- register(ctx, current);
- }
- } else
- {
- // Entity was removed
- if (ctx.getTransaction() != null)
- {
- // Disassociate ctx with tx
- deregister(ctx, current);
- }
- }
- }
- } else
- {
- // No tx
-
- // Synchronize with DB
- if (!ctx.isSynchronized())
- {
-//DEBUG Logger.debug("SYNCH");
-
((EntityContainer)getContainer()).getPersistenceManager().loadEntity(ctx);
- ctx.setSynchronized(true);
- }
-
- try
- {
- Object result = getNext().invoke(mi);
-
- // Store after each invocation -- not on exception though, or removal
+
+ // Currently synched with underlying storage
+ ((EntityEnterpriseContext)ctx).setSynchronized(true);
+ }
+ }
+ }
+
+ public Object invoke(MethodInvocation mi)
+ throws Exception
+ {
+ EntityEnterpriseContext ctx =
(EntityEnterpriseContext)mi.getEnterpriseContext();
+
+
+ Transaction tx = ctx.getTransaction();
+ Transaction current = mi.getTransaction();
+
+ //DEBUG Logger.debug("TX:"+(current.getStatus() ==
Status.STATUS_ACTIVE));
+
+ if (current != null &&
+ current.getStatus() == Status.STATUS_ACTIVE)
+ {
+
+ // Synchronize with DB
+ if (!ctx.isSynchronized())
+ {
+ //DEBUG Logger.debug("SYNCH");
+
((EntityContainer)getContainer()).getPersistenceManager().loadEntity(ctx);
+ ctx.setSynchronized(true);
+ }
+
+ try
+ {
+ return getNext().invoke(mi);
+ } finally
+ {
+ if (ctx.getId() != null)
+ {
+ // Associate ctx with tx
+ if (tx != null)
+ {
+ ctx.setInvoked(true); // This causes
ejbStore to be invoked on tx commit
+ register(ctx, current);
+ }
+ } else
+ {
+ // Entity was removed
+ if (ctx.getTransaction() != null)
+ {
+ // Disassociate ctx with tx
+ deregister(ctx, current);
+ }
+ }
+ }
+ } else
+ {
+ // No tx
+
+ // Synchronize with DB
+ if (!ctx.isSynchronized())
+ {
+ //DEBUG Logger.debug("SYNCH");
+
((EntityContainer)getContainer()).getPersistenceManager().loadEntity(ctx);
+ ctx.setSynchronized(true);
+ }
+
+ try
+ {
+ Object result = getNext().invoke(mi);
+
+ // Store after each invocation -- not on exception
though, or removal
// And skip reads too ("get" methods)
- if (ctx.getId() != null && !mi.getMethod().getName().startsWith("get"))
-
((EntityContainer)getContainer()).getPersistenceManager().storeEntity(ctx);
-
- return result;
- } catch (Exception e)
- {
- // Exception - force reload on next call
- ctx.setSynchronized(false);
- throw e;
- }
- }
- }
-
- // Protected ----------------------------------------------------
-
- // Inner classes -------------------------------------------------
- class InstanceSynchronization
- implements Synchronization
- {
- ArrayList ctxList = new ArrayList();
- Transaction tx;
-
- InstanceSynchronization(Transaction tx)
- {
- this.tx = tx;
- }
-
- public void add(EnterpriseContext ctx)
- {
- ctxList.add(ctx.getId());
- }
-
- public void remove(EnterpriseContext ctx)
- {
- ctxList.remove(ctx.getId());
- }
-
- // Synchronization implementation -----------------------------
- public void beforeCompletion()
- {
- InstanceCache cache = ((EntityContainer)getContainer()).getInstanceCache();
-
- try
- {
-
- for (int i = 0; i < ctxList.size(); i++)
- {
- // Lock instance
- try
- {
- EntityEnterpriseContext ctx =
(EntityEnterpriseContext)cache.get(ctxList.get(i));
- // Store instance if business method was
- if (ctx.isInvoked())
-
((EntityContainer)getContainer()).getPersistenceManager().storeEntity(ctx);
-
- // Save for after completion
- ctxList.set(i, ctx);
- } catch (NoSuchEntityException e)
- {
- // Object has been removed -- ignore
- }
- }
- } catch (RemoteException e)
- {
- // Store failed -> rollback!
- try
- {
- tx.setRollbackOnly();
- } catch (SystemException ex)
- {
- ex.printStackTrace();
- }
- }
- }
-
- public void afterCompletion(int status)
- {
- // If rolled back -> invalidate instance
- if (status == Status.STATUS_ROLLEDBACK)
- {
-
- for (int i = 0; i < ctxList.size(); i++)
- {
- try
- {
- EntityEnterpriseContext ctx =
(EntityEnterpriseContext)ctxList.get(i);
-
- ctx.setId(null);
- ctx.setTransaction(null);
- container.getInstanceCache().remove(ctx);
- container.getInstancePool().free(ctx); // TODO: should this be
done? still valid instance?
- } catch (Exception e)
- {
- // Ignore
- }
- }
- } else
- {
- for (int i = 0; i < ctxList.size(); i++)
- {
+ if (ctx.getId() != null &&
!mi.getMethod().getName().startsWith("get"))
+
((EntityContainer)getContainer()).getPersistenceManager().storeEntity(ctx);
+
+ return result;
+ } catch (Exception e)
+ {
+ // Exception - force reload on next call
+ ctx.setSynchronized(false);
+ throw e;
+ }
+ }
+ }
+
+ // Protected ----------------------------------------------------
+
+ // Inner classes -------------------------------------------------
+ class InstanceSynchronization
+ implements Synchronization
+ {
+ ArrayList ctxList = new ArrayList();
+ Transaction tx;
+
+ InstanceSynchronization(Transaction tx)
+ {
+ this.tx = tx;
+ }
+
+ public void add(EnterpriseContext ctx)
+ {
+ ctxList.add(ctx.getId());
+ }
+
+ public void remove(EnterpriseContext ctx)
+ {
+ ctxList.remove(ctx.getId());
+ }
+
+ // Synchronization implementation -----------------------------
+ public void beforeCompletion()
+ {
+ InstanceCache cache =
((EntityContainer)getContainer()).getInstanceCache();
+
+ try
+ {
+
+ for (int i = 0; i < ctxList.size(); i++)
+ {
+ // Lock instance
+ try
+ {
+ EntityEnterpriseContext ctx =
(EntityEnterpriseContext)cache.get(ctxList.get(i));
+ // Store instance if business method
was
+ if (ctx.isInvoked())
+
((EntityContainer)getContainer()).getPersistenceManager().storeEntity(ctx);
+
+ // Save for after completion
+ ctxList.set(i, ctx);
+ } catch (NoSuchEntityException e)
+ {
+ // Object has been removed -- ignore
+ }
+ }
+ } catch (RemoteException e)
+ {
+ // Store failed -> rollback!
+ try
+ {
+ tx.setRollbackOnly();
+ } catch (SystemException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ }
+
+ public void afterCompletion(int status)
+ {
+ // If rolled back -> invalidate instance
+ if (status == Status.STATUS_ROLLEDBACK)
+ {
+
+ for (int i = 0; i < ctxList.size(); i++)
+ {
+ try
+ {
+ EntityEnterpriseContext ctx =
(EntityEnterpriseContext)ctxList.get(i);
+
+ ctx.setId(null);
+ ctx.setTransaction(null);
+
container.getInstanceCache().remove(ctx);
+ container.getInstancePool().free(ctx);
// TODO: should this be done? still valid instance?
+ } catch (Exception e)
+ {
+ // Ignore
+ }
+ }
+ } else
+ {
+ for (int i = 0; i < ctxList.size(); i++)
+ {
switch (commitOption)
{
// Keep instance cached after tx commit
case A:
try
{
- EntityEnterpriseContext ctx
= (EntityEnterpriseContext)ctxList.get(i);
- ctx.setTransaction(null);
- ctx.setInvoked(false);
-
container.getInstanceCache().release(ctx);
+
EntityEnterpriseContext ctx = (EntityEnterpriseContext)ctxList.get(i);
+
ctx.setTransaction(null);
+ ctx.setInvoked(false);
+
container.getInstanceCache().release(ctx);
} catch (Exception e)
{
- Logger.debug(e);
+ Logger.debug(e);
}
- break;
+ break;
// Keep instance, but invalidate state
case B:
try
{
- EntityEnterpriseContext ctx
= (EntityEnterpriseContext)ctxList.get(i);
- ctx.setTransaction(null);
- ctx.setInvoked(false);
+
EntityEnterpriseContext ctx = (EntityEnterpriseContext)ctxList.get(i);
+
ctx.setTransaction(null);
+ ctx.setInvoked(false);
ctx.setSynchronized(false); // Invalidate state
-
container.getInstanceCache().release(ctx);
+
container.getInstanceCache().release(ctx);
} catch (Exception e)
{
- Logger.debug(e);
+ Logger.debug(e);
}
- break;
-
- // Passivate instance
- case C:
- try
- {
- EntityEnterpriseContext ctx =
(EntityEnterpriseContext)ctxList.get(i);
- ctx.setTransaction(null);
- ctx.setInvoked(false);
-
-
container.getInstanceCache().get(ctx.getId()); // Lock in cache
-
((EntityContainer)getContainer()).getPersistenceManager().passivateEntity(ctx); //
Passivate instance
-
container.getInstanceCache().remove(ctx.getId()); // Remove from cache
-
-
container.getInstancePool().free(ctx); // Add to instance pool
+ break;
+
+ // Passivate instance
+ case C:
+ try
+ {
+
EntityEnterpriseContext ctx = (EntityEnterpriseContext)ctxList.get(i);
+
ctx.setTransaction(null);
+ ctx.setInvoked(false);
+
+
container.getInstanceCache().get(ctx.getId()); // Lock in cache
+
((EntityContainer)getContainer()).getPersistenceManager().passivateEntity(ctx); //
Passivate instance
+
container.getInstanceCache().remove(ctx.getId()); // Remove from cache
+
+
container.getInstancePool().free(ctx); // Add to instance pool
- } catch (Exception e)
- {
- Logger.debug(e);
- }
+ } catch (Exception e)
+ {
+ Logger.debug(e);
+ }
break;
}
- }
- }
-
- // Remove from tx/synch mapping
- synchs.remove(this);
-
- // Notify all who are waiting for this tx to end
- synchronized (tx)
- {
- tx.notifyAll();
- }
- }
- }
+ }
+ }
+
+ // Remove from tx/synch mapping
+ synchs.remove(this);
+
+ // Notify all who are waiting for this tx to end
+ synchronized (tx)
+ {
+ tx.notifyAll();
+ }
+ }
+ }
}