/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.web.tomcat.service.session;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.servlet.http.HttpServletResponse;
import org.apache.catalina.Container;
import org.apache.catalina.Context;
import org.apache.catalina.Engine;
import org.apache.catalina.Globals;
import org.apache.catalina.Host;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.LifecycleListener;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.connector.Response;
import org.apache.catalina.core.ContainerBase;
import org.apache.catalina.util.LifecycleSupport;
import org.apache.tomcat.util.http.TomcatCookie;
import org.apache.tomcat.util.modeler.Registry;
import org.jboss.logging.Logger;
import org.jboss.metadata.web.jboss.JBossWebMetaData;
import org.jboss.metadata.web.jboss.PassivationConfig;
import org.jboss.web.tomcat.service.session.distributedcache.spi.ClusteringNotSupportedException;
import org.jboss.web.tomcat.service.session.distributedcache.spi.OutgoingDistributableSessionData;
import org.jboss.web.tomcat.statistics.ReplicationStatistics;
/**
* Base abstract implementation of Tomcat manager without the concept of
* session operations, e.g., add, remove, etc.
*
* @author Ben Wang
* @author Hany Mesha
* @author Brian Stansberry
*
* @version $Revision: 91181 $
*/
public abstract class JBossManager
implements AbstractJBossManager, Lifecycle,
JBossManagerMBean, PropertyChangeListener
{
// ------------------------------------------------------------------ Fields
protected ReplicationStatistics stats_ = new ReplicationStatistics();
/**
* Session passivation flag set in jboss-web.xml by the user.
* If true, then the session passivation is enabled for this web application,
* otherwise, it's disabled
*/
protected boolean passivationMode_ = false;
/**
* Min time (milliseconds) the session must be idle since lastAccesstime before
* it's eligible for passivation if passivation is enabled and more
* than maxActiveAllowed_ sessions are in memory.
* Setting to -1 means it's ignored.
*/
protected long passivationMinIdleTime_ = -1;
/**
* Max time (milliseconds) the session must be idle since lastAccesstime before
* it will be passivated if passivation is enabled.
* Setting to -1 means session should not be forced out.
*/
protected long passivationMaxIdleTime_ = -1;
/**
* The lifecycle_ event support for this component.
*/
protected LifecycleSupport lifecycle_ = new LifecycleSupport(this);
/**
* Has this component been started_ yet?
*/
protected boolean started_ = false;
/**
* Are we allowing backgroundProcess() to execute? We use an object
* so stop() can lock on it to wait for
*/
protected AtomicBoolean backgroundProcessAllowed = new AtomicBoolean();
/**
* The objectname this Manager is associated with
*/
protected ObjectName objectName_;
/**
* The Log object for this class
*/
protected Logger log_ = Logger.getLogger(this.getClass().getName());
/**
* Whether trace logging is enabled for our logger. Rechecked
* every time backgroundProcess() is invoked.
*/
protected boolean trace_ = log_.isTraceEnabled();
/**
* The Container with which this Manager is associated.
*/
protected Container container_;
/**
/**
* The distributable flag for Sessions created by this Manager. If this
* flag is set to <code>true</code>, any user attributes added to a
* session controlled by this Manager must be Serializable.
*/
protected boolean distributable_ = true;
/**
* The default maximum inactive interval for Sessions created by
* this Manager.
*/
protected int maxInactiveInterval_ = 60;
/** Maximum of active sessions allowed. -1 is unlimited. */
protected int maxActiveAllowed_ = -1;
/** Number of sessions created by this manager */
protected AtomicInteger createdCounter_ = new AtomicInteger();
/** number of sessions rejected because the number active sessions exceeds maxActive */
protected AtomicInteger rejectedCounter_ = new AtomicInteger();
/** Number of active sessions */
protected AtomicInteger localActiveCounter_ = new AtomicInteger();
/** Maximum number of concurrently locally active sessions */
protected AtomicInteger maxLocalActiveCounter_ = new AtomicInteger();
/** Maximum number of active sessions seen so far */
protected AtomicInteger maxActiveCounter_ = new AtomicInteger();
/** Number of sessions that have been active locally that are now expired. */
protected AtomicInteger expiredCounter_ = new AtomicInteger();
/** Number of ms since last call to reset() */
protected long timeSinceLastReset_ = 0;
/** Cumulative time spent in backgroundProcess */
protected AtomicLong processingTime_ = new AtomicLong();
/** Stores the locally active sessions. */
protected final Map<String, ClusteredSession<? extends OutgoingDistributableSessionData>> sessions_ =
new ConcurrentHashMap<String,ClusteredSession<? extends OutgoingDistributableSessionData>>();
/** The property change support for this component. */
protected PropertyChangeSupport support_ = new PropertyChangeSupport(this);
/** Generates ids for new sessions */
protected SessionIDGenerator sessionIDGenerator_= SessionIDGenerator.getInstance();;
/** Our containing engine's jvmRoute (if it has one) */
protected String jvmRoute_;
/** Our JMX Server */
protected MBeanServer mserver_ = null;
/**
* How often calls to backgroundProcess() should trigger
* expiration/passivation processing
*/
protected volatile int processExpiresFrequency = 1;
/**
* How many times backgroundProcess() has been called since we last
* processed expiration/passivation.
*/
protected int backgroundProcessCount = 0;
/** Maximum time in ms a now expired session has been alive */
protected AtomicInteger maxAliveTime = new AtomicInteger();
/** Average time in ms a now expired session has been alive */
protected AtomicInteger averageAliveTime = new AtomicInteger();
/**
* Number of times our session id generator has generated an id
* that matches an existing session.
*/
protected AtomicInteger duplicates_ = new AtomicInteger();
// TODO Need a string manager to handle localization
// ------------------------------------------------------------ Constructors
/**
* Creates a new JBossManager
*/
protected JBossManager()
{
}
// -------------------------------------------------------------- Properties
public boolean getUseSessionPassivation()
{
return passivationMode_;
}
public void setUseSessionPassivation(boolean enabled)
{
this.passivationMode_ = enabled;
}
public long getPassivationMinIdleTime()
{
return passivationMinIdleTime_;
}
public void setPassivationMinIdleTime(long passivationMinIdleTime)
{
this.passivationMinIdleTime_ = passivationMinIdleTime;
}
public long getPassivationMaxIdleTime()
{
return passivationMaxIdleTime_;
}
public void setPassivationMaxIdleTime(long passivationMaxIdleTime)
{
this.passivationMaxIdleTime_ = passivationMaxIdleTime;
}
// ---------------------------------------------------- AbstractJBossManager
/**
* {@inheritDoc}
*/
public void init(String name, JBossWebMetaData webMetaData)
throws ClusteringNotSupportedException
{
if (webMetaData.getMaxActiveSessions() != null)
{
maxActiveAllowed_ = webMetaData.getMaxActiveSessions().intValue();
}
PassivationConfig pConfig = webMetaData.getPassivationConfig();
if (pConfig != null)
{
if (pConfig.getUseSessionPassivation() != null)
{
setUseSessionPassivation(pConfig.getUseSessionPassivation().booleanValue());
if (getUseSessionPassivation())
{
Integer min = pConfig.getPassivationMinIdleTime();
if (min != null)
setPassivationMinIdleTime(min.intValue());
Integer max = pConfig.getPassivationMaxIdleTime();
if (max != null)
setPassivationMaxIdleTime(max.intValue());
}
}
}
log_.debug("init(): maxActiveSessions allowed is " + maxActiveAllowed_ +
" and passivationMode is " + passivationMode_);
}
/**
* {@inheritDoc}
*/
public String getJvmRoute()
{
if (jvmRoute_ == null)
{
Engine e = getEngine();
jvmRoute_= (e == null ? null : e.getJvmRoute());
}
return jvmRoute_;
}
/**
* {@inheritDoc}
*/
public void setNewSessionCookie(String sessionId, HttpServletResponse response)
{
if (response != null)
{
Context context = (Context) container_;
Connector connector = ((Response) response).getConnector();
if (context.getCookies())
{
// set a new session cookie
TomcatCookie cookie = new TomcatCookie(Globals.SESSION_COOKIE_NAME, sessionId);
// JBAS-6206. Configure cookie a la o.a.c.connector.Request.configureSessionCookie()
cookie.setMaxAge(-1);
if (context.getSessionCookie().getPath() != null)
{
cookie.setPath(context.getSessionCookie().getPath());
}
else
{
String contextPath = context.getEncodedPath();
if ("".equals(contextPath))
{
contextPath = "/";
}
cookie.setPath(contextPath);
}
if (context.getSessionCookie().getComment() != null)
{
cookie.setComment(context.getSessionCookie().getComment());
}
if (context.getSessionCookie().getDomain() != null)
{
cookie.setDomain(context.getSessionCookie().getDomain());
}
if (context.getSessionCookie().isHttpOnly())
{
cookie.setHttpOnly(true);
}
if (context.getSessionCookie().isSecure())
{
cookie.setSecure(true);
}
if (connector.getSecure())
{
cookie.setSecure(true);
}
if (trace_)
{
log_.trace("Setting cookie with session id:" + sessionId + " & name:" + Globals.SESSION_COOKIE_NAME);
}
response.addCookie(cookie);
}
}
}
// ----------------------------------------------------------------- Manager
/**
* {@inheritDoc}
*/
public void addPropertyChangeListener(PropertyChangeListener listener)
{
support_.addPropertyChangeListener(listener);
}
/**
* {@inheritDoc}
*/
public void removePropertyChangeListener(PropertyChangeListener listener)
{
support_.removePropertyChangeListener(listener);
}
/**
* {@inheritDoc}
*/
public void propertyChange(PropertyChangeEvent evt)
{
support_.firePropertyChange(evt);
}
/**
* {@inheritDoc}
*/
public void backgroundProcess()
{
// Always reset trace_
trace_ = log_.isTraceEnabled();
// For other work, only execute every processExpiresFrequency
backgroundProcessCount = (backgroundProcessCount + 1) % processExpiresFrequency;
if (backgroundProcessCount != 0)
return;
synchronized (backgroundProcessAllowed)
{
if (backgroundProcessAllowed.get())
{
long start = System.currentTimeMillis();
processExpirationPassivation();
long elapsed = System.currentTimeMillis() - start;
processingTime_.addAndGet(elapsed);
}
}
}
/**
* {@inheritDoc}
*/
public int getActiveSessions()
{
return (int) getLocalActiveSessionCount();
}
/**
* {@inheritDoc}
*/
public Container getContainer()
{
return container_;
}
/**
* {@inheritDoc}
*/
public void setContainer(Container container)
{
// De-register from the old Container (if any)
if ((this.container_ != null) && (this.container_ instanceof Context))
this.container_.removePropertyChangeListener(this);
// Default processing provided by our superclass
this.container_ = container;
// Register with the new Container (if any)
if ((this.container_ != null) && (this.container_ instanceof Context))
{
setMaxInactiveInterval
(((Context) this.container_).getSessionTimeout() * 60);
this.container_.addPropertyChangeListener(this);
}
}
/**
* {@inheritDoc}
*/
public boolean getDistributable()
{
return distributable_;
}
/**
* {@inheritDoc}
*/
public void setDistributable(boolean distributable)
{
this.distributable_ = distributable;
}
/**
* {@inheritDoc}
*/
public int getExpiredSessions()
{
return expiredCounter_.get();
}
/** No-op */
public void setExpiredSessions(int expiredSessions)
{
// ignored
}
/**
* {@inheritDoc}
*/
public int getMaxActive()
{
return maxActiveAllowed_;
}
/**
* {@inheritDoc}
*/
public void setMaxActive(int maxActive)
{
this.maxActiveAllowed_ = maxActive;
}
/**
* {@inheritDoc}
*/
public int getMaxInactiveInterval()
{
return maxInactiveInterval_;
}
/**
* {@inheritDoc}
*/
public void setMaxInactiveInterval(int interval)
{
this.maxInactiveInterval_ = interval;
}
/**
* {@inheritDoc}
*/
public long getProcessingTime()
{
return this.processingTime_.get();
}
/**
* {@inheritDoc}
*/
public int getRejectedSessions()
{
return rejectedCounter_.get();
}
/** No-op */
public void setRejectedSessions(int rejectedSessions)
{
// ignored
}
/**
* {@inheritDoc}
*/
public int getSessionAverageAliveTime()
{
return averageAliveTime.get();
}
/** No-op */
public void setSessionAverageAliveTime(int sessionAverageAliveTime)
{
// ignored
}
/**
* {@inheritDoc}
*/
public int getSessionCounter()
{
return createdCounter_.get();
}
/** No-op */
public void setSessionCounter(int sessionCounter)
{
// ignored
}
/**
* {@inheritDoc}
*/
public int getSessionIdLength()
{
return SessionIDGenerator.SESSION_ID_BYTES;
}
/** No-op */
public void setSessionIdLength(int idLength)
{
// ignored
}
/**
* {@inheritDoc}
*/
public int getSessionMaxAliveTime()
{
return maxAliveTime.get();
}
/** No-op */
public void setSessionMaxAliveTime(int sessionAliveTime)
{
// ignored
}
/** Throws UnsupportedOperationException */
public void load() throws ClassNotFoundException, IOException
{
throw new UnsupportedOperationException("load() not supported");
}
/** Throws UnsupportedOperationException */
public void unload() throws IOException
{
throw new UnsupportedOperationException("unload() not supported");
}
// -------------------------------------------------------------- Lifecycle
public void addLifecycleListener(LifecycleListener listener)
{
lifecycle_.addLifecycleListener(listener);
}
public LifecycleListener[] findLifecycleListeners()
{
return lifecycle_.findLifecycleListeners();
}
public void removeLifecycleListener(LifecycleListener listener)
{
lifecycle_.removeLifecycleListener(listener);
}
/**
* Start this Manager
*
* @throws org.apache.catalina.LifecycleException
*
*/
public void start() throws LifecycleException
{
startManager();
}
/**
* Stop this Manager
*
* @throws org.apache.catalina.LifecycleException
*
*/
public void stop() throws LifecycleException
{
// Block for any ongoing backgroundProcess, then disable
synchronized (backgroundProcessAllowed)
{
backgroundProcessAllowed.set(false);
}
resetStats();
stopManager();
}
// ------------------------------------------------------- JBossManagerMBean
/**
* {@inheritDoc}
*/
public long getActiveSessionCount()
{
return calcActiveSessions();
}
/**
* {@inheritDoc}
*/
public String getAlgorithm()
{
return SessionIDGenerator.SESSION_ID_HASH_ALGORITHM;
}
/**
* {@inheritDoc}
*/
public String getClassName()
{
return getClass().getName();
}
/**
* {@inheritDoc}
*/
public long getCreatedSessionCount()
{
return createdCounter_.get();
}
/**
* {@inheritDoc}
*/
public long getExpiredSessionCount()
{
return expiredCounter_.get();
}
/**
* {@inheritDoc}
*/
public long getLocalActiveSessionCount()
{
return localActiveCounter_.get();
}
/**
* {@inheritDoc}
*/
public int getMaxActiveAllowed()
{
return getMaxActive();
}
/**
* {@inheritDoc}
*/
public void setMaxActiveAllowed(int maxActive)
{
setMaxActive(maxActive);
}
/**
* {@inheritDoc}
*/
public int getMaxActiveSessions()
{
return getMaxActiveAllowed();
}
/**
* {@inheritDoc}
*/
public long getMaxActiveSessionCount()
{
return this.maxActiveCounter_.get();
}
/**
* {@inheritDoc}
*/
public long getMaxLocalActiveSessionCount()
{
return maxLocalActiveCounter_.get();
}
/**
* {@inheritDoc}
*/
public String getName()
{
return getClass().getSimpleName();
}
/**
* {@inheritDoc}
*/
public int getProcessExpiresFrequency()
{
return this.processExpiresFrequency;
}
/**
* {@inheritDoc}
*/
public void setProcessExpiresFrequency(int frequency)
{
this.processExpiresFrequency = frequency;
}
/**
* {@inheritDoc}
*/
public long getRejectedSessionCount()
{
return rejectedCounter_.get();
}
/**
* {@inheritDoc}
*/
public ReplicationStatistics getReplicationStatistics()
{
return stats_;
}
/**
* {@inheritDoc}
*/
public long getTimeSinceLastReset()
{
return (System.currentTimeMillis() - timeSinceLastReset_) / (1000L);
}
/**
* {@inheritDoc}
*/
public String reportReplicationStatistics()
{
StringBuffer tmp = new StringBuffer();
tmp.append("<table><tr>");
tmp.append("<th>sessionID</th>");
tmp.append("<th>replicationCount</th>");
tmp.append("<th>minPassivationTime</th>");
tmp.append("<th>maxPassivationTime</th>");
tmp.append("<th>totalPassivationTime</th>");
tmp.append("<th>minReplicationTime</th>");
tmp.append("<th>maxReplicationTime</th>");
tmp.append("<th>totalReplicationlTime</th>");
tmp.append("<th>loadCount</th>");
tmp.append("<th>minLoadTime</th>");
tmp.append("<th>maxLoadTime</th>");
tmp.append("<th>totalLoadTime</th>");
Map<String, ReplicationStatistics.TimeStatistic> copy = new HashMap<String, ReplicationStatistics.TimeStatistic>(stats_.getStats());
for (Map.Entry<String, ReplicationStatistics.TimeStatistic> entry : copy.entrySet())
{
ReplicationStatistics.TimeStatistic stat = (ReplicationStatistics.TimeStatistic) entry.getValue();
if (stat != null)
{
tmp.append("<tr><td>");
tmp.append(entry.getKey());
tmp.append("</td><td>");
tmp.append(stat.replicationCount);
tmp.append("</td><td>");
tmp.append(stat.minPassivationTime);
tmp.append("</td><td>");
tmp.append(stat.maxPassivationTime);
tmp.append("</td><td>");
tmp.append(stat.totalPassivationTime);
tmp.append("</td><td>");
tmp.append(stat.minReplicationTime);
tmp.append("</td><td>");
tmp.append(stat.maxReplicationTime);
tmp.append("</td><td>");
tmp.append(stat.totalReplicationlTime);
tmp.append("</td><td>");
tmp.append(stat.loadCount);
tmp.append("</td><td>");
tmp.append(stat.minLoadTime);
tmp.append("</td><td>");
tmp.append(stat.maxLoadTime);
tmp.append("</td><td>");
tmp.append(stat.totalLoadlTime);
tmp.append("</td></tr>");
}
}
tmp.append("</table>");
copy.clear();
return tmp.toString();
}
/**
* {@inheritDoc}
*/
public String reportReplicationStatisticsCSV()
{
StringBuffer tmp = createCSVHeader();
Map<String, ReplicationStatistics.TimeStatistic> copy = new HashMap<String, ReplicationStatistics.TimeStatistic>(stats_.getStats());
for (Map.Entry<String, ReplicationStatistics.TimeStatistic> entry : copy.entrySet())
{
ReplicationStatistics.TimeStatistic stat = (ReplicationStatistics.TimeStatistic) entry.getValue();
if (stat != null)
{
tmp.append("\n");
tmp.append(entry.getKey());
tmp.append(",");
tmp.append(stat.replicationCount);
tmp.append(",");
tmp.append(stat.minPassivationTime);
tmp.append(",");
tmp.append(stat.maxPassivationTime);
tmp.append(",");
tmp.append(stat.totalPassivationTime);
tmp.append(",");
tmp.append(stat.minReplicationTime);
tmp.append(",");
tmp.append(stat.maxReplicationTime);
tmp.append(",");
tmp.append(stat.totalReplicationlTime);
tmp.append(",");
tmp.append(stat.loadCount);
tmp.append(",");
tmp.append(stat.minLoadTime);
tmp.append(",");
tmp.append(stat.maxLoadTime);
tmp.append(",");
tmp.append(stat.totalLoadlTime);
}
}
copy.clear();
return tmp.toString();
}
/**
* {@inheritDoc}
*/
public String reportReplicationStatisticsCSV(String sessionId)
{
StringBuffer tmp = createCSVHeader();
Map<String, ReplicationStatistics.TimeStatistic> stats = stats_.getStats();
ReplicationStatistics.TimeStatistic stat =
(ReplicationStatistics.TimeStatistic) stats.get(sessionId);
if (stat != null)
{
tmp.append("\n");
tmp.append(sessionId);
tmp.append(",");
tmp.append(stat.replicationCount);
tmp.append(",");
tmp.append(stat.minPassivationTime);
tmp.append(",");
tmp.append(stat.maxPassivationTime);
tmp.append(",");
tmp.append(stat.totalPassivationTime);
tmp.append(",");
tmp.append(stat.minReplicationTime);
tmp.append(",");
tmp.append(stat.maxReplicationTime);
tmp.append(",");
tmp.append(stat.totalReplicationlTime);
tmp.append(",");
tmp.append(stat.loadCount);
tmp.append(",");
tmp.append(stat.minLoadTime);
tmp.append(",");
tmp.append(stat.maxLoadTime);
tmp.append(",");
tmp.append(stat.totalLoadlTime);
}
return tmp.toString();
}
/**
* {@inheritDoc}
*/
public void resetStats()
{
stats_.resetStats();
maxActiveCounter_.set(localActiveCounter_.get());
rejectedCounter_.set(0);
createdCounter_.set(0);
expiredCounter_.set(0);
processingTime_.set(0);
maxAliveTime.set(0);
averageAliveTime.set(0);
duplicates_.set(0);
timeSinceLastReset_ = System.currentTimeMillis();
}
// ------------------------------------------------------------------ Public
/**
* Gets the JMX <code>ObjectName</code> under
* which our <code>TreeCache</code> is registered.
*/
public ObjectName getObjectName()
{
return objectName_;
}
// ------------------------------------------------------------------ Protected
/**
* Go through all sessions and look if they have expired or need to be passivated.
*/
protected abstract void processExpirationPassivation();
/** Get the total number of active sessions */
protected abstract int getTotalActiveSessions();
/**
* Calculates the number of active sessions, and updates
* the max # of local active sessions and max # of sessions.
* <p>
* Call this method when a new session is added or when an
* accurate count of active sessions is needed.
* </p>
*
* @return the size of the sessions map + the size of the unloaded sessions
* map - the count of passivated sessions
*/
protected int calcActiveSessions()
{
localActiveCounter_.set(sessions_.size());
int active = localActiveCounter_.get();
int maxLocal = maxLocalActiveCounter_.get();
while (active > maxLocal)
{
if (!maxLocalActiveCounter_.compareAndSet(maxLocal, active))
{
maxLocal = maxLocalActiveCounter_.get();
}
}
int count = getTotalActiveSessions();
int max = maxActiveCounter_.get();
while (count > max)
{
if (!maxActiveCounter_.compareAndSet(max, count))
{
max = maxActiveCounter_.get();
// Something changed, so reset our count
count = getTotalActiveSessions();
}
}
return count;
}
/**
* Returns the given session if it is being actively managed by this manager.
* An actively managed session is on that was either created on this server,
* brought into local management by a call to
* {@link #findLocalSession(String)} or brought into local management by a
* call to {@link #findSessions()}.
*
* @param realId the session id, with any trailing jvmRoute removed.
*
* @see #getRealId(String)
*/
protected ClusteredSession<? extends OutgoingDistributableSessionData> findLocalSession(String realId)
{
return sessions_.get(realId);
}
/**
* Returns all the sessions that are being actively managed by this manager.
* This includes those that were created on this server, those that were
* brought into local management by a call to
* {@link #findLocalSession(String)} as well as all sessions brought into
* local management by a call to {@link #findSessions()}.
*/
protected ClusteredSession<? extends OutgoingDistributableSessionData>[] findLocalSessions()
{
Collection<ClusteredSession<? extends OutgoingDistributableSessionData>> coll = sessions_.values();
@SuppressWarnings("unchecked")
ClusteredSession<? extends OutgoingDistributableSessionData>[] sess = new ClusteredSession[coll.size()];
return coll.toArray(sess);
}
/**
* Get a new session-id from the distributed store
*
* @return new session-id
*/
protected String getNextId()
{
return sessionIDGenerator_.getSessionId();
}
/**
* Updates statistics to reflect that a session with a given "alive time"
* has been expired.
*
* @param sessionAliveTime number of ms from when the session was created
* to when it was expired.
*/
protected void sessionExpired(int sessionAliveTime)
{
int current = maxAliveTime.get();
while (sessionAliveTime > current)
{
if (maxAliveTime.compareAndSet(current, sessionAliveTime))
break;
else
current = maxAliveTime.get();
}
expiredCounter_.incrementAndGet();
int newAverage;
do
{
int expCount = expiredCounter_.get();
current = averageAliveTime.get();
newAverage = ((current * (expCount - 1)) + sessionAliveTime)/expCount;
}
while (averageAliveTime.compareAndSet(current, newAverage) == false);
}
/**
* Register this Manager with JMX.
*/
protected void registerManagerMBean()
{
try
{
MBeanServer server = getMBeanServer();
String domain;
if (container_ instanceof ContainerBase)
{
domain = ((ContainerBase) container_).getDomain();
}
else
{
domain = server.getDefaultDomain();
}
String hostName = ((Host) container_.getParent()).getName();
hostName = (hostName == null) ? "localhost" : hostName;
String path = ((Context) container_).getPath();
path="".equals(path) ? "/" : path;
ObjectName clusterName = new ObjectName(domain
+ ":type=Manager,host=" + hostName + ",path="
+ path);
if (server.isRegistered(clusterName))
{
log_.warn("MBean " + clusterName + " already registered");
return;
}
objectName_ = clusterName;
server.registerMBean(this, clusterName);
}
catch (Exception ex)
{
log_.error("Could not register " + getClass().getSimpleName() + " to MBeanServer", ex);
}
}
/**
* Unregister this Manager from the JMX server.
*/
protected void unregisterManagerMBean()
{
if (mserver_ != null && objectName_ != null)
{
try
{
mserver_.unregisterMBean(objectName_);
}
catch (Exception e)
{
log_.error("Could not unregister " + getClass().getSimpleName() + " from MBeanServer", e);
}
}
}
/**
* Get the current MBean Server.
*
* @return
* @throws Exception
*/
protected MBeanServer getMBeanServer() throws Exception
{
if (mserver_ == null)
{
mserver_ = Registry.getRegistry(null, null).getMBeanServer();
}
return mserver_;
}
/**
* Prepare for the beginning of active use of the public methods of this
* component. This method should be called after <code>configure()</code>,
* and before any of the public methods of the component are utilized.
*
* @throws IllegalStateException if this component has already been
* started_
* @throws org.apache.catalina.LifecycleException
* if this component detects a fatal error
* that prevents this component from being used
*/
protected void startManager() throws LifecycleException
{
log_.debug("Starting JBossManager");
// Validate and update our current component state
if (started_)
throw new LifecycleException("JBossManager alreadyStarted");
backgroundProcessAllowed.set(true);
lifecycle_.fireLifecycleEvent(START_EVENT, null);
started_ = true;
// register ClusterManagerMBean to the MBeanServer
registerManagerMBean();
}
/**
* Gracefully terminate the active use of the public methods of this
* component. This method should be the last one called on a given
* instance of this component.
*
* @throws IllegalStateException if this component has not been started_
* @throws org.apache.catalina.LifecycleException
* if this component detects a fatal error
* that needs to be reported
*/
protected void stopManager() throws LifecycleException
{
log_.debug("Stopping JBossManager");
// Validate and update our current component state
if (!started_)
throw new LifecycleException
("JBossManager notStarted");
lifecycle_.fireLifecycleEvent(STOP_EVENT, null);
started_ = false;
// unregister from the MBeanServer
unregisterManagerMBean();
}
// ----------------------------------------------------------------- Private
private StringBuffer createCSVHeader()
{
StringBuffer tmp = new StringBuffer();
tmp.append("sessionID,");
tmp.append("replicationCount,");
tmp.append("minPassivationTime,");
tmp.append("maxPassivationTime,");
tmp.append("totalPassivationTime,");
tmp.append("minReplicationTime,");
tmp.append("maxReplicationTime,");
tmp.append("totalReplicationlTime,");
tmp.append("loadCount,");
tmp.append("minLoadTime,");
tmp.append("maxLoadTime,");
tmp.append("totalLoadTime");
return tmp;
}
/**
* Retrieve the enclosing Engine for this Manager.
*
* @return an Engine object (or null).
*/
private Engine getEngine()
{
Engine e = null;
for (Container c = getContainer(); e == null && c != null; c = c.getParent())
{
if (c != null && c instanceof Engine)
{
e = (Engine) c;
}
}
return e;
}
}