package org.jboss.ejb;
import org.jboss.logging.Logger;
import org.jboss.metadata.ApplicationMetaData;
import org.jboss.metadata.BeanMetaData;
import org.jboss.metadata.SecurityRoleRefMetaData;
import org.jboss.security.RealmMapping;
import org.jboss.security.RunAsIdentity;
import org.jboss.security.SimplePrincipal;
import org.jboss.tm.TransactionTimeoutConfiguration;
import org.jboss.tm.usertx.client.ServerVMClientUserTransaction;
import javax.ejb.EJBContext;
import javax.ejb.EJBException;
import javax.ejb.EJBHome;
import javax.ejb.EJBLocalHome;
import javax.ejb.TimerService;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.NotSupportedException;
import javax.transaction.RollbackException;
import javax.transaction.Status;
import javax.transaction.Synchronization;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;
import java.rmi.RemoteException;
import java.security.Identity;
import java.security.Principal;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Properties;
import java.util.Stack;
public abstract class EnterpriseContext
implements AllowedOperationsFlags
{
protected static Logger log = Logger.getLogger(EnterpriseContext.class);
Object instance;
Container con;
Synchronization synch;
Transaction transaction;
private Principal principal;
private Principal beanPrincipal;
Object id;
int locked = 0;
Object txLock = new Object();
private Stack inMethodStack = new Stack();
private static ServerVMClientUserTransaction.UserTransactionStartedListener tsl;
public static void setUserTransactionStartedListener(ServerVMClientUserTransaction.UserTransactionStartedListener newTsl)
{
tsl = newTsl;
}
public EnterpriseContext(Object instance, Container con)
{
this.instance = instance;
this.con = con;
}
public Object getInstance()
{
return instance;
}
public Container getContainer()
{
return con;
}
public abstract void discard()
throws RemoteException;
public abstract EJBContext getEJBContext();
public void setId(Object id)
{
this.id = id;
}
public Object getId()
{
return id;
}
public Object getTxLock()
{
return txLock;
}
public void setTransaction(Transaction transaction)
{
this.transaction = transaction;
}
public Transaction getTransaction()
{
return transaction;
}
public void setPrincipal(Principal principal)
{
this.principal = principal;
this.beanPrincipal = null;
}
public void lock()
{
locked++;
}
public void unlock()
{
locked--;
if (locked < 0)
{
log.error("locked < 0", new Throwable());
}
}
public boolean isLocked()
{
return locked != 0;
}
public Principal getCallerPrincipal()
{
EJBContextImpl ctxImpl = (EJBContextImpl) getEJBContext();
return ctxImpl.getCallerPrincipalInternal();
}
public void clear()
{
this.id = null;
this.locked = 0;
this.principal = null;
this.beanPrincipal = null;
this.synch = null;
this.transaction = null;
this.inMethodStack.clear();
}
protected boolean isContainerManagedTx()
{
BeanMetaData md = con.getBeanMetaData();
return md.isContainerManagedTx();
}
protected boolean isUserManagedTx()
{
BeanMetaData md = con.getBeanMetaData();
return md.isContainerManagedTx() == false;
}
protected class EJBContextImpl
implements EJBContext
{
private InitialContext ctx;
protected EJBContextImpl()
{
try
{
ctx = new InitialContext();
}
catch (NamingException e)
{
throw new RuntimeException(e);
}
}
public Object lookup(String name)
{
try
{
return ctx.lookup(name);
}
catch (NamingException ignored)
{
}
return null;
}
private UserTransactionImpl userTransaction = null;
public Identity getCallerIdentity()
{
throw new EJBException("Deprecated");
}
public TimerService getTimerService() throws IllegalStateException
{
return getContainer().getTimerService(null);
}
public Principal getCallerPrincipal()
{
return getCallerPrincipalInternal();
}
Principal getCallerPrincipalInternal()
{
if (beanPrincipal == null)
{
RealmMapping rm = con.getRealmMapping();
if (principal != null)
{
if (rm != null)
beanPrincipal = rm.getPrincipal(principal);
else
beanPrincipal = principal;
}
else if (rm != null)
{ beanPrincipal = rm.getPrincipal(principal);
}
else
{ ApplicationMetaData appMetaData = con.getBeanMetaData().getApplicationMetaData();
String name = appMetaData.getUnauthenticatedPrincipal();
if (name != null)
beanPrincipal = new SimplePrincipal(name);
}
}
if (beanPrincipal == null)
throw new IllegalStateException("No security context set");
return beanPrincipal;
}
public EJBHome getEJBHome()
{
EJBProxyFactory proxyFactory = con.getProxyFactory();
if (proxyFactory == null)
throw new IllegalStateException("No remote home defined.");
return (EJBHome) proxyFactory.getEJBHome();
}
public EJBLocalHome getEJBLocalHome()
{
if (con.getLocalHomeClass() == null)
throw new IllegalStateException("No local home defined.");
if (con instanceof EntityContainer)
return ((EntityContainer) con).getLocalProxyFactory().getEJBLocalHome();
else if (con instanceof StatelessSessionContainer)
return ((StatelessSessionContainer) con).getLocalProxyFactory().getEJBLocalHome();
else if (con instanceof StatefulSessionContainer)
return ((StatefulSessionContainer) con).getLocalProxyFactory().getEJBLocalHome();
throw new EJBException("No EJBLocalHome available (BUG!)");
}
public Properties getEnvironment()
{
throw new EJBException("Deprecated");
}
public boolean getRollbackOnly()
{
if (con.getBeanMetaData().isBeanManagedTx())
throw new IllegalStateException("getRollbackOnly() not allowed for BMT beans.");
try
{
TransactionManager tm = con.getTransactionManager();
if (tm.getTransaction() == null)
throw new IllegalStateException("getRollbackOnly() not allowed without a transaction.");
return tm.getStatus() == Status.STATUS_MARKED_ROLLBACK;
}
catch (SystemException e)
{
log.warn("failed to get tx manager status; ignoring", e);
return true;
}
}
public void setRollbackOnly()
{
if (con.getBeanMetaData().isBeanManagedTx())
throw new IllegalStateException("setRollbackOnly() not allowed for BMT beans.");
try
{
TransactionManager tm = con.getTransactionManager();
if (tm.getTransaction() == null)
throw new IllegalStateException("setRollbackOnly() not allowed without a transaction.");
tm.setRollbackOnly();
}
catch (SystemException e)
{
log.warn("failed to set rollback only; ignoring", e);
}
}
public boolean isCallerInRole(Identity id)
{
throw new EJBException("Deprecated");
}
public boolean isCallerInRole(String roleName)
{
RunAsIdentity runAsIdentity = SecurityActions.peekRunAsIdentity(1);
if (principal == null && runAsIdentity == null)
return false;
RealmMapping rm = con.getRealmMapping();
if (rm == null)
{
String msg = "isCallerInRole() called with no security context. "
+ "Check that a security-domain has been set for the application.";
throw new IllegalStateException(msg);
}
Iterator it = getContainer().getBeanMetaData().getSecurityRoleReferences();
boolean matchFound = false;
while (it.hasNext())
{
SecurityRoleRefMetaData meta = (SecurityRoleRefMetaData) it.next();
if (meta.getName().equals(roleName))
{
roleName = meta.getLink();
matchFound = true;
break;
}
}
if (!matchFound)
log.warn("no match found for security role " + roleName +
" in the deployment descriptor for ejb " + getContainer().getBeanMetaData().getEjbName());
HashSet set = new HashSet();
set.add(new SimplePrincipal(roleName));
if (runAsIdentity == null)
return rm.doesUserHaveRole(principal, set);
else
return runAsIdentity.doesUserHaveRole(set);
}
public UserTransaction getUserTransaction()
{
if (userTransaction == null)
{
if (isContainerManagedTx())
{
throw new IllegalStateException
("CMT beans are not allowed to get a UserTransaction");
}
userTransaction = new UserTransactionImpl();
}
return userTransaction;
}
}
protected class UserTransactionImpl
implements UserTransaction
{
private int timeout = 0;
boolean trace;
public UserTransactionImpl()
{
trace = log.isTraceEnabled();
if (trace)
log.trace("new UserTx: " + this);
}
public void begin()
throws NotSupportedException, SystemException
{
TransactionManager tm = con.getTransactionManager();
int oldTimeout = -1;
if (tm instanceof TransactionTimeoutConfiguration)
oldTimeout = ((TransactionTimeoutConfiguration) tm).getTransactionTimeout();
tm.setTransactionTimeout(timeout);
try
{
tm.begin();
if (tsl != null)
tsl.userTransactionStarted();
Transaction tx = tm.getTransaction();
if (trace)
log.trace("UserTx begin: " + tx);
setTransaction(tx);
}
finally
{
if (oldTimeout != -1)
tm.setTransactionTimeout(oldTimeout);
}
}
public void commit()
throws RollbackException, HeuristicMixedException, HeuristicRollbackException,
SecurityException, IllegalStateException, SystemException
{
TransactionManager tm = con.getTransactionManager();
try
{
Transaction tx = tm.getTransaction();
if (trace)
log.trace("UserTx commit: " + tx);
int status = tm.getStatus();
tm.commit();
}
finally
{
setTransaction(null);
}
}
public void rollback()
throws IllegalStateException, SecurityException, SystemException
{
TransactionManager tm = con.getTransactionManager();
try
{
Transaction tx = tm.getTransaction();
if (trace)
log.trace("UserTx rollback: " + tx);
tm.rollback();
}
finally
{
setTransaction(null);
}
}
public void setRollbackOnly()
throws IllegalStateException, SystemException
{
TransactionManager tm = con.getTransactionManager();
Transaction tx = tm.getTransaction();
if (trace)
log.trace("UserTx setRollbackOnly: " + tx);
tm.setRollbackOnly();
}
public int getStatus()
throws SystemException
{
TransactionManager tm = con.getTransactionManager();
return tm.getStatus();
}
public void setTransactionTimeout(int seconds)
throws SystemException
{
timeout = seconds;
}
}
}