package org.jboss.ejb;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Set;
import java.rmi.RemoteException;
import javax.ejb.EJBObject;
import javax.ejb.EJBLocalObject;
import javax.ejb.RemoveException;
import javax.ejb.EJBException;
import javax.ejb.Handle;
import javax.management.ObjectName;
import org.jboss.invocation.Invocation;
import org.jboss.invocation.InvocationType;
import org.jboss.util.UnreachableStatementException;
public class StatefulSessionContainer
extends SessionContainer
implements EJBProxyFactoryContainer, InstancePoolContainer
{
protected StatefulSessionPersistenceManager persistenceManager;
protected InstanceCache instanceCache;
protected Method getEJBObject;
public void setInstanceCache(InstanceCache ic)
{
this.instanceCache = ic;
ic.setContainer(this);
}
public InstanceCache getInstanceCache()
{
return instanceCache;
}
public StatefulSessionPersistenceManager getPersistenceManager()
{
return persistenceManager;
}
public void setPersistenceManager(StatefulSessionPersistenceManager pm)
{
persistenceManager = pm;
pm.setContainer(this);
}
public Set getMethodPermissions(Method m, InvocationType iface)
{
if (m.equals(getEJBObject) == false)
return super.getMethodPermissions(m, iface);
Class[] sig = {};
Set permissions = getBeanMetaData().getMethodPermissions("create",
sig, iface);
return permissions;
}
protected void createService() throws Exception
{
super.createService();
try
{
getEJBObject = Handle.class.getMethod("getEJBObject",
new Class[0]);
}
catch (Exception e)
{
log.warn("Failed to grant access to the Handle.getEJBObject method");
}
}
protected void createInstanceCache() throws Exception
{
try
{
ObjectName containerName = super.getJmxName();
Hashtable props = containerName.getKeyPropertyList();
props.put("plugin", "cache");
ObjectName cacheName = new ObjectName(containerName.getDomain(), props);
server.registerMBean(instanceCache, cacheName);
}
catch (Throwable t)
{
log.debug("Failed to register cache as mbean", t);
}
instanceCache.create();
}
protected void createPersistenceManager() throws Exception
{
persistenceManager.create();
}
protected void startPersistenceManager() throws Exception
{
persistenceManager.start();
}
protected void startInstanceCache() throws Exception
{
instanceCache.start();
}
protected void stopPersistenceManager()
{
persistenceManager.stop();
}
protected void stopInstanceCache()
{
instanceCache.stop();
}
protected void destroyPersistenceManager()
{
persistenceManager.destroy();
persistenceManager.setContainer(null);
}
protected void destroyInstanceCache()
{
instanceCache.destroy();
instanceCache.setContainer(null);
try
{
ObjectName containerName = super.getJmxName();
Hashtable props = containerName.getKeyPropertyList();
props.put("plugin", "cache");
ObjectName cacheName = new ObjectName(containerName.getDomain(), props);
server.unregisterMBean(cacheName);
}
catch (Throwable ignore)
{
}
}
public void remove(Invocation mi)
throws RemoteException, RemoveException
{
StatefulSessionEnterpriseContext ctx = (StatefulSessionEnterpriseContext) mi.getEnterpriseContext();
if (ctx.getId() == null)
{
throw new RemoveException("SFSB has been removed already");
}
try
{
AllowedOperationsAssociation.pushInMethodFlag(IN_EJB_REMOVE);
getPersistenceManager().removeSession(ctx);
}
finally
{
AllowedOperationsAssociation.popInMethodFlag();
}
ctx.setId(null);
removeCount++;
}
private void createSession(final Method m,
final Object[] args,
final StatefulSessionEnterpriseContext ctx)
throws Exception
{
boolean debug = log.isDebugEnabled();
Object id = getPersistenceManager().createId(ctx);
if (debug)
{
log.debug("Created new session ID: " + id);
}
ctx.setId(id);
try
{
AllowedOperationsAssociation.pushInMethodFlag(IN_EJB_CREATE);
String createName = m.getName();
Object instance = ctx.getInstance();
String ejbCreateName = "ejbC" + createName.substring(1);
Method createMethod = instance.getClass().getMethod(ejbCreateName, m.getParameterTypes());
if (debug)
{
log.debug("Using create method for session: " + createMethod);
}
createMethod.invoke(instance, args);
createCount++;
}
catch (IllegalAccessException e)
{
ctx.setId(null);
throw new EJBException(e);
}
catch (InvocationTargetException e)
{
ctx.setId(null);
Throwable t = e.getTargetException();
if (t instanceof RuntimeException)
{
if (t instanceof EJBException)
throw (EJBException) t;
throw new EJBException((Exception) t);
}
else if (t instanceof Exception)
{
throw (Exception) t;
}
else if (t instanceof Error)
{
throw (Error) t;
}
else
{
throw new org.jboss.util.UnexpectedThrowable(t);
}
}
finally
{
AllowedOperationsAssociation.popInMethodFlag();
}
getPersistenceManager().createdSession(ctx);
getInstanceCache().insert(ctx);
if (getProxyFactory() != null)
ctx.setEJBObject((EJBObject) getProxyFactory().getStatefulSessionEJBObject(id));
if (getLocalHomeClass() != null)
ctx.setEJBLocalObject(getLocalProxyFactory().getStatefulSessionEJBLocalObject(id));
}
public EJBObject createHome(Invocation mi)
throws Exception
{
StatefulSessionEnterpriseContext ctx = (StatefulSessionEnterpriseContext) mi.getEnterpriseContext();
createSession(mi.getMethod(), mi.getArguments(), ctx);
return ctx.getEJBObject();
}
public void removeLocalHome(Invocation mi)
throws RemoteException, RemoveException
{
throw new UnreachableStatementException();
}
public EJBLocalObject createLocalHome(Invocation mi)
throws Exception
{
StatefulSessionEnterpriseContext ctx = (StatefulSessionEnterpriseContext) mi.getEnterpriseContext();
createSession(mi.getMethod(), mi.getArguments(), ctx);
return ctx.getEJBLocalObject();
}
public EJBObject getEJBObject(Invocation mi) throws RemoteException
{
EJBProxyFactory ci = getProxyFactory();
if (ci == null)
{
String msg = "No ProxyFactory, check for ProxyFactoryFinderInterceptor";
throw new IllegalStateException(msg);
}
Object id = mi.getArguments()[0];
if (id == null)
throw new IllegalStateException("Cannot get a session interface with a null id");
InstanceCache cache = getInstanceCache();
BeanLock lock = getLockManager().getLock(id);
lock.sync();
try
{
if (cache.get(id) == null)
throw new RemoteException("Session no longer exists: " + id);
}
finally
{
lock.releaseSync();
getLockManager().removeLockRef(id);
}
return (EJBObject) ci.getStatefulSessionEJBObject(id);
}
public void removeHome(Invocation mi)
throws RemoteException, RemoveException
{
throw new Error("Not Yet Implemented");
}
protected void setupHomeMapping() throws Exception
{
boolean isEJB1x = metaData.getApplicationMetaData().isEJB1x();
Map map = new HashMap();
if (homeInterface != null)
{
Method[] m = homeInterface.getMethods();
for (int i = 0; i < m.length; i++)
{
try
{
if (isEJB1x == false && m[i].getName().startsWith("create"))
{
map.put(m[i], getClass().getMethod("createHome",
new Class[]{Invocation.class}));
}
else
{
map.put(m[i], getClass().getMethod(m[i].getName() + "Home",
new Class[]{Invocation.class}));
}
}
catch (NoSuchMethodException e)
{
log.info(m[i].getName() + " in bean has not been mapped");
}
}
}
if (localHomeInterface != null)
{
Method[] m = localHomeInterface.getMethods();
for (int i = 0; i < m.length; i++)
{
try
{
if (isEJB1x == false && m[i].getName().startsWith("create"))
{
map.put(m[i], getClass().getMethod("createLocalHome",
new Class[]{Invocation.class}));
}
else
{
map.put(m[i], getClass().getMethod(m[i].getName() + "LocalHome",
new Class[]{Invocation.class}));
}
}
catch (NoSuchMethodException e)
{
log.info(m[i].getName() + " in bean has not been mapped");
}
}
}
try
{
Class handleClass = Class.forName("javax.ejb.Handle");
Method getEJBObjectMethod = handleClass.getMethod("getEJBObject", new Class[0]);
map.put(getEJBObjectMethod, getClass().getMethod("getEJBObject",
new Class[]{Invocation.class}));
}
catch (NoSuchMethodException e)
{
log.debug("Couldn't find getEJBObject method on container");
}
homeMapping = map;
}
protected Interceptor createContainerInterceptor()
{
return new ContainerInterceptor();
}
class ContainerInterceptor
extends AbstractContainerInterceptor
{
public Object invokeHome(Invocation mi) throws Exception
{
boolean trace = log.isTraceEnabled();
if (trace)
{
log.trace("HOMEMETHOD coming in ");
log.trace("" + mi.getMethod());
log.trace("HOMEMETHOD coming in hashcode" + mi.getMethod().hashCode());
log.trace("HOMEMETHOD coming in classloader" + mi.getMethod().getDeclaringClass().getClassLoader().hashCode());
log.trace("CONTAINS " + getHomeMapping().containsKey(mi.getMethod()));
}
Method miMethod = mi.getMethod();
Method m = (Method) getHomeMapping().get(miMethod);
if (m == null)
{
String msg = "Invalid invocation, check your deployment packaging"
+ ", method=" + miMethod;
throw new EJBException(msg);
}
if (trace)
{
log.trace("HOMEMETHOD m " + m);
java.util.Iterator iterator = getHomeMapping().keySet().iterator();
while (iterator.hasNext())
{
Method me = (Method) iterator.next();
if (me.getName().endsWith("create"))
{
log.trace(me.toString());
log.trace("" + me.hashCode());
log.trace("" + me.getDeclaringClass().getClassLoader().hashCode());
log.trace("equals " + me.equals(mi.getMethod()) + " " + mi.getMethod().equals(me));
}
}
}
try
{
return mi.performCall(StatefulSessionContainer.this, m, new Object[]{mi});
}
catch (Exception e)
{
rethrow(e);
}
throw new org.jboss.util.UnreachableStatementException();
}
public Object invoke(Invocation mi) throws Exception
{
EnterpriseContext ctx = (EnterpriseContext) mi.getEnterpriseContext();
if (ctx.getTransaction() == null)
ctx.setTransaction(mi.getTransaction());
Method miMethod = mi.getMethod();
Method m = (Method) getBeanMapping().get(miMethod);
if (m == null)
{
String msg = "Invalid invocation, check your deployment packaging"
+ ", method=" + miMethod;
throw new EJBException(msg);
}
if (m.getDeclaringClass().equals(StatefulSessionContainer.class)
|| m.getDeclaringClass().equals(SessionContainer.class))
{
try
{
return mi.performCall(StatefulSessionContainer.this, m, new Object[]{mi});
}
catch (Exception e)
{
rethrow(e);
}
}
else
{
try
{
Object bean = ctx.getInstance();
return mi.performCall(bean, m, mi.getArguments());
}
catch (Exception e)
{
rethrow(e);
}
}
throw new org.jboss.util.UnreachableStatementException();
}
}
}