dain        2005/02/25 18:06:09

  Modified:    modules/core/src/java/org/openejb/entity
                        EntityInstanceContext.java
                        EntityInstanceFactory.java
                        EntityInstanceInterceptor.java
  Log:

  Added support for in-tx cacheing back in
  This unturned a load of places that were not handling transaction contexts 
properly and bugs in the context itself
  Changed instance contexts so they track entrancy and can be killed as 
required by the spec
  Made all instance context fields final
  
  Revision  Changes    Path
  1.13      +92 -39    
openejb/modules/core/src/java/org/openejb/entity/EntityInstanceContext.java
  
  Index: EntityInstanceContext.java
  ===================================================================
  RCS file: 
/home/projects/openejb/scm/openejb/modules/core/src/java/org/openejb/entity/EntityInstanceContext.java,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- EntityInstanceContext.java        16 Feb 2005 06:12:38 -0000      1.12
  +++ EntityInstanceContext.java        25 Feb 2005 23:06:09 -0000      1.13
  @@ -48,7 +48,6 @@
   package org.openejb.entity;
   
   import java.util.Set;
  -
   import javax.ejb.EnterpriseBean;
   import javax.ejb.EntityContext;
   
  @@ -58,29 +57,28 @@
   import org.openejb.AbstractInstanceContext;
   import org.openejb.EJBInvocation;
   import org.openejb.EJBOperation;
  +import org.openejb.cache.InstancePool;
   import org.openejb.dispatch.SystemMethodIndices;
   import org.openejb.proxy.EJBProxyFactory;
   import org.openejb.timer.BasicTimerService;
   
   /**
  - *
  - *
    * @version $Revision$ $Date$
    */
   public abstract class EntityInstanceContext extends AbstractInstanceContext {
  -    private final Object containerId;
       private final EntityContextImpl entityContext;
  -    private Object id;
  +    private final EJBInvocation setContextInvocation;
  +    private final EJBInvocation unsetContextInvocation;
       private final EJBInvocation ejbActivateInvocation;
       private final EJBInvocation ejbPassivateInvocation;
       private final EJBInvocation loadInvocation;
       private final EJBInvocation storeInvocation;
  -    private boolean stateValid;
  -    private int callDepth;
  +    private Object id;
  +    private boolean loaded = false;
  +    private InstancePool pool;
   
       public EntityInstanceContext(Object containerId, EJBProxyFactory 
proxyFactory, EnterpriseBean instance, Interceptor lifecycleInterceptorChain, 
SystemMethodIndices systemMethodIndices, Set unshareableResources, Set 
applicationManagedSecurityResources, TransactionContextManager 
transactionContextManager, BasicTimerService timerService) {
  -        super(lifecycleInterceptorChain, unshareableResources, 
applicationManagedSecurityResources, instance, proxyFactory, timerService);
  -        this.containerId = containerId;
  +        super(containerId, instance, lifecycleInterceptorChain, 
proxyFactory, timerService, unshareableResources, 
applicationManagedSecurityResources);
           entityContext = new EntityContextImpl(this, 
transactionContextManager);
           ejbActivateInvocation = 
systemMethodIndices.getEjbActivateInvocation(this);
           ejbPassivateInvocation = 
systemMethodIndices.getEjbPassivateInvocation(this);
  @@ -90,10 +88,6 @@
           unsetContextInvocation = 
systemMethodIndices.getUnsetContextInvocation(this);
       }
   
  -    public Object getContainerId() {
  -        return containerId;
  -    }
  -
       public Object getId() {
           return id;
       }
  @@ -102,6 +96,14 @@
           this.id = id;
       }
   
  +    public InstancePool getPool() {
  +        return pool;
  +    }
  +
  +    public void setPool(InstancePool pool) {
  +        this.pool = pool;
  +    }
  +
       public void setOperation(EJBOperation operation) {
           entityContext.setState(operation);
       }
  @@ -119,53 +121,104 @@
           storeInvocation.setTransactionContext(transactionContext);
       }
   
  -    public boolean isStateValid() {
  -        return stateValid;
  +    public boolean isLoaded() {
  +        return loaded;
       }
   
  -    public void setStateValid(boolean stateValid) {
  -        this.stateValid = stateValid;
  +    public void setLoaded(boolean loaded) {
  +        this.loaded = loaded;
       }
   
  +    public void die() {
  +        if (pool != null) {
  +            pool.remove(this);
  +            pool = null;
  +        }
  +        loaded = false;
  +        setTransactionContext(null);
  +        super.die();
  +    }
   
  -    public boolean isInCall() {
  -        return callDepth > 0;
  +    public void associate() throws Throwable {
  +        super.associate();
  +        if (id != null && !loaded) {
  +            ejbActivate();
  +            ejbLoad();
  +            loaded = true;
  +        }
       }
   
  -    public void enter() {
  -        callDepth++;
  +    public void unassociate() throws Throwable {
  +        super.unassociate();
  +        try {
  +            if (!isDead()) {
  +                if (id != null) {
  +                    ejbPassivate();
  +                }
  +                if (pool != null) {
  +                    pool.release(this);
  +                }
  +            }
  +        } catch (Throwable t) {
  +            // problem passivating instance - discard it and throw the 
problem (will cause rollback)
  +            if (pool != null) {
  +                pool.remove(this);
  +            }
  +            throw t;
  +        } finally {
  +            loaded = false;
  +            setTransactionContext(null);
  +        }
       }
   
  -    public void exit() {
  -        assert isInCall();
  -        callDepth--;
  +    public void beforeCommit() throws Throwable {
  +        super.beforeCommit();
  +        flush();
       }
   
  -    public void ejbActivate() throws Throwable {
  -        systemChain.invoke(ejbActivateInvocation);
  +    public void flush() throws Throwable {
  +        super.flush();
  +        if (id != null) {
  +            if (!loaded) {
  +                throw new IllegalStateException("Trying to invoke ejbStore 
on an unloaded instance");
  +            }
  +            ejbStore();
  +        }
       }
   
  -    public void ejbPassivate() throws Throwable {
  -        systemChain.invoke(ejbPassivateInvocation);
  +    public void setContext() throws Throwable {
  +        if (isDead()) {
  +            throw new IllegalStateException("Context is dead: container=" + 
getContainerId() + ", id=" + getId());
  +        }
  +        systemChain.invoke(setContextInvocation);
       }
   
  -    public void associate() throws Throwable {
  -        if (id != null && !stateValid) {
  -            systemChain.invoke(loadInvocation);
  -            stateValid = true;
  +    public void unsetContext() throws Throwable {
  +        if (isDead()) {
  +            throw new IllegalStateException("Context is dead: container=" + 
getContainerId() + ", id=" + getId());
           }
  +        systemChain.invoke(unsetContextInvocation);
       }
   
  -    public void beforeCommit() {
  +    protected void ejbActivate() throws Throwable {
  +        if (isDead()) {
  +            throw new IllegalStateException("Context is dead: container=" + 
getContainerId() + ", id=" + getId());
  +        }
  +        systemChain.invoke(ejbActivateInvocation);
       }
   
  -    public void flush() throws Throwable {
  -        if (id != null) {
  -            assert (stateValid) : "Trying to invoke ejbStore for invalid 
instance";
  -            systemChain.invoke(storeInvocation);
  +    protected void ejbPassivate() throws Throwable {
  +        if (isDead()) {
  +            throw new IllegalStateException("Context is dead: container=" + 
getContainerId() + ", id=" + getId());
           }
  +        systemChain.invoke(ejbPassivateInvocation);
  +    }
  +
  +    protected void ejbLoad() throws Throwable {
  +        systemChain.invoke(loadInvocation);
       }
   
  -    public void afterCommit(boolean status) {
  +    public void ejbStore() throws Throwable {
  +        systemChain.invoke(storeInvocation);
       }
   }
  
  
  
  1.6       +5 -3      
openejb/modules/core/src/java/org/openejb/entity/EntityInstanceFactory.java
  
  Index: EntityInstanceFactory.java
  ===================================================================
  RCS file: 
/home/projects/openejb/scm/openejb/modules/core/src/java/org/openejb/entity/EntityInstanceFactory.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- EntityInstanceFactory.java        26 Jan 2005 23:28:00 -0000      1.5
  +++ EntityInstanceFactory.java        25 Feb 2005 23:06:09 -0000      1.6
  @@ -87,11 +87,13 @@
               try {
                   ctx.setContext();
               } catch (Throwable t) {
  -                //TODO check this error handling
  +                ctx.die();
                   if (t instanceof Exception) {
                       throw (Exception) t;
  -                } else {
  +                } else if (t instanceof Error) {
                       throw (Error) t;
  +                } else {
  +                    throw new Error(t);
                   }
               }
   
  
  
  
  1.13      +44 -64    
openejb/modules/core/src/java/org/openejb/entity/EntityInstanceInterceptor.java
  
  Index: EntityInstanceInterceptor.java
  ===================================================================
  RCS file: 
/home/projects/openejb/scm/openejb/modules/core/src/java/org/openejb/entity/EntityInstanceInterceptor.java,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- EntityInstanceInterceptor.java    16 Feb 2005 06:12:38 -0000      1.12
  +++ EntityInstanceInterceptor.java    25 Feb 2005 23:06:09 -0000      1.13
  @@ -82,87 +82,67 @@
   
       public InvocationResult invoke(final Invocation invocation) throws 
Throwable {
           EJBInvocation ejbInvocation = (EJBInvocation) invocation;
  -        TransactionContext transactionContext = 
ejbInvocation.getTransactionContext();
  -        Object id = ejbInvocation.getId();
   
  -        boolean newContext = false;
  -        EntityInstanceContext context = null;
  -        // if we have an id then check if there is already a context 
associated with the transaction
  -        if ( id != null) {
  -            context = (EntityInstanceContext) 
transactionContext.getContext(containerId, id);
  -        }
  +        // initialize the context and set it into the invocation
  +        EntityInstanceContext ctx = getInstanceContext(ejbInvocation);
  +        ejbInvocation.setEJBInstanceContext(ctx);
   
  -        // if we didn't find an existing context, create a new one.
  -        if (context == null) {
  -            context = (EntityInstanceContext) pool.acquire();
  -            newContext = true;
  -
  -            context.setTransactionContext(transactionContext);
  -            if (id != null) {
  -                // always activate on the way in....
  -                context.setId(id);
  -                try {
  -                    context.ejbActivate();
  -                } catch (Throwable t) {
  -                    // problem activating instance - discard it and throw 
the problem (will cause rollback)
  -                    pool.remove(context);
  -                    throw t;
  -                }
  -
  -                // associate this instance with the TransactionContext
  -                try {
  -                    transactionContext.associate(context);
  -                } catch (NoSuchEntityException e) {
  -                    if (ejbInvocation.getType().isLocal()) {
  -                        throw new NoSuchObjectLocalException().initCause(e);
  -                    } else {
  -                        throw new NoSuchObjectException(e.getMessage());
  -                    }
  -                }
  +        // check reentrancy
  +        if (!reentrant && ctx.isInCall()) {
  +            if (ejbInvocation.getType().isLocal()) {
  +                throw new NotReentrantLocalException("" + containerId);
  +            } else {
  +                throw new NotReentrantException("" + containerId);
               }
           }
   
  -        ejbInvocation.setEJBInstanceContext(context);
  -        if (!reentrant && context.isInCall()) {
  +        TransactionContext transactionContext = 
ejbInvocation.getTransactionContext();
  +        InstanceContext oldContext = null;
  +        try {
  +            oldContext = transactionContext.beginInvocation(ctx);
  +        } catch (NoSuchEntityException e) {
               if (ejbInvocation.getType().isLocal()) {
  -                throw new NotReentrantLocalException("" + containerId);
  +                throw new NoSuchObjectLocalException().initCause(e);
               } else {
  -                throw new NotReentrantException("" + containerId);
  +                throw new NoSuchObjectException(e.getMessage());
               }
           }
  -        InstanceContext oldContext = 
transactionContext.beginInvocation(context);
  -        context.enter();
  -        boolean threwException = false;
           try {
               InvocationResult result = next.invoke(invocation);
               return result;
  -        } catch (Throwable t) {
  -            threwException = true;
  +        } catch(Throwable t) {
  +            // we must kill the instance when a system exception is thrown
  +            ctx.die();
  +            transactionContext.unassociate(ctx);
               throw t;
           } finally {
  -            context.exit();
  -            transactionContext.endInvocation(oldContext);
  +            ejbInvocation.getTransactionContext().endInvocation(oldContext);
               ejbInvocation.setEJBInstanceContext(null);
  +        }
  +    }
   
  -            if (id == null) id = context.getId();
  +    private EntityInstanceContext getInstanceContext(EJBInvocation 
ejbInvocation) throws Throwable {
  +        TransactionContext transactionContext = 
ejbInvocation.getTransactionContext();
  +        Object id = ejbInvocation.getId();
  +        EntityInstanceContext ctx = null;
   
  -            if (id != null) {
  -                // passivate on the way out if this is a new context
  -                if (newContext) {
  -                    try {
  -                        context.flush();
  -                        context.ejbPassivate();
  -                    } catch (Throwable t) {
  -                        // problem passivating instance - discard it and 
throw the problem (will cause rollback)
  -                        pool.remove(context);
  -                        // throw this exception only if we are not already 
throwing a business exception
  -                        if (!threwException) throw t;
  -                    } finally {
  -                        context.setTransactionContext(null);
  -                        
transactionContext.unassociate(context.getContainerId(), id);
  -                    }
  -                }
  +        // if we have an id then check if there is already a context 
associated with the transaction
  +        if ( id != null) {
  +            ctx = (EntityInstanceContext) 
transactionContext.getContext(containerId, id);
  +            // if we have a dead context, the cached context was discarded, 
so we need clean it up and get a new one
  +            if (ctx != null && ctx.isDead()) {
  +                transactionContext.unassociate(ctx);
  +                ctx = null;
               }
           }
  +
  +        // if we didn't find an existing context, create a new one.
  +        if (ctx == null) {
  +            ctx = (EntityInstanceContext) pool.acquire();
  +            ctx.setId(id);
  +            ctx.setPool(pool);
  +            ctx.setTransactionContext(transactionContext);
  +        }
  +        return ctx;
       }
   }
  
  
  

Reply via email to