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;
}
}