package org.jboss.web.tomcat.tc5.session;
import org.apache.catalina.Session;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.Context;
import org.apache.catalina.deploy.FilterDef;
import org.apache.catalina.deploy.FilterMap;
import org.jboss.metadata.WebMetaData;
import org.jboss.util.NestedRuntimeException;
import javax.transaction.TransactionManager;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.RollbackException;
import javax.transaction.Status;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionRequiredException;
import javax.transaction.TransactionRolledbackException;
import javax.transaction.UserTransaction;
import javax.naming.NamingException;
import javax.naming.InitialContext;
import java.util.List;
public class JBossCacheManager
extends JBossManager
{
private static final String info_ = "JBossCacheManager/1.0";
private InitialContext initialContext_;
private JBossCacheService proxy_;
protected boolean useJK_ = false;
protected TransactionManager tm;
public JBossCacheManager()
{
}
public void init(String name, WebMetaData webMetaData, boolean useJK, boolean useLocalCache)
throws ClusteringNotSupportedException
{
super.init(name, webMetaData, useJK, useLocalCache);
this.useJK_ = useJK;
try
{
proxy_ = (JBossCacheService) new JBossCacheService();
}
catch (Throwable t)
{
String str = "JBossCacheService to Tomcat clustering not found";
log_.error(str);
throw new ClusteringNotSupportedException(str);
}
}
public JBossCacheService getCacheService()
{
return proxy_;
}
public void start() throws LifecycleException
{
super.start();
try
{
tm =(TransactionManager)new InitialContext().lookup("java:/TransactionManager");
}
catch (Exception e)
{
log_.error("Cannot get a reference to the transaction manager", e);
throw new LifecycleException(e);
}
if (useJK_)
{
boolean hasFilterCreated = false;
Context context = (Context) container_;
context.getServletContext().setAttribute("AbstractJBossManager", this);
String filterName = "JvmRouteFilter";
if (log_.isDebugEnabled())
{
log_.debug("start(): we are using mod_jk(2) for load-balancing. Will add " + filterName);
}
FilterDef def = new FilterDef();
def.setFilterName(filterName);
def.setDescription("Filter to re-package the session id with jvmroute if failing-over under mod_jk(2)");
def.setFilterClass(org.jboss.web.tomcat.tc5.JvmRouteFilter.class.getName());
FilterDef[] defs = context.findFilterDefs();
for (int i = 0; i < defs.length; i++)
{
FilterDef d = defs[i];
if (d.getFilterName().equals(filterName))
{
hasFilterCreated = true;
break;
}
}
if (!hasFilterCreated)
context.addFilterDef(def);
FilterMap map = new FilterMap();
map.setFilterName(filterName);
map.setURLPattern("/*");
context.addFilterMap(map);
}
ClassLoader tcl = super.getContainer().getLoader().getClassLoader();
proxy_.start(tcl, this);
if (log_.isDebugEnabled())
{
log_.debug("start(): JBossCacheService started");
}
}
public void stop() throws LifecycleException
{
super.stop();
proxy_.stop();
tm = null;
}
public Session createSession()
{
return createSession(null);
}
public Session createSession(String sessionId)
{
ClusteredSession session = null;
if (replicationGranularity_ == WebMetaData.REPLICATION_GRANULARITY_ATTRIBUTE)
{
session = (ClusteredSession) new AttributeBasedClusteredSession(this);
}
else if (replicationGranularity_ == WebMetaData.REPLICATION_GRANULARITY_SESSION)
{
session = (ClusteredSession) new SessionBasedClusteredSession(this);
}
session.setNew(true);
session.setCreationTime(System.currentTimeMillis());
session.setMaxInactiveInterval(this.maxInactiveInterval_);
if (sessionId == null)
{
sessionId = this.getNextId();
if (useJK_)
{
if (log_.isDebugEnabled())
{
log_.debug("createSession(): useJK is true. Will append JvmRoute: " + this.getJvmRoute());
}
sessionId += "." + this.getJvmRoute();
}
}
session.setValid(true);
session.setId(sessionId);
if (log_.isDebugEnabled())
{
log_.debug("Creating an ClusteredSession with id: " + session.getId());
}
createdCounter_++;
return session;
}
public boolean storeSession(Session baseSession)
{
if (!(baseSession instanceof ClusteredSession))
{
throw new IllegalArgumentException("You can only add ClusteredSessions to this Manager");
}
ClusteredSession session = (ClusteredSession) baseSession;
if (session == null)
{
return false;
}
if (session.isValid())
{
sessions_.put(getRealId(session.getId()), session);
String id = session.getId();
long beginPassivate = System.currentTimeMillis();
session.passivate();
long endPassivate = System.currentTimeMillis();
stats_.updatePassivationStats(id, (endPassivate - beginPassivate));
if (log_.isDebugEnabled())
{
log_.debug("check to see if needs to store and replicate session with id " + id);
}
long beginReplication = System.currentTimeMillis();
processSessionRepl(session);
long endReplication = System.currentTimeMillis();
stats_.updateReplicationStats(id, (endReplication - beginReplication));
return true;
}
else
{
return false;
}
}
public void add(Session session)
{
if (session == null)
return;
if (!session.isValid())
{
log_.error("Cannot add session with id=" + session.getId() + " because it is invalid");
return;
}
if (maxActive_ != -1 && activeCounter_ >= maxActive_)
{
rejectedCounter_++;
throw new IllegalStateException("JBossCacheManager.add(): number of active sessions exceeds the maximum limit: " +
maxActive_ + " when trying to add session id " + session.getId());
}
if (storeSession((ClusteredSession) session))
{
activeCounter_++;
if (log_.isDebugEnabled())
{
log_.debug("Session with id=" + session.getId() + " added. Current active sessions " + activeCounter_);
}
}
}
public Session createEmptySession()
{
ClusteredSession session = null;
if (replicationGranularity_ == WebMetaData.REPLICATION_GRANULARITY_ATTRIBUTE)
{
session = (ClusteredSession) new AttributeBasedClusteredSession(this);
}
else if (replicationGranularity_ == WebMetaData.REPLICATION_GRANULARITY_SESSION)
{
session = (ClusteredSession) new SessionBasedClusteredSession(this);
}
if (log_.isDebugEnabled())
{
log_.debug("Creating an empty ClusteredSession: " + session);
}
createdCounter_++;
return session;
}
public Session findSession(String id)
{
String realId = getRealId(id);
ClusteredSession session = findLocalSession(realId);
if (session != null && !session.isOutdated() )
{
return session;
}
else
{
return loadSession(realId);
}
}
public Session[] findSessions()
{
Session[] sessions;
List ids = proxy_.getNewSessionsInStore();
if(ids.size() ==0)
{
Session[] sess = new Session[0];
sess = (Session[]) sessions_.values().toArray(sess);
return sess;
}
if(log_.isDebugEnabled()) {
log_.debug("findSessions: find ids from cache store: " + ids);
}
for(int i=0; i < ids.size(); i++) {
Session session = loadSession((String)ids.get(i));
if( session == null )
{
continue;
}
sessions_.put(ids.get(i), session); }
Session[] sess = new Session[0];
sess = (Session[]) sessions_.values().toArray(sess);
return sess;
}
public ClusteredSession[] findLocalSessions()
{
ClusteredSession[] sess = new ClusteredSession[0];
sess = (ClusteredSession[]) sessions_.values().toArray(sess);
return sess;
}
public ClusteredSession findLocalSession(String realId)
{
ClusteredSession session = (ClusteredSession) sessions_.get(realId);
return session;
}
public void remove(Session session)
{
String id = session.getId();
if (id == null) return;
if (log_.isDebugEnabled())
{
log_.debug("Removing session from store with id: " + id);
}
((ClusteredSession) session).removeMyself();
sessions_.remove(getRealId(session.getId()));
activeCounter_--;
}
public void removeLocal(Session session)
{
String id = session.getId();
if (id == null) return;
if (log_.isDebugEnabled())
{
log_.debug("Removing session from local store with id: " + id);
}
((ClusteredSession) session).removeMyselfLocal();
sessions_.remove(getRealId(session.getId()));
expiredCounter_++;
activeCounter_--;
}
protected Session loadSession(String realId)
{
ClusteredSession session = null;
if (realId == null)
{
return null;
}
session = (ClusteredSession) proxy_.getSession(realId);
if (session != null)
{
session.initAfterLoad(this);
sessions_.put(getRealId(session.getId()), session);
}
if (log_.isDebugEnabled())
{
log_.debug("loadSession(): id= " + realId + ", session=" + session);
}
return session;
}
protected void processSessionRepl(ClusteredSession session)
{
boolean doTx = false;
try
{
if(tm.getTransaction() == null)
doTx = true;
if(doTx)
tm.begin();
session.processSessionRepl();
}
catch (Exception ex)
{
log_.error("processSessionRepl: failed with exception: " + ex);
try
{
tm.setRollbackOnly();
}
catch (Exception exn)
{
exn.printStackTrace();
}
throw new NestedRuntimeException("JBossCacheManager.processSessionRepl(): failed to replicate session.", ex);
}
finally
{
if(doTx)
endTransaction();
}
}
protected void endTransaction()
{
try {
if(tm.getTransaction().getStatus() != Status.STATUS_MARKED_ROLLBACK)
{
tm.commit();
} else
{
tm.rollback();
}
} catch (Exception e) {
e.printStackTrace();
throw new NestedRuntimeException("TreeCacheAop.endTransaction(): ", e);
}
}
protected void processExpires()
{
if (log_.isTraceEnabled())
{
log_.trace("Looking for sessions that have expired ...");
}
try
{
Session sessions[] = findSessions();
for (int i = 0; i < sessions.length; ++i)
{
ClusteredSession session = (ClusteredSession) sessions[i];
if(session == null)
{
log_.warn("processExpires(): processing null session at index " +i);
continue;
}
boolean doTx = false;
try
{
if(tm.getTransaction() == null)
doTx = true;
if(doTx)
tm.begin();
if (!session.isValid()) continue;
}
catch (Exception ex)
{
log_.error("processSessionExpire: failed with exception: " + ex);
try
{
tm.setRollbackOnly();
}
catch (Exception exn)
{
exn.printStackTrace();
}
throw new NestedRuntimeException("JBossCacheManager.processSessionExpire(): failed to expire session.", ex);
}
finally
{
if(doTx)
endTransaction();
}
}
}
catch (Exception ex)
{
log_.error("processExpires: failed with exception: " + ex);
ex.printStackTrace();
}
}
private String getRealId(String id)
{
if (!useJK_) return id;
int index = id.indexOf(".");
if (index > 0)
{
return id.substring(0, id.indexOf("."));
}
else
{
return id;
}
}
}