User: fleury
Date: 00/09/26 11:58:33
Modified: src/main/org/jboss/ejb/plugins
StatefulSessionFilePersistenceManager.java
StatefulSessionInstanceInterceptor.java
StatelessSessionInstanceInterceptor.java
Added: src/main/org/jboss/ejb/plugins TxInterceptorCMT.java
Log:
new adds for the proper management of Tx and cache
Revision Changes Path
1.7 +240 -240
jboss/src/main/org/jboss/ejb/plugins/StatefulSessionFilePersistenceManager.java
Index: StatefulSessionFilePersistenceManager.java
===================================================================
RCS file:
/products/cvs/ejboss/jboss/src/main/org/jboss/ejb/plugins/StatefulSessionFilePersistenceManager.java,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- StatefulSessionFilePersistenceManager.java 2000/08/18 03:20:57 1.6
+++ StatefulSessionFilePersistenceManager.java 2000/09/26 18:58:32 1.7
@@ -1,240 +1,240 @@
-/*
- * jBoss, the OpenSource EJB server
- *
- * Distributable under GPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.ejb.plugins;
-
-import java.beans.Beans;
-import java.beans.beancontext.BeanContextServicesSupport;
-import java.io.File;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.FileOutputStream;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.lang.reflect.InvocationTargetException;
-import java.rmi.RemoteException;
-import java.rmi.NoSuchObjectException;
-import java.rmi.ServerException;
-import java.util.Collection;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.sql.SQLException;
-import java.sql.ResultSet;
-import java.sql.ResultSetMetaData;
-import java.sql.DriverManager;
-import java.sql.Statement;
-import java.sql.PreparedStatement;
-import java.sql.Connection;
-
-import javax.ejb.EJBObject;
-import javax.ejb.Handle;
-import javax.ejb.SessionBean;
-import javax.ejb.CreateException;
-import javax.ejb.DuplicateKeyException;
-import javax.ejb.FinderException;
-import javax.ejb.RemoveException;
-import javax.naming.Context;
-import javax.naming.InitialContext;
-
-import org.jboss.ejb.Container;
-import org.jboss.ejb.StatefulSessionContainer;
-import org.jboss.ejb.StatefulSessionPersistenceManager;
-import org.jboss.ejb.StatefulSessionEnterpriseContext;
-import org.jboss.logging.Logger;
-
-
-/**
- * StatefulSessionFilePersistenceManager
- *
- * This class is one of the passivating plugins for jBoss.
- * It is fairly simple and can work from the file system from wich jBoss is
operating
- *
- * @see <related>
- * @author Rickard �berg ([EMAIL PROTECTED])
- * @author <a href="[EMAIL PROTECTED]">Marc Fleury</a>
- * @version $Revision: 1.6 $
- */
-public class StatefulSessionFilePersistenceManager
- implements StatefulSessionPersistenceManager
-{
- // Constants -----------------------------------------------------
-
- // Attributes ----------------------------------------------------
- StatefulSessionContainer con;
-
- Method ejbActivate;
- Method ejbPassivate;
- Method ejbRemove;
-
- File dir;
-
- // Static --------------------------------------------------------
- private static long id = System.currentTimeMillis();
-
- // Constructors --------------------------------------------------
-
- // Public --------------------------------------------------------
- public void setContainer(Container c)
- {
- con = (StatefulSessionContainer)c;
- }
-
- public void init()
- throws Exception {
-
- // Find methods
- ejbActivate = SessionBean.class.getMethod("ejbActivate", new Class[0]);
-
- ejbPassivate = SessionBean.class.getMethod("ejbPassivate", new Class[0]);
-
- ejbRemove = SessionBean.class.getMethod("ejbRemove", new Class[0]);
-
- // Initialize the dataStore
- String ejbName = con.getBeanMetaData().getEjbName();
-
- File database = new File("database");
-
- dir = new File(database, ejbName);
-
- dir.mkdirs();
-
- Logger.log("Storing sessions for "+ejbName+" in:"+dir);
-
- // Clear dir of old files
- File[] sessions = dir.listFiles();
- for (int i = 0; i < sessions.length; i++)
- {
- sessions[i].delete();
- }
- Logger.log(sessions.length + " old sessions removed");
- }
-
- public void start()
- throws Exception
- {
- }
-
- public void stop()
- {
- }
-
- public void destroy()
- {
- }
-
- public void createSession(Method m, Object[] args,
StatefulSessionEnterpriseContext ctx)
- throws RemoteException, CreateException
- {
- // Get methods
- try
- {
- Method createMethod = con.getBeanClass().getMethod("ejbCreate",
m.getParameterTypes());
-
- // Call ejbCreate
- createMethod.invoke(ctx.getInstance(), args);
-
- // Set id
- ctx.setId(nextId());
-
- // Lock instance in cache
- ((StatefulSessionContainer)con).getInstanceCache().insert(ctx);
-
- // Create EJBObject
-
ctx.setEJBObject(con.getContainerInvoker().getStatefulSessionEJBObject(ctx.getId()));
-
- } catch (InvocationTargetException e)
- {
- throw new CreateException("Create failed:"+e);
- } catch (NoSuchMethodException e)
- {
- throw new CreateException("Create methods not found:"+e);
- } catch (IllegalAccessException e)
- {
- throw new CreateException("Could not create entity:"+e);
- }
- }
-
- public void activateSession(StatefulSessionEnterpriseContext ctx)
- throws RemoteException
- {
- try
- {
-
- ObjectInputStream in;
-
-
- // Load state
- in = new SessionObjectInputStream(ctx, new FileInputStream(new
File(dir, ctx.getId()+".ser")));
- Field[] fields = ctx.getInstance().getClass().getFields();
-
- for (int i = 0; i < fields.length; i++)
- if (!Modifier.isTransient(fields[i].getModifiers()))
- fields[i].set(ctx.getInstance(), in.readObject());
-
- // Call bean
- ejbActivate.invoke(ctx.getInstance(), new Object[0]);
- } catch (Exception e)
- {
- throw new ServerException("Activation failed", e);
- }
- }
-
- public void passivateSession(StatefulSessionEnterpriseContext ctx)
- throws RemoteException
- {
- try
- {
- // Call bean
- ejbPassivate.invoke(ctx.getInstance(), new Object[0]);
-
- // Store state
- ObjectOutputStream out = new SessionObjectOutputStream(new
FileOutputStream(new File(dir, ctx.getId()+".ser")));
-
- Field[] fields = ctx.getInstance().getClass().getFields();
-
- for (int i = 0; i < fields.length; i++)
- if (!Modifier.isTransient(fields[i].getModifiers()))
- out.writeObject(fields[i].get(ctx.getInstance()));
-
- out.close();
- } catch (Exception e)
- {
- throw new ServerException("Passivation failed", e);
- }
- }
-
- public void removeSession(StatefulSessionEnterpriseContext ctx)
- throws RemoteException, RemoveException
- {
- // Call bean
- try
- {
- ejbRemove.invoke(ctx.getInstance(), new Object[0]);
- } catch (Exception e)
- {
- throw new ServerException("Remove failed", e);
- }
- }
-
- // Z implementation ----------------------------------------------
-
- // Package protected ---------------------------------------------
-
- // Protected -----------------------------------------------------
- protected Long nextId()
- {
- return new Long(id++);
- }
-
- // Private -------------------------------------------------------
-
- // Inner classes -------------------------------------------------
-}
+/*
+ * jBoss, the OpenSource EJB server
+ *
+ * Distributable under GPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.ejb.plugins;
+
+import java.beans.Beans;
+import java.beans.beancontext.BeanContextServicesSupport;
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.FileOutputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.InvocationTargetException;
+import java.rmi.RemoteException;
+import java.rmi.NoSuchObjectException;
+import java.rmi.ServerException;
+import java.util.Collection;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.sql.SQLException;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.DriverManager;
+import java.sql.Statement;
+import java.sql.PreparedStatement;
+import java.sql.Connection;
+
+import javax.ejb.EJBObject;
+import javax.ejb.Handle;
+import javax.ejb.SessionBean;
+import javax.ejb.CreateException;
+import javax.ejb.DuplicateKeyException;
+import javax.ejb.FinderException;
+import javax.ejb.RemoveException;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+
+import org.jboss.ejb.Container;
+import org.jboss.ejb.StatefulSessionContainer;
+import org.jboss.ejb.StatefulSessionPersistenceManager;
+import org.jboss.ejb.StatefulSessionEnterpriseContext;
+import org.jboss.logging.Logger;
+
+
+/**
+ * StatefulSessionFilePersistenceManager
+ *
+ * This class is one of the passivating plugins for jBoss.
+ * It is fairly simple and can work from the file system from wich jBoss is
operating
+ *
+ * @see <related>
+ * @author Rickard �berg ([EMAIL PROTECTED])
+ * @author <a href="[EMAIL PROTECTED]">Marc Fleury</a>
+ * @version $Revision: 1.7 $
+ */
+public class StatefulSessionFilePersistenceManager
+ implements StatefulSessionPersistenceManager
+{
+ // Constants -----------------------------------------------------
+
+ // Attributes ----------------------------------------------------
+ StatefulSessionContainer con;
+
+ Method ejbActivate;
+ Method ejbPassivate;
+ Method ejbRemove;
+
+ File dir;
+
+ // Static --------------------------------------------------------
+ private static long id = System.currentTimeMillis();
+
+ // Constructors --------------------------------------------------
+
+ // Public --------------------------------------------------------
+ public void setContainer(Container c)
+ {
+ con = (StatefulSessionContainer)c;
+ }
+
+ public void init()
+ throws Exception {
+
+ // Find methods
+ ejbActivate = SessionBean.class.getMethod("ejbActivate", new Class[0]);
+
+ ejbPassivate = SessionBean.class.getMethod("ejbPassivate", new Class[0]);
+
+ ejbRemove = SessionBean.class.getMethod("ejbRemove", new Class[0]);
+
+ // Initialize the dataStore
+ String ejbName = con.getBeanMetaData().getEjbName();
+
+ File database = new File("database");
+
+ dir = new File(database, ejbName);
+
+ dir.mkdirs();
+
+ Logger.log("Storing sessions for "+ejbName+" in:"+dir);
+
+ // Clear dir of old files
+ File[] sessions = dir.listFiles();
+ for (int i = 0; i < sessions.length; i++)
+ {
+ sessions[i].delete();
+ }
+ Logger.log(sessions.length + " old sessions removed");
+ }
+
+ public void start()
+ throws Exception
+ {
+ }
+
+ public void stop()
+ {
+ }
+
+ public void destroy()
+ {
+ }
+
+ public void createSession(Method m, Object[] args,
StatefulSessionEnterpriseContext ctx)
+ throws RemoteException, CreateException
+ {
+ // Get methods
+ try
+ {
+ Method createMethod = con.getBeanClass().getMethod("ejbCreate",
m.getParameterTypes());
+
+ // Call ejbCreate
+ createMethod.invoke(ctx.getInstance(), args);
+
+ // Set id
+ ctx.setId(nextId());
+
+ // Insert in cache
+ ((StatefulSessionContainer)con).getInstanceCache().insert(ctx);
+
+ // Create EJBObject
+
ctx.setEJBObject(con.getContainerInvoker().getStatefulSessionEJBObject(ctx.getId()));
+
+ } catch (InvocationTargetException e)
+ {
+ throw new CreateException("Create failed:"+e);
+ } catch (NoSuchMethodException e)
+ {
+ throw new CreateException("Create methods not found:"+e);
+ } catch (IllegalAccessException e)
+ {
+ throw new CreateException("Could not create entity:"+e);
+ }
+ }
+
+ public void activateSession(StatefulSessionEnterpriseContext ctx)
+ throws RemoteException
+ {
+ try
+ {
+
+ ObjectInputStream in;
+
+
+ // Load state
+ in = new SessionObjectInputStream(ctx, new FileInputStream(new
File(dir, ctx.getId()+".ser")));
+ Field[] fields = ctx.getInstance().getClass().getFields();
+
+ for (int i = 0; i < fields.length; i++)
+ if (!Modifier.isTransient(fields[i].getModifiers()))
+ fields[i].set(ctx.getInstance(), in.readObject());
+
+ // Call bean
+ ejbActivate.invoke(ctx.getInstance(), new Object[0]);
+ } catch (Exception e)
+ {
+ throw new ServerException("Activation failed", e);
+ }
+ }
+
+ public void passivateSession(StatefulSessionEnterpriseContext ctx)
+ throws RemoteException
+ {
+ try
+ {
+ // Call bean
+ ejbPassivate.invoke(ctx.getInstance(), new Object[0]);
+
+ // Store state
+ ObjectOutputStream out = new SessionObjectOutputStream(new
FileOutputStream(new File(dir, ctx.getId()+".ser")));
+
+ Field[] fields = ctx.getInstance().getClass().getFields();
+
+ for (int i = 0; i < fields.length; i++)
+ if (!Modifier.isTransient(fields[i].getModifiers()))
+ out.writeObject(fields[i].get(ctx.getInstance()));
+
+ out.close();
+ } catch (Exception e)
+ {
+ throw new ServerException("Passivation failed", e);
+ }
+ }
+
+ public void removeSession(StatefulSessionEnterpriseContext ctx)
+ throws RemoteException, RemoveException
+ {
+ // Call bean
+ try
+ {
+ ejbRemove.invoke(ctx.getInstance(), new Object[0]);
+ } catch (Exception e)
+ {
+ throw new ServerException("Remove failed", e);
+ }
+ }
+
+ // Z implementation ----------------------------------------------
+
+ // Package protected ---------------------------------------------
+
+ // Protected -----------------------------------------------------
+ protected Long nextId()
+ {
+ return new Long(id++);
+ }
+
+ // Private -------------------------------------------------------
+
+ // Inner classes -------------------------------------------------
+}
1.4 +313 -131
jboss/src/main/org/jboss/ejb/plugins/StatefulSessionInstanceInterceptor.java
Index: StatefulSessionInstanceInterceptor.java
===================================================================
RCS file:
/products/cvs/ejboss/jboss/src/main/org/jboss/ejb/plugins/StatefulSessionInstanceInterceptor.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- StatefulSessionInstanceInterceptor.java 2000/06/16 13:10:23 1.3
+++ StatefulSessionInstanceInterceptor.java 2000/09/26 18:58:32 1.4
@@ -1,131 +1,313 @@
-/*
-* 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;
-import java.rmi.RemoteException;
-
-import org.jboss.ejb.Container;
-import org.jboss.ejb.InstanceCache;
-import org.jboss.ejb.InstancePool;
-import org.jboss.ejb.StatefulSessionContainer;
-import org.jboss.ejb.EnterpriseContext;
-import org.jboss.ejb.MethodInvocation;
-
-
-/**
-* This container acquires the given instance.
-*
-* @see <related>
-* @author Rickard �berg ([EMAIL PROTECTED])
-* @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a>
-* @version $Revision: 1.3 $
-*/
-public class StatefulSessionInstanceInterceptor
- extends AbstractInterceptor
-{
- // Constants ----------------------------------------------------
-
- // Attributes ---------------------------------------------------
- protected StatefulSessionContainer container;
-
- // Static -------------------------------------------------------
-
- // Constructors -------------------------------------------------
-
- // Public -------------------------------------------------------
- public void setContainer(Container container)
- {
- this.container = (StatefulSessionContainer)container;
- }
-
- public Container getContainer()
- {
- return container;
- }
- // Interceptor implementation -----------------------------------
- public Object invokeHome(MethodInvocation mi)
- throws Exception
- {
- // Get context
- mi.setEnterpriseContext(container.getInstancePool().get());
-
- try
- {
- // Invoke through interceptors
- return getNext().invokeHome(mi);
- } finally
- {
- // Still free? Not free if create() was called successfully
- if (mi.getEnterpriseContext().getId() == null)
- {
- // Create did not associate an ID with the ctx
- // There is nothing to do just let the garbage
collector do its work
-
- } else
- {
- // Create was called succesfully we go to the cache
-
container.getInstanceCache().release(mi.getEnterpriseContext());
- }
- }
- }
-
- public Object invoke(MethodInvocation mi)
- throws Exception
- {
- // Get context
- EnterpriseContext ctx = container.getInstanceCache().get(mi.getId());
- mi.setEnterpriseContext(ctx);
-
- try
- {
- // Invoke through interceptors
- return getNext().invoke(mi);
- } catch (RemoteException e)
- {
- // Discard instance
- container.getInstanceCache().remove(mi.getId());
- ctx = null;
-
- throw e;
- } catch (RuntimeException e)
- {
- // Discard instance
- container.getInstanceCache().remove(mi.getId());
- ctx = null;
-
- throw e;
- } catch (Error e)
- {
- // Discard instance
- container.getInstanceCache().remove(mi.getId());
- ctx = null;
-
- throw e;
- } finally
- {
- if (ctx != null)
- {
- // Still a valid instance
-
- if (ctx.getId() == null)
- {
- // Remove from cache
-
container.getInstanceCache().remove(mi.getId());
-
- // It has been removed -> send to free pool
- container.getInstancePool().free(ctx);
- }
- {
- // Return context
- container.getInstanceCache().release(ctx);
- }
- }
- }
- }
-}
-
+/*
+* 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;
+import java.rmi.RemoteException;
+
+import org.jboss.ejb.Container;
+import org.jboss.ejb.InstanceCache;
+import org.jboss.ejb.InstancePool;
+import org.jboss.ejb.StatefulSessionContainer;
+import org.jboss.ejb.StatefulSessionEnterpriseContext;
+import org.jboss.ejb.EnterpriseContext;
+import org.jboss.ejb.MethodInvocation;
+import org.jboss.logging.Logger;
+import org.jboss.metadata.SessionMetaData;
+import javax.transaction.Transaction;
+import javax.transaction.RollbackException;
+import javax.transaction.Status;
+import javax.transaction.Synchronization;
+
+import javax.ejb.EJBException;
+
+
+/**
+* This container acquires the given instance.
+*
+* @see <related>
+* @author Rickard �berg ([EMAIL PROTECTED])
+* @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a>
+* @version $Revision: 1.4 $
+*/
+public class StatefulSessionInstanceInterceptor
+extends AbstractInterceptor
+{
+ // Constants ----------------------------------------------------
+
+ // Attributes ---------------------------------------------------
+ protected StatefulSessionContainer container;
+
+ // Static -------------------------------------------------------
+
+ // Constructors -------------------------------------------------
+
+ // Public -------------------------------------------------------
+
+ public void setContainer(Container container)
+ {
+ this.container = (StatefulSessionContainer)container;
+ }
+
+ public Container getContainer()
+ {
+ return container;
+ }
+ // Interceptor implementation -----------------------------------
+ public Object invokeHome(MethodInvocation mi)
+ throws Exception
+ {
+ // Get context
+
+ // get a new context from the pool (this is a home method call)
+ EnterpriseContext ctx = container.getInstancePool().get();
+
+
+ // set the context on the methodInvocation
+ mi.setEnterpriseContext(ctx);
+
+ // It is a new context for sure so we can lock it
+ ctx.lock();
+
+
+ try
+ {
+ // Invoke through interceptors
+ return getNext().invokeHome(mi);
+ } finally
+ {
+ // Still free? Not free if create() was called successfully
+ if (ctx.getId() == null)
+ {
+
+
container.getInstancePool().free(mi.getEnterpriseContext());
+ } else
+ {
+ // DEBUG Logger.log("Session was created; not
returned to pool");
+
+ // Create was called succesfully we go to the cache
+ synchronized (ctx) {
+
+ // Release the lock
+ ctx.unlock();
+
+ //Let the waiters know
+ //ctx.notifyAll();
+ }
+ }
+ }
+ }
+
+
+ private void register(EnterpriseContext 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) {
+
+ return;
+ }
+
+ // We want to be notified when the transaction commits
+ tx.registerSynchronization(synch);
+
+ } catch (RollbackException e) {
+
+ } catch (Exception e) {
+
+ throw new EJBException(e);
+
+ }
+ }
+
+ public Object invoke(MethodInvocation mi)
+ throws Exception
+ {
+ // Get context
+ EnterpriseContext ctx = container.getInstanceCache().get(mi.getId());
+
+ // Associate it with the method invocation
+ mi.setEnterpriseContext(ctx);
+
+
+ // We synchronize the locking logic (so we can be reentrant)
+ synchronized (ctx)
+ {
+
+ // BMT beans will lock and replace tx no matter what, CMT do
work on transaction
+ if
(!((SessionMetaData)container.getBeanMetaData()).isBeanManagedTx()) {
+
+ // Do we have a running transaction with the context
+ if (ctx.getTransaction() != null &&
+ // And are we trying to enter with another
transaction
+
!ctx.getTransaction().equals(mi.getTransaction()))
+ {
+ // Calls must be in the same transaction
+ throw new RemoteException("Application Error:
tried to enter Stateful bean with different transaction context");
+ }
+
+ //If the instance will participate in a new
transaction we register a sync for it
+ if (ctx.getTransaction() == null &&
mi.getTransaction() != null) {
+
+ register(ctx, mi.getTransaction());
+
+ }
+ }
+
+ if (!ctx.isLocked()){
+
+ //take it!
+ ctx.lock();
+ }
+
+ else
+ {
+
+ // Calls must be in the same transaction
+ throw new RemoteException("Application Error: no
concurrent calls on stateful beans");
+ }
+ }
+
+ try
+ {
+ // Invoke through interceptors
+ return getNext().invoke(mi);
+ } catch (RemoteException e)
+ {
+ // Discard instance
+ container.getInstanceCache().remove(mi.getId());
+ ctx = null;
+
+ throw e;
+ } catch (RuntimeException e)
+ {
+ // Discard instance
+ container.getInstanceCache().remove(mi.getId());
+ ctx = null;
+
+ throw e;
+ } catch (Error e)
+ {
+ // Discard instance
+ container.getInstanceCache().remove(mi.getId());
+ ctx = null;
+
+ throw e;
+ } finally
+ {
+ if (ctx != null)
+ {
+ // Still a valid instance
+
+ // release it
+ ctx.unlock();
+
+ // if removed, remove from cache
+ if (ctx.getId() == null)
+ {
+ // Remove from cache
+
container.getInstanceCache().remove(mi.getId());
+ }
+ }
+ }
+ }
+
+ // Inner classes -------------------------------------------------
+
+ private class InstanceSynchronization
+ implements Synchronization
+ {
+ /**
+ * The transaction we follow.
+ */
+ private Transaction tx;
+
+ /**
+ * The context we manage.
+ */
+ private EnterpriseContext ctx;
+
+ // a utility boolean for session sync
+ boolean notifySession = false;
+
+ // Utility methods for the notifications
+ Method beforeCompletion, afterCompletion;
+
+
+ /**
+ * Create a new instance synchronization instance.
+ */
+ InstanceSynchronization(Transaction tx, EnterpriseContext ctx)
+ {
+ this.tx = tx;
+ this.ctx = ctx;
+
+ // Let's compute it now
+ notifySession = (ctx.getInstance() instanceof
javax.ejb.SessionSynchronization);
+
+ if (notifySession) {
+ try {
+
+ // Get the class we are working on
+ Class sync =
Class.forName("javax.ejb.SessionSynchronization");
+
+ // Lookup the methods on it
+ beforeCompletion =
sync.getMethod("beforeCompletion", new Class[0]);
+
+ afterCompletion =
sync.getMethod("afterCompletion", new Class[] {Integer.TYPE});
+ }
+ catch (Exception e) { Logger.exception(e);}
+ }
+ }
+
+ // Synchronization implementation -----------------------------
+
+ public void beforeCompletion()
+ {
+ Logger.log("beforeCompletion called");
+
+ // lock the context the transaction is being commited (no need
for sync)
+ ctx.lock();
+
+ if (notifySession) {
+ try {
+
+ beforeCompletion.invoke(ctx.getInstance(), new
Object[0]);
+ }
+ catch (Exception e) { Logger.exception(e);}
+ }
+ }
+
+ public void afterCompletion(int status)
+ {
+ Logger.log("afterCompletion called");
+
+ // finish the transaction association
+ ctx.setTransaction(null);
+
+ // unlock this context
+ ctx.unlock();
+
+ if (notifySession) {
+
+ try {
+
+ afterCompletion.invoke(ctx.getInstance(), new
Object[] {new Integer(status)});
+ }
+ catch (Exception e) {Logger.exception(e);}
+ }
+
+
+ }
+ }
+}
+
1.3 +6 -1
jboss/src/main/org/jboss/ejb/plugins/StatelessSessionInstanceInterceptor.java
Index: StatelessSessionInstanceInterceptor.java
===================================================================
RCS file:
/products/cvs/ejboss/jboss/src/main/org/jboss/ejb/plugins/StatelessSessionInstanceInterceptor.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- StatelessSessionInstanceInterceptor.java 2000/06/16 13:10:23 1.2
+++ StatelessSessionInstanceInterceptor.java 2000/09/26 18:58:32 1.3
@@ -39,7 +39,7 @@
*
* @see <related>
* @author Rickard �berg ([EMAIL PROTECTED])
- * @version $Revision: 1.2 $
+ * @version $Revision: 1.3 $
*/
public class StatelessSessionInstanceInterceptor
extends AbstractInterceptor
@@ -77,6 +77,9 @@
// Get context
mi.setEnterpriseContext(container.getInstancePool().get());
+ // There is no need for synchronization since the instance is always fresh
also there should
+ // never be a tx associated with the instance.
+
try
{
// Invoke through interceptors
@@ -86,6 +89,8 @@
// Return context
container.getInstancePool().free(mi.getEnterpriseContext());
}
+
}
+
}
1.1 jboss/src/main/org/jboss/ejb/plugins/TxInterceptorCMT.java
Index: TxInterceptorCMT.java
===================================================================
/*
* 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;
import java.rmi.RemoteException;
import java.rmi.ServerException;
import java.util.*;
import javax.swing.tree.*;
import javax.transaction.Status;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import javax.transaction.RollbackException;
import javax.transaction.TransactionRequiredException;
import javax.transaction.SystemException;
import javax.ejb.EJBException;
import org.jboss.ejb.Container;
import org.jboss.ejb.EnterpriseContext;
import org.jboss.ejb.MethodInvocation;
import org.jboss.tm.TxManager;
import org.jboss.logging.Logger;
import org.jboss.metadata.MetaData;
import org.jboss.metadata.BeanMetaData;
import org.jboss.metadata.MethodMetaData;
/**
* <description>
*
* @see <related>
* @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.1 $
*/
public class TxInterceptorCMT
extends AbstractInterceptor
{
// Attributes ----------------------------------------------------
private TxManager tm;
private HashMap methodTx = new HashMap();
protected Container container;
// Static --------------------------------------------------------
// Constructors --------------------------------------------------
// Public --------------------------------------------------------
public void setContainer(Container container)
{
this.container = container;
}
public Container getContainer()
{
return container;
}
// Interceptor implementation --------------------------------------
public void init()
throws Exception
{
// Store TM reference locally
tm = (TxManager) getContainer().getTransactionManager();
// Find out method->tx-type mappings from meta-info
// EnterpriseBean eb = getContainer.getMetaData();
// eb.getBeanContext()
}
public Object invokeHome(MethodInvocation mi)
throws Exception
{
return runWithTransactions(false, mi);
}
/**
* This method does invocation interpositioning of tx management
*
* @param id
* @param m
* @param args
* @return
* @exception Exception
*/
public Object invoke(MethodInvocation mi) throws Exception {
return runWithTransactions(true, mi);
}
private void printMethod(Method m, byte type) {
String name;
switch(type) {
case MetaData.TX_MANDATORY:
name = "TX_MANDATORY";
break;
case MetaData.TX_NEVER:
name = "TX_NEVER";
break;
case MetaData.TX_NOT_SUPPORTED:
name = "TX_NOT_SUPPORTED";
break;
case MetaData.TX_REQUIRED:
name = "TX_REQUIRED";
break;
case MetaData.TX_REQUIRES_NEW:
name = "TX_REQUIRES_NEW";
break;
case MetaData.TX_SUPPORTS:
name = "TX_SUPPORTS";
break;
default:
name = "TX_UNKNOWN";
}
Logger.debug(name+" for "+m.getName());
}
private Object invokeNext(boolean remoteInvocation, MethodInvocation mi) throws
Exception {
if (remoteInvocation) {
return getNext().invoke(mi);
} else {
return getNext().invokeHome(mi);
}
}
/*
* runWithTransactions
*
* This is where the meat is. We define what to do with the Tx based on the
declaration.
* The MethodInvocation is always the final authority on what the Tx looks like
leaving this
* interceptor. In other words, interceptors down the chain should not rely on
the thread
* association with Tx but on the Tx present in the MethodInvocation
*/
private Object runWithTransactions(boolean remoteInvocation, MethodInvocation
mi) throws Exception {
// Old transaction is the transaction that comes with the MI
Transaction oldTransaction = mi.getTransaction();
// New transaction is the new transaction this might start
Transaction newTransaction = null;
//DEBUG Logger.log("Current transaction in MI is
"+mi.getTransaction());
//DEBUG Logger.log("Current method "+mi.getMethod().getName());
byte transType = getTransactionMethod(mi.getMethod(), remoteInvocation);
printMethod(mi.getMethod(), transType);
switch (transType) {
case MetaData.TX_NOT_SUPPORTED:
{
// Thread arriving must be clean (jboss doesn't set the thread
previously)
// However optimized calls come with associated thread for
example
Transaction threadTx = tm.disassociateThread();
try {
// Do not set a transaction on the thread even if in MI,
just run
return invokeNext(remoteInvocation,mi );
}
finally {
// IN case we had a Tx associated with the thread reassociate
if (threadTx != null) {
tm.associateThread(threadTx);
}
}
}
case MetaData.TX_REQUIRED:
{
if (oldTransaction == null) { // No tx running
// Create tx
tm.begin();
// get the tx
newTransaction = tm.getTransaction();
// Let the method invocation know
mi.setTransaction(newTransaction);
}
else { // We have a tx propagated
// Associate it with the thread
tm.associateThread(oldTransaction);
}
// Continue invocation
try {
return invokeNext(remoteInvocation,mi );
}
catch (RemoteException e) {
if (newTransaction != null) {
//We started it,
newTransaction.rollback();
}
throw e;
}
catch (RuntimeException e) {
if (newTransaction != null) {
// We started it
newTransaction.rollback();
}
throw new ServerException("Exception occurred", e);
}
catch (Error e) {
if (newTransaction != null) {
// we started it
newTransaction.rollback();
}
throw new ServerException("Exception
occurred:"+e.getMessage());
}
finally {
//DEBUG Logger.log("TxInterceptorCMT: in finally");
Logger.log("TxInterceptorCMT: In finally");
// Only do something if we started the transaction
if (newTransaction != null) {
// Marked rollback
if (newTransaction.getStatus() ==
Status.STATUS_MARKED_ROLLBACK) {
// actually roll it back
newTransaction.rollback();
}
//Still running
else if(newTransaction.getStatus() ==
Status.STATUS_ACTIVE) {
// Commit tx
// This will happen if
// a) everything goes well
// b) app. exception was thrown
Logger.log("TxInterceptorCMT:before commit");
newTransaction.commit();
Logger.log("TxInterceptorCMT:after commit");
}
// reassociate the oldTransaction with the
methodInvocation (even null)
mi.setTransaction(oldTransaction);
}
}
}
case MetaData.TX_SUPPORTS:
{
if (oldTransaction != null) { // We have a tx propagated
// Associate it with the thread
tm.associateThread(oldTransaction);
}
// If we don't have a tx propagated we don't do anything
// Continue invocation
try {
return invokeNext(remoteInvocation,mi );
}
catch (RuntimeException e) {
throw new ServerException("Exception occurred", e);
}
catch (Error e) {
throw new ServerException("Exception
occurred:"+e.getMessage());
}
// Even on error we don't do anything with the tx, we didn't
start it
}
case MetaData.TX_REQUIRES_NEW:
{
// Thread arriving must be clean (jboss doesn't set the thread
previously)
// However optimized calls come with associated thread for
example
Transaction threadTx = tm.disassociateThread();
// Always begin a transaction
tm.begin();
// get it
newTransaction = tm.getTransaction();
// Set it on the method invocation
mi.setTransaction(newTransaction);
// Continue invocation
try {
return invokeNext(remoteInvocation,mi );
}
catch (RemoteException e) {
// We started it for sure
newTransaction.rollback();
throw e;
}
catch (RuntimeException e) {
// We started it for sure
newTransaction.rollback();
throw new ServerException("Exception occurred", e);
}
catch (Error e) {
// We started it for sure
newTransaction.rollback();
throw new ServerException("Exception
occurred:"+e.getMessage());
}
finally {
// We started the transaction for sure so we commit or roll
back
if (newTransaction.getStatus() ==
Status.STATUS_MARKED_ROLLBACK) {
newTransaction.rollback();
}
else {
// Commit tx
// This will happen if
// a) everything goes well
// b) app. exception was thrown
newTransaction.commit();
}
// set the old transaction back on the method invocation
mi.setTransaction(oldTransaction);
// IN case we had a Tx associated with the thread reassociate
if (threadTx != null) {
tm.associateThread(threadTx);
}
}
}
case MetaData.TX_MANDATORY:
{
if (oldTransaction == null) { // no transaction = bad!
throw new TransactionRequiredException("Transaction
Required, read the spec!");
}
else {
// Associate it with the thread
tm.associateThread(oldTransaction);
// That's it
return invokeNext(remoteInvocation,mi );
}
}
case MetaData.TX_NEVER:
{
if (oldTransaction != null) { // Transaction = bad!
throw new RemoteException("Transaction not allowed");
}
else {
return invokeNext(remoteInvocation,mi );
}
}
}
return null;
}
// Protected ----------------------------------------------------
// This should be cached, since this method is called very often
protected byte getTransactionMethod(Method m, boolean remoteInvocation) {
Byte b = (Byte)methodTx.get(m);
if(b != null) return b.byteValue();
BeanMetaData bmd = container.getBeanMetaData();
//DEBUG Logger.log("Found metadata for bean '"+bmd.getEjbName()+"'"+" method
is "+m.getName());
byte result = bmd.getMethodTransactionType(m.getName(),
m.getParameterTypes(), remoteInvocation);
// provide default if method is not found in descriptor
if (result == MetaData.TX_UNKNOWN) result = MetaData.TX_REQUIRED;
methodTx.put(m, new Byte(result));
return result;
}
// Inner classes -------------------------------------------------
}