Fields Summary |
---|
protected org.apache.juli.logging.Log | log |
protected DataInputStream | randomIS |
protected String | devRandomSource |
protected static final String | DEFAULT_ALGORITHMThe default message digest algorithm to use if we cannot use
the requested one. |
protected String | algorithmThe message digest algorithm to be used when generating session
identifiers. This must be an algorithm supported by the
java.security.MessageDigest class on your platform. |
protected org.apache.catalina.Container | containerThe Container with which this Manager is associated. |
protected MessageDigest | digestReturn the MessageDigest implementation to be used when
creating session identifiers. |
protected boolean | distributableThe distributable flag for Sessions created by this Manager. If this
flag is set to true , any user attributes added to a
session controlled by this Manager must be Serializable. |
protected String | entropyA String initialization parameter used to increase the entropy of
the initialization of our random number generator. |
private static final String | infoThe descriptive information string for this implementation. |
protected int | maxInactiveIntervalThe default maximum inactive interval for Sessions created by
this Manager. |
protected int | sessionIdLengthThe session id length of Sessions created by this Manager. |
protected static String | nameThe descriptive name of this Manager implementation (for logging). |
protected Random | randomA random number generator to use when generating session identifiers. |
protected String | randomClassThe Java class name of the random number generator class to be used
when generating session identifiers. |
protected int | sessionMaxAliveTimeThe longest time (in seconds) that an expired session had been alive. |
protected int | sessionAverageAliveTimeAverage time (in seconds) that expired sessions had been alive. |
protected int | expiredSessionsNumber of sessions that have expired. |
protected Map | sessionsThe set of currently active Sessions for this Manager, keyed by
session identifier. |
protected int | sessionCounter |
protected int | maxActive |
protected int | duplicates |
protected boolean | initialized |
protected long | processingTimeProcessing time during session expiration. |
private int | countIteration count for background processing. |
protected int | processExpiresFrequencyFrequency of the session expiration, and related manager operations.
Manager operations will be done once for the specified amount of
backgrondProcess calls (ie, the lower the amount, the most often the
checks will occur). |
protected static org.apache.catalina.util.StringManager | smThe string manager for this package. |
protected PropertyChangeSupport | supportThe property change support for this component. |
protected String | domain |
protected ObjectName | oname |
protected MBeanServer | mserver |
Methods Summary |
---|
public void | add(org.apache.catalina.Session session)Add this Session to the set of active Sessions for this Manager.
sessions.put(session.getIdInternal(), session);
int size = sessions.size();
if( size > maxActive ) {
maxActive = size;
}
|
public void | addPropertyChangeListener(java.beans.PropertyChangeListener listener)Add a property change listener to this component.
support.addPropertyChangeListener(listener);
|
public void | backgroundProcess()Implements the Manager interface, direct call to processExpires
count = (count + 1) % processExpiresFrequency;
if (count == 0)
processExpires();
|
public org.apache.catalina.Session | createEmptySession()Get a session from the recycled ones or create a new empty one.
The PersistentManager manager does not need to create session data
because it reads it from the Store.
return (getNewSession());
|
public org.apache.catalina.Session | createSession()Construct and return a new session object, based on the default
settings specified by this Manager's properties. The session
id will be assigned by this method, and available via the getId()
method of the returned session. If a new session cannot be created
for any reason, return null .
return createSession(null);
|
public org.apache.catalina.Session | createSession(java.lang.String sessionId)Construct and return a new session object, based on the default
settings specified by this Manager's properties. The session
id specified will be used as the session id.
If a new session cannot be created for any reason, return
null .
// Recycle or create a Session instance
Session session = createEmptySession();
// Initialize the properties of the new session and return it
session.setNew(true);
session.setValid(true);
session.setCreationTime(System.currentTimeMillis());
session.setMaxInactiveInterval(this.maxInactiveInterval);
if (sessionId == null) {
sessionId = generateSessionId();
// FIXME WHy we need no duplication check?
/*
synchronized (sessions) {
while (sessions.get(sessionId) != null) { // Guarantee
// uniqueness
duplicates++;
sessionId = generateSessionId();
}
}
*/
// FIXME: Code to be used in case route replacement is needed
/*
} else {
String jvmRoute = getJvmRoute();
if (getJvmRoute() != null) {
String requestJvmRoute = null;
int index = sessionId.indexOf(".");
if (index > 0) {
requestJvmRoute = sessionId
.substring(index + 1, sessionId.length());
}
if (requestJvmRoute != null && !requestJvmRoute.equals(jvmRoute)) {
sessionId = sessionId.substring(0, index) + "." + jvmRoute;
}
}
*/
}
session.setId(sessionId);
sessionCounter++;
return (session);
|
public void | destroy()
if( oname != null )
Registry.getRegistry(null, null).unregisterComponent(oname);
initialized=false;
oname = null;
|
public void | expireSession(java.lang.String sessionId)
Session s=(Session)sessions.get(sessionId);
if( s==null ) {
if(log.isInfoEnabled())
log.info("Session not found " + sessionId);
return;
}
s.expire();
|
public org.apache.catalina.Session | findSession(java.lang.String id)Return the active Session, associated with this Manager, with the
specified session id (if any); otherwise return null .
if (id == null)
return (null);
return (Session) sessions.get(id);
|
public org.apache.catalina.Session[] | findSessions()Return the set of active Sessions associated with this Manager.
If this Manager has no active Sessions, a zero-length array is returned.
Session results[] = null;
synchronized (sessions) {
results = new Session[sessions.size()];
results = (Session[]) sessions.values().toArray(results);
}
return (results);
|
protected synchronized java.lang.String | generateSessionId()Generate and return a new session identifier.
byte random[] = new byte[16];
String jvmRoute = getJvmRoute();
String result = null;
// Render the result as a String of hexadecimal digits
StringBuffer buffer = new StringBuffer();
do {
int resultLenBytes = 0;
if (result != null) {
buffer = new StringBuffer();
duplicates++;
}
while (resultLenBytes < this.sessionIdLength) {
getRandomBytes(random);
random = getDigest().digest(random);
for (int j = 0;
j < random.length && resultLenBytes < this.sessionIdLength;
j++) {
byte b1 = (byte) ((random[j] & 0xf0) >> 4);
byte b2 = (byte) (random[j] & 0x0f);
if (b1 < 10)
buffer.append((char) ('0" + b1));
else
buffer.append((char) ('A" + (b1 - 10)));
if (b2 < 10)
buffer.append((char) ('0" + b2));
else
buffer.append((char) ('A" + (b2 - 10)));
resultLenBytes++;
}
}
if (jvmRoute != null) {
buffer.append('.").append(jvmRoute);
}
result = buffer.toString();
} while (sessions.containsKey(result));
return (result);
|
public int | getActiveSessions()Returns the number of active sessions
return sessions.size();
|
public java.lang.String | getAlgorithm()Return the message digest algorithm for this Manager.
return (this.algorithm);
|
public java.lang.String | getClassName()Returns the name of the implementation class.
return this.getClass().getName();
|
public org.apache.catalina.Container | getContainer()Return the Container with which this Manager is associated.
return (this.container);
|
public synchronized java.security.MessageDigest | getDigest()Return the MessageDigest object to be used for calculating
session identifiers. If none has been created yet, initialize
one the first time this method is called.
if (this.digest == null) {
long t1=System.currentTimeMillis();
if (log.isDebugEnabled())
log.debug(sm.getString("managerBase.getting", algorithm));
try {
this.digest = MessageDigest.getInstance(algorithm);
} catch (NoSuchAlgorithmException e) {
log.error(sm.getString("managerBase.digest", algorithm), e);
try {
this.digest = MessageDigest.getInstance(DEFAULT_ALGORITHM);
} catch (NoSuchAlgorithmException f) {
log.error(sm.getString("managerBase.digest",
DEFAULT_ALGORITHM), e);
this.digest = null;
}
}
if (log.isDebugEnabled())
log.debug(sm.getString("managerBase.gotten"));
long t2=System.currentTimeMillis();
if( log.isDebugEnabled() )
log.debug("getDigest() " + (t2-t1));
}
return (this.digest);
|
public boolean | getDistributable()Return the distributable flag for the sessions supported by
this Manager.
return (this.distributable);
|
public java.lang.String | getDomain()
return domain;
|
public int | getDuplicates()Number of duplicated session IDs generated by the random source.
Anything bigger than 0 means problems.
return duplicates;
|
public org.apache.catalina.Engine | getEngine()Retrieve the enclosing Engine for this Manager.
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;
|
public java.lang.String | getEntropy()Return the entropy increaser value, or compute a semi-useful value
if this String has not yet been set.
// Calculate a semi-useful value if this has not been set
if (this.entropy == null) {
// Use APR to get a crypto secure entropy value
byte[] result = new byte[32];
boolean apr = false;
try {
String methodName = "random";
Class paramTypes[] = new Class[2];
paramTypes[0] = result.getClass();
paramTypes[1] = int.class;
Object paramValues[] = new Object[2];
paramValues[0] = result;
paramValues[1] = new Integer(32);
Method method = Class.forName("org.apache.tomcat.jni.OS")
.getMethod(methodName, paramTypes);
method.invoke(null, paramValues);
apr = true;
} catch (Throwable t) {
// Ignore
}
if (apr) {
setEntropy(new String(result));
} else {
setEntropy(this.toString());
}
}
return (this.entropy);
|
public int | getExpiredSessions()Gets the number of sessions that have expired.
return expiredSessions;
|
public java.lang.String | getInfo()Return descriptive information about this Manager implementation and
the corresponding version number, in the format
<description>/<version> .
return (info);
|
public java.lang.String | getJvmRoute()Retrieve the JvmRoute for the enclosing Engine.
Engine e = getEngine();
return e == null ? null : e.getJvmRoute();
|
public java.lang.String | getLastAccessedTime(java.lang.String sessionId)
Session s=(Session)sessions.get(sessionId);
if( s==null ) {
log.info("Session not found " + sessionId);
return "";
}
return new Date(s.getLastAccessedTime()).toString();
|
public int | getMaxActive()Max number of concurrent active sessions
return maxActive;
|
public int | getMaxInactiveInterval()Return the default maximum inactive interval (in seconds)
for Sessions created by this Manager.
return (this.maxInactiveInterval);
|
public java.lang.String | getName()Return the descriptive short name of this Manager implementation.
return (name);
|
protected StandardSession | getNewSession()Get new session class to be used in the doLoad() method.
return new StandardSession(this);
|
public javax.management.ObjectName | getObjectName()
return oname;
|
public int | getProcessExpiresFrequency()Return the frequency of manager checks.
return (this.processExpiresFrequency);
|
public long | getProcessingTime()
return processingTime;
|
public java.util.Random | getRandom()Return the random number generator instance we should use for
generating session identifiers. If there is no such generator
currently defined, construct and seed a new one.
if (this.random == null) {
// Calculate the new random number generator seed
long seed = System.currentTimeMillis();
long t1 = seed;
char entropy[] = getEntropy().toCharArray();
for (int i = 0; i < entropy.length; i++) {
long update = ((byte) entropy[i]) << ((i % 8) * 8);
seed ^= update;
}
try {
// Construct and seed a new random number generator
Class clazz = Class.forName(randomClass);
this.random = (Random) clazz.newInstance();
this.random.setSeed(seed);
} catch (Exception e) {
// Fall back to the simple case
log.error(sm.getString("managerBase.random", randomClass),
e);
this.random = new java.util.Random();
this.random.setSeed(seed);
}
if(log.isDebugEnabled()) {
long t2=System.currentTimeMillis();
if( (t2-t1) > 100 )
log.debug(sm.getString("managerBase.seeding", randomClass) + " " + (t2-t1));
}
}
return (this.random);
|
protected void | getRandomBytes(byte[] bytes)
// Generate a byte array containing a session identifier
if (devRandomSource != null && randomIS == null) {
setRandomFile(devRandomSource);
}
if (randomIS != null) {
try {
int len = randomIS.read(bytes);
if (len == bytes.length) {
return;
}
if(log.isDebugEnabled())
log.debug("Got " + len + " " + bytes.length );
} catch (Exception ex) {
// Ignore
}
devRandomSource = null;
try {
randomIS.close();
} catch (Exception e) {
log.warn("Failed to close randomIS.");
}
randomIS = null;
}
getRandom().nextBytes(bytes);
|
public java.lang.String | getRandomClass()Return the random number generator class name.
return (this.randomClass);
|
public java.lang.String | getRandomFile()
return devRandomSource;
|
public java.util.HashMap | getSession(java.lang.String sessionId)Returns information about the session with the given session id.
The session information is organized as a HashMap, mapping
session attribute names to the String representation of their values.
Session s = (Session) sessions.get(sessionId);
if (s == null) {
if (log.isInfoEnabled()) {
log.info("Session not found " + sessionId);
}
return null;
}
Enumeration ee = s.getSession().getAttributeNames();
if (ee == null || !ee.hasMoreElements()) {
return null;
}
HashMap map = new HashMap();
while (ee.hasMoreElements()) {
String attrName = (String) ee.nextElement();
map.put(attrName, getSessionAttribute(sessionId, attrName));
}
return map;
|
public java.lang.String | getSessionAttribute(java.lang.String sessionId, java.lang.String key)For debugging: get a session attribute
Session s = (Session) sessions.get(sessionId);
if( s==null ) {
if(log.isInfoEnabled())
log.info("Session not found " + sessionId);
return null;
}
Object o=s.getSession().getAttribute(key);
if( o==null ) return null;
return o.toString();
|
public int | getSessionAverageAliveTime()Gets the average time (in seconds) that expired sessions had been
alive.
return sessionAverageAliveTime;
|
public int | getSessionCounter()Total sessions created by this manager.
return sessionCounter;
|
public int | getSessionIdLength()Gets the session id length (in bytes) of Sessions created by
this Manager.
return (this.sessionIdLength);
|
public int | getSessionMaxAliveTime()Gets the longest time (in seconds) that an expired session had been
alive.
return sessionMaxAliveTime;
|
public void | init()
if( initialized ) return;
initialized=true;
log = LogFactory.getLog(ManagerBase.class);
if( oname==null ) {
try {
StandardContext ctx=(StandardContext)this.getContainer();
Engine eng=(Engine)ctx.getParent().getParent();
domain=ctx.getEngineName();
distributable = ctx.getDistributable();
StandardHost hst=(StandardHost)ctx.getParent();
String path = ctx.getPath();
if (path.equals("")) {
path = "/";
}
oname=new ObjectName(domain + ":type=Manager,path="
+ path + ",host=" + hst.getName());
Registry.getRegistry(null, null).registerComponent(this, oname, null );
} catch (Exception e) {
log.error("Error registering ",e);
}
}
// Initialize random number generation
getRandomBytes(new byte[16]);
if(log.isDebugEnabled())
log.debug("Registering " + oname );
|
public java.lang.String | listSessionIds()For debugging: return a list of all session ids currently active
StringBuffer sb=new StringBuffer();
Iterator keys = sessions.keySet().iterator();
while (keys.hasNext()) {
sb.append(keys.next()).append(" ");
}
return sb.toString();
|
public void | postDeregister()
|
public void | postRegister(java.lang.Boolean registrationDone)
|
public void | preDeregister()
|
public javax.management.ObjectName | preRegister(javax.management.MBeanServer server, javax.management.ObjectName name)
oname=name;
mserver=server;
domain=name.getDomain();
return name;
|
public void | processExpires()Invalidate all sessions that have expired.
long timeNow = System.currentTimeMillis();
Session sessions[] = findSessions();
int expireHere = 0 ;
if(log.isDebugEnabled())
log.debug("Start expire sessions " + getName() + " at " + timeNow + " sessioncount " + sessions.length);
for (int i = 0; i < sessions.length; i++) {
if (!sessions[i].isValid()) {
expireHere++;
}
}
long timeEnd = System.currentTimeMillis();
if(log.isDebugEnabled())
log.debug("End expire sessions " + getName() + " processingTime " + (timeEnd - timeNow) + " expired sessions: " + expireHere);
processingTime += ( timeEnd - timeNow );
|
public void | remove(org.apache.catalina.Session session)Remove this Session from the active Sessions for this Manager.
sessions.remove(session.getIdInternal());
|
public void | removePropertyChangeListener(java.beans.PropertyChangeListener listener)Remove a property change listener from this component.
support.removePropertyChangeListener(listener);
|
public void | setAlgorithm(java.lang.String algorithm)Set the message digest algorithm for this Manager.
String oldAlgorithm = this.algorithm;
this.algorithm = algorithm;
support.firePropertyChange("algorithm", oldAlgorithm, this.algorithm);
|
public void | setContainer(org.apache.catalina.Container container)Set the Container with which this Manager is associated.
Container oldContainer = this.container;
this.container = container;
support.firePropertyChange("container", oldContainer, this.container);
|
public void | setDistributable(boolean distributable)Set the distributable flag for the sessions supported by this
Manager. If this flag is set, all user data objects added to
sessions associated with this manager must implement Serializable.
boolean oldDistributable = this.distributable;
this.distributable = distributable;
support.firePropertyChange("distributable",
new Boolean(oldDistributable),
new Boolean(this.distributable));
|
public void | setDuplicates(int duplicates)
this.duplicates = duplicates;
|
public void | setEntropy(java.lang.String entropy)Set the entropy increaser value.
String oldEntropy = entropy;
this.entropy = entropy;
support.firePropertyChange("entropy", oldEntropy, this.entropy);
|
public void | setExpiredSessions(int expiredSessions)Sets the number of sessions that have expired.
this.expiredSessions = expiredSessions;
|
public void | setMaxActive(int maxActive)
this.maxActive = maxActive;
|
public void | setMaxInactiveInterval(int interval)Set the default maximum inactive interval (in seconds)
for Sessions created by this Manager.
int oldMaxInactiveInterval = this.maxInactiveInterval;
this.maxInactiveInterval = interval;
support.firePropertyChange("maxInactiveInterval",
new Integer(oldMaxInactiveInterval),
new Integer(this.maxInactiveInterval));
|
public void | setProcessExpiresFrequency(int processExpiresFrequency)Set the manager checks frequency.
if (processExpiresFrequency <= 0) {
return;
}
int oldProcessExpiresFrequency = this.processExpiresFrequency;
this.processExpiresFrequency = processExpiresFrequency;
support.firePropertyChange("processExpiresFrequency",
new Integer(oldProcessExpiresFrequency),
new Integer(this.processExpiresFrequency));
|
public void | setProcessingTime(long processingTime)
this.processingTime = processingTime;
|
public void | setRandomClass(java.lang.String randomClass)Set the random number generator class name.
String oldRandomClass = this.randomClass;
this.randomClass = randomClass;
support.firePropertyChange("randomClass", oldRandomClass,
this.randomClass);
|
public void | setRandomFile(java.lang.String s)Use /dev/random-type special device. This is new code, but may reduce
the big delay in generating the random.
You must specify a path to a random generator file. Use /dev/urandom
for linux ( or similar ) systems. Use /dev/random for maximum security
( it may block if not enough "random" exist ). You can also use
a pipe that generates random.
The code will check if the file exists, and default to java Random
if not found. There is a significant performance difference, very
visible on the first call to getSession ( like in the first JSP )
- so use it if available.
// as a hack, you can use a static file - and genarate the same
// session ids ( good for strange debugging )
if (Globals.IS_SECURITY_ENABLED){
randomIS = (DataInputStream)AccessController.doPrivileged(new PrivilegedSetRandomFile());
} else {
try{
devRandomSource=s;
File f=new File( devRandomSource );
if( ! f.exists() ) return;
randomIS= new DataInputStream( new FileInputStream(f));
randomIS.readLong();
if( log.isDebugEnabled() )
log.debug( "Opening " + devRandomSource );
} catch( IOException ex ) {
try {
randomIS.close();
} catch (Exception e) {
log.warn("Failed to close randomIS.");
}
randomIS=null;
}
}
|
public void | setSessionAverageAliveTime(int sessionAverageAliveTime)Sets the average time (in seconds) that expired sessions had been
alive.
this.sessionAverageAliveTime = sessionAverageAliveTime;
|
public void | setSessionCounter(int sessionCounter)
this.sessionCounter = sessionCounter;
|
public void | setSessionIdLength(int idLength)Sets the session id length (in bytes) for Sessions created by this
Manager.
int oldSessionIdLength = this.sessionIdLength;
this.sessionIdLength = idLength;
support.firePropertyChange("sessionIdLength",
new Integer(oldSessionIdLength),
new Integer(this.sessionIdLength));
|
public void | setSessionMaxAliveTime(int sessionMaxAliveTime)Sets the longest time (in seconds) that an expired session had been
alive.
this.sessionMaxAliveTime = sessionMaxAliveTime;
|