Does not compile, draft of changes.
This commit is contained in:
parent
c45cd8ce03
commit
3e3bfb9d6b
|
@ -27,17 +27,17 @@ package org.eclipse.jetty.server.session.x;
|
|||
public abstract class AbstractSessionDataStore implements SessionDataStore
|
||||
{
|
||||
|
||||
public abstract void doStore() throws Exception;
|
||||
public abstract void doStore(SessionKey key, SessionData data) throws Exception;
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.session.x.SessionDataStore#store(java.lang.String, org.eclipse.jetty.server.session.x.SessionData)
|
||||
*/
|
||||
@Override
|
||||
public void store(String id, SessionData data) throws Exception
|
||||
public void store(SessionKey key, SessionData data) throws Exception
|
||||
{
|
||||
try
|
||||
{
|
||||
doStore();
|
||||
doStore(key, data);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
|
@ -32,15 +32,13 @@ public abstract class AbstractSessionStore implements SessionStore
|
|||
|
||||
public abstract Session newSession (SessionData data);
|
||||
|
||||
public abstract Session doGet(String id);
|
||||
public abstract Session doGet(SessionKey key);
|
||||
|
||||
public abstract Session doPutIfAbsent (String id, Session session);
|
||||
public abstract void doPut (SessionKey key, Session session);
|
||||
|
||||
public abstract void doPut (String id, Session session);
|
||||
public abstract boolean doExists (SessionKey key);
|
||||
|
||||
public abstract boolean doExists (String id);
|
||||
|
||||
public abstract void doDelete (String id);
|
||||
public abstract void doDelete (SessionKey key);
|
||||
|
||||
|
||||
public AbstractSessionStore ()
|
||||
|
@ -69,17 +67,17 @@ public abstract class AbstractSessionStore implements SessionStore
|
|||
* @see org.eclipse.jetty.server.session.x.SessionStore#get(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public Session get(String id) throws Exception
|
||||
public Session get(SessionKey key) throws Exception
|
||||
{
|
||||
//look locally
|
||||
Session session = doGet(id);
|
||||
Session session = doGet(key);
|
||||
|
||||
//not in session store, load the data for the session if possible
|
||||
if (session == null && _sessionDataStore != null)
|
||||
{
|
||||
SessionData data = _sessionDataStore.load(id);
|
||||
SessionData data = _sessionDataStore.load(key);
|
||||
session = newSession(data);
|
||||
doPut(id, session);
|
||||
doPut(key, session);
|
||||
}
|
||||
return session;
|
||||
}
|
||||
|
@ -92,16 +90,16 @@ public abstract class AbstractSessionStore implements SessionStore
|
|||
* @see org.eclipse.jetty.server.session.x.SessionStore#put(java.lang.String, org.eclipse.jetty.server.session.x.Session)
|
||||
*/
|
||||
@Override
|
||||
public void put(String id, Session session) throws Exception
|
||||
public void put(SessionKey key, Session session) throws Exception
|
||||
{
|
||||
//if the session is already in our cache, then we want to write through any changes
|
||||
if (doExists(id))
|
||||
if (doExists(key))
|
||||
{
|
||||
//if the session data has changed, or the cache is considered stale, write it to any backing store
|
||||
if ((session.getSessionData().isDirty() || isStale(session)) && _sessionDataStore != null)
|
||||
{
|
||||
session.willPassivate();
|
||||
_sessionDataStore.store(id, session.getSessionData());
|
||||
_sessionDataStore.store(key, session.getSessionData());
|
||||
session.didActivate();
|
||||
}
|
||||
}
|
||||
|
@ -111,10 +109,10 @@ public abstract class AbstractSessionStore implements SessionStore
|
|||
if (_sessionDataStore != null)
|
||||
{
|
||||
session.willPassivate();
|
||||
_sessionDataStore.store(id, session.getSessionData());
|
||||
_sessionDataStore.store(SessionKey.getKey(session.getSessionData()), session.getSessionData());
|
||||
session.didActivate();
|
||||
}
|
||||
doPut(id,session);
|
||||
doPut(key,session);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -127,21 +125,11 @@ public abstract class AbstractSessionStore implements SessionStore
|
|||
* @see org.eclipse.jetty.server.session.x.SessionStore#exists(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean exists(String id)
|
||||
public boolean exists(SessionKey key)
|
||||
{
|
||||
return doExists(id);
|
||||
return doExists(key);
|
||||
}
|
||||
|
||||
/**
|
||||
*TODO does this mean absent in the Session cache or the backing store???
|
||||
*
|
||||
* @see org.eclipse.jetty.server.session.x.SessionStore#putIfAbsent(java.lang.String, org.eclipse.jetty.server.session.x.Session)
|
||||
*/
|
||||
@Override
|
||||
public Session putIfAbsent(String id, Session session) throws Exception
|
||||
{
|
||||
return doPutIfAbsent(id, session);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a session object from this store and from any backing store.
|
||||
|
@ -149,13 +137,13 @@ public abstract class AbstractSessionStore implements SessionStore
|
|||
* @see org.eclipse.jetty.server.session.x.SessionStore#delete(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean delete(String id) throws Exception
|
||||
public boolean delete(SessionKey key) throws Exception
|
||||
{
|
||||
boolean deleted = true;
|
||||
//TODO synchronization???
|
||||
if (_sessionDataStore != null)
|
||||
deleted = _sessionDataStore.delete(id);
|
||||
doDelete(id);
|
||||
deleted = _sessionDataStore.delete(key);
|
||||
doDelete(key);
|
||||
return deleted;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,26 @@
|
|||
|
||||
package org.eclipse.jetty.server.session.x;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.sql.Blob;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.Driver;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.naming.InitialContext;
|
||||
import javax.naming.NameNotFoundException;
|
||||
import javax.naming.NamingException;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
/**
|
||||
* JDBCSessionDataStore
|
||||
|
@ -28,9 +47,653 @@ package org.eclipse.jetty.server.session.x;
|
|||
*/
|
||||
public class JDBCSessionDataStore extends AbstractSessionDataStore
|
||||
{
|
||||
private final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session");
|
||||
|
||||
|
||||
|
||||
protected int _deleteBlockSize = 10; //number of ids to include in where 'in' clause for finding long expired sessions
|
||||
protected boolean _initialized = false;
|
||||
|
||||
|
||||
|
||||
private DatabaseAdaptor _dbAdaptor;
|
||||
|
||||
|
||||
|
||||
private SessionTableSchema _sessionTableSchema;
|
||||
|
||||
/**
|
||||
* DatabaseAdaptor
|
||||
*
|
||||
* Handles differences between databases.
|
||||
*
|
||||
* Postgres uses the getBytes and setBinaryStream methods to access
|
||||
* a "bytea" datatype, which can be up to 1Gb of binary data. MySQL
|
||||
* is happy to use the "blob" type and getBlob() methods instead.
|
||||
*
|
||||
* TODO if the differences become more major it would be worthwhile
|
||||
* refactoring this class.
|
||||
*/
|
||||
public static class DatabaseAdaptor
|
||||
{
|
||||
String _dbName;
|
||||
boolean _isLower;
|
||||
boolean _isUpper;
|
||||
|
||||
protected String _blobType; //if not set, is deduced from the type of the database at runtime
|
||||
protected String _longType; //if not set, is deduced from the type of the database at runtime
|
||||
private String _driverClassName;
|
||||
private String _connectionUrl;
|
||||
private Driver _driver;
|
||||
private DataSource _datasource;
|
||||
private String _jndiName;
|
||||
|
||||
|
||||
public DatabaseAdaptor ()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public void adaptTo(DatabaseMetaData dbMeta)
|
||||
throws SQLException
|
||||
{
|
||||
_dbName = dbMeta.getDatabaseProductName().toLowerCase(Locale.ENGLISH);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug ("Using database {}",_dbName);
|
||||
_isLower = dbMeta.storesLowerCaseIdentifiers();
|
||||
_isUpper = dbMeta.storesUpperCaseIdentifiers();
|
||||
}
|
||||
|
||||
|
||||
public void setBlobType(String blobType)
|
||||
{
|
||||
_blobType = blobType;
|
||||
}
|
||||
|
||||
public String getBlobType ()
|
||||
{
|
||||
if (_blobType != null)
|
||||
return _blobType;
|
||||
|
||||
if (_dbName.startsWith("postgres"))
|
||||
return "bytea";
|
||||
|
||||
return "blob";
|
||||
}
|
||||
|
||||
|
||||
public void setLongType(String longType)
|
||||
{
|
||||
_longType = longType;
|
||||
}
|
||||
|
||||
|
||||
public String getLongType ()
|
||||
{
|
||||
if (_longType != null)
|
||||
return _longType;
|
||||
|
||||
if (_dbName == null)
|
||||
throw new IllegalStateException ("DbAdaptor missing metadata");
|
||||
|
||||
if (_dbName.startsWith("oracle"))
|
||||
return "number(20)";
|
||||
|
||||
return "bigint";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a camel case identifier into either upper or lower
|
||||
* depending on the way the db stores identifiers.
|
||||
*
|
||||
* @param identifier the raw identifier
|
||||
* @return the converted identifier
|
||||
*/
|
||||
public String convertIdentifier (String identifier)
|
||||
{
|
||||
if (_dbName == null)
|
||||
throw new IllegalStateException ("DbAdaptor missing metadata");
|
||||
|
||||
if (_isLower)
|
||||
return identifier.toLowerCase(Locale.ENGLISH);
|
||||
if (_isUpper)
|
||||
return identifier.toUpperCase(Locale.ENGLISH);
|
||||
|
||||
return identifier;
|
||||
}
|
||||
|
||||
|
||||
public String getDBName ()
|
||||
{
|
||||
return _dbName;
|
||||
}
|
||||
|
||||
|
||||
public InputStream getBlobInputStream (ResultSet result, String columnName)
|
||||
throws SQLException
|
||||
{
|
||||
if (_dbName == null)
|
||||
throw new IllegalStateException ("DbAdaptor missing metadata");
|
||||
|
||||
if (_dbName.startsWith("postgres"))
|
||||
{
|
||||
byte[] bytes = result.getBytes(columnName);
|
||||
return new ByteArrayInputStream(bytes);
|
||||
}
|
||||
|
||||
Blob blob = result.getBlob(columnName);
|
||||
return blob.getBinaryStream();
|
||||
}
|
||||
|
||||
|
||||
public boolean isEmptyStringNull ()
|
||||
{
|
||||
if (_dbName == null)
|
||||
throw new IllegalStateException ("DbAdaptor missing metadata");
|
||||
|
||||
return (_dbName.startsWith("oracle"));
|
||||
}
|
||||
|
||||
/**
|
||||
* rowId is a reserved word for Oracle, so change the name of this column
|
||||
* @return true if db in use is oracle
|
||||
*/
|
||||
public boolean isRowIdReserved ()
|
||||
{
|
||||
if (_dbName == null)
|
||||
throw new IllegalStateException ("DbAdaptor missing metadata");
|
||||
|
||||
return (_dbName != null && _dbName.startsWith("oracle"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure jdbc connection information via a jdbc Driver
|
||||
*
|
||||
* @param driverClassName the driver classname
|
||||
* @param connectionUrl the driver connection url
|
||||
*/
|
||||
public void setDriverInfo (String driverClassName, String connectionUrl)
|
||||
{
|
||||
_driverClassName=driverClassName;
|
||||
_connectionUrl=connectionUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure jdbc connection information via a jdbc Driver
|
||||
*
|
||||
* @param driverClass the driver class
|
||||
* @param connectionUrl the driver connection url
|
||||
*/
|
||||
public void setDriverInfo (Driver driverClass, String connectionUrl)
|
||||
{
|
||||
_driver=driverClass;
|
||||
_connectionUrl=connectionUrl;
|
||||
}
|
||||
|
||||
|
||||
public void setDatasource (DataSource ds)
|
||||
{
|
||||
_datasource = ds;
|
||||
}
|
||||
|
||||
public void setDatasourceName (String jndi)
|
||||
{
|
||||
_jndiName=jndi;
|
||||
}
|
||||
|
||||
public void initializeDatabase ()
|
||||
throws Exception
|
||||
{
|
||||
if (_datasource != null)
|
||||
return; //already set up
|
||||
|
||||
if (_jndiName!=null)
|
||||
{
|
||||
InitialContext ic = new InitialContext();
|
||||
_datasource = (DataSource)ic.lookup(_jndiName);
|
||||
}
|
||||
else if ( _driver != null && _connectionUrl != null )
|
||||
{
|
||||
DriverManager.registerDriver(_driver);
|
||||
}
|
||||
else if (_driverClassName != null && _connectionUrl != null)
|
||||
{
|
||||
Class.forName(_driverClassName);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
InitialContext ic = new InitialContext();
|
||||
_datasource = (DataSource)ic.lookup("jdbc/sessions"); //last ditch effort
|
||||
}
|
||||
catch (NamingException e)
|
||||
{
|
||||
throw new IllegalStateException("No database configured for sessions");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a connection from the driver or datasource.
|
||||
*
|
||||
* @return the connection for the datasource
|
||||
* @throws SQLException if unable to get the connection
|
||||
*/
|
||||
protected Connection getConnection ()
|
||||
throws SQLException
|
||||
{
|
||||
if (_datasource != null)
|
||||
return _datasource.getConnection();
|
||||
else
|
||||
return DriverManager.getConnection(_connectionUrl);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* SessionTableSchema
|
||||
*
|
||||
*/
|
||||
public static class SessionTableSchema
|
||||
{
|
||||
public final static int MAX_INTERVAL_NOT_SET = -999;
|
||||
|
||||
protected DatabaseAdaptor _dbAdaptor;
|
||||
protected String _tableName = "JettySessions";
|
||||
protected String _rowIdColumn = "rowId";
|
||||
protected String _idColumn = "sessionId";
|
||||
protected String _contextPathColumn = "contextPath";
|
||||
protected String _virtualHostColumn = "virtualHost";
|
||||
protected String _lastNodeColumn = "lastNode";
|
||||
protected String _accessTimeColumn = "accessTime";
|
||||
protected String _lastAccessTimeColumn = "lastAccessTime";
|
||||
protected String _createTimeColumn = "createTime";
|
||||
protected String _cookieTimeColumn = "cookieTime";
|
||||
protected String _lastSavedTimeColumn = "lastSavedTime";
|
||||
protected String _expiryTimeColumn = "expiryTime";
|
||||
protected String _maxIntervalColumn = "maxInterval";
|
||||
protected String _mapColumn = "map";
|
||||
|
||||
private String _insertSession;
|
||||
|
||||
private String _deleteSession;
|
||||
|
||||
private String _updateSession;
|
||||
|
||||
private String _updateSessionNode;
|
||||
|
||||
private String _updateSessionAccessTime;
|
||||
|
||||
private String _selectBoundedExpiredSessions;
|
||||
|
||||
private String _selectExpiredSessions;
|
||||
|
||||
|
||||
protected void setDatabaseAdaptor(DatabaseAdaptor dbadaptor)
|
||||
{
|
||||
_dbAdaptor = dbadaptor;
|
||||
}
|
||||
|
||||
|
||||
public String getTableName()
|
||||
{
|
||||
return _tableName;
|
||||
}
|
||||
public void setTableName(String tableName)
|
||||
{
|
||||
checkNotNull(tableName);
|
||||
_tableName = tableName;
|
||||
}
|
||||
public String getRowIdColumn()
|
||||
{
|
||||
if ("rowId".equals(_rowIdColumn) && _dbAdaptor.isRowIdReserved())
|
||||
_rowIdColumn = "srowId";
|
||||
return _rowIdColumn;
|
||||
}
|
||||
public void setRowIdColumn(String rowIdColumn)
|
||||
{
|
||||
checkNotNull(rowIdColumn);
|
||||
if (_dbAdaptor == null)
|
||||
throw new IllegalStateException ("DbAdaptor is null");
|
||||
|
||||
if (_dbAdaptor.isRowIdReserved() && "rowId".equals(rowIdColumn))
|
||||
throw new IllegalArgumentException("rowId is reserved word for Oracle");
|
||||
|
||||
_rowIdColumn = rowIdColumn;
|
||||
}
|
||||
public String getIdColumn()
|
||||
{
|
||||
return _idColumn;
|
||||
}
|
||||
public void setIdColumn(String idColumn)
|
||||
{
|
||||
checkNotNull(idColumn);
|
||||
_idColumn = idColumn;
|
||||
}
|
||||
public String getContextPathColumn()
|
||||
{
|
||||
return _contextPathColumn;
|
||||
}
|
||||
public void setContextPathColumn(String contextPathColumn)
|
||||
{
|
||||
checkNotNull(contextPathColumn);
|
||||
_contextPathColumn = contextPathColumn;
|
||||
}
|
||||
public String getVirtualHostColumn()
|
||||
{
|
||||
return _virtualHostColumn;
|
||||
}
|
||||
public void setVirtualHostColumn(String virtualHostColumn)
|
||||
{
|
||||
checkNotNull(virtualHostColumn);
|
||||
_virtualHostColumn = virtualHostColumn;
|
||||
}
|
||||
public String getLastNodeColumn()
|
||||
{
|
||||
return _lastNodeColumn;
|
||||
}
|
||||
public void setLastNodeColumn(String lastNodeColumn)
|
||||
{
|
||||
checkNotNull(lastNodeColumn);
|
||||
_lastNodeColumn = lastNodeColumn;
|
||||
}
|
||||
public String getAccessTimeColumn()
|
||||
{
|
||||
return _accessTimeColumn;
|
||||
}
|
||||
public void setAccessTimeColumn(String accessTimeColumn)
|
||||
{
|
||||
checkNotNull(accessTimeColumn);
|
||||
_accessTimeColumn = accessTimeColumn;
|
||||
}
|
||||
public String getLastAccessTimeColumn()
|
||||
{
|
||||
return _lastAccessTimeColumn;
|
||||
}
|
||||
public void setLastAccessTimeColumn(String lastAccessTimeColumn)
|
||||
{
|
||||
checkNotNull(lastAccessTimeColumn);
|
||||
_lastAccessTimeColumn = lastAccessTimeColumn;
|
||||
}
|
||||
public String getCreateTimeColumn()
|
||||
{
|
||||
return _createTimeColumn;
|
||||
}
|
||||
public void setCreateTimeColumn(String createTimeColumn)
|
||||
{
|
||||
checkNotNull(createTimeColumn);
|
||||
_createTimeColumn = createTimeColumn;
|
||||
}
|
||||
public String getCookieTimeColumn()
|
||||
{
|
||||
return _cookieTimeColumn;
|
||||
}
|
||||
public void setCookieTimeColumn(String cookieTimeColumn)
|
||||
{
|
||||
checkNotNull(cookieTimeColumn);
|
||||
_cookieTimeColumn = cookieTimeColumn;
|
||||
}
|
||||
public String getLastSavedTimeColumn()
|
||||
{
|
||||
return _lastSavedTimeColumn;
|
||||
}
|
||||
public void setLastSavedTimeColumn(String lastSavedTimeColumn)
|
||||
{
|
||||
checkNotNull(lastSavedTimeColumn);
|
||||
_lastSavedTimeColumn = lastSavedTimeColumn;
|
||||
}
|
||||
public String getExpiryTimeColumn()
|
||||
{
|
||||
return _expiryTimeColumn;
|
||||
}
|
||||
public void setExpiryTimeColumn(String expiryTimeColumn)
|
||||
{
|
||||
checkNotNull(expiryTimeColumn);
|
||||
_expiryTimeColumn = expiryTimeColumn;
|
||||
}
|
||||
public String getMaxIntervalColumn()
|
||||
{
|
||||
return _maxIntervalColumn;
|
||||
}
|
||||
public void setMaxIntervalColumn(String maxIntervalColumn)
|
||||
{
|
||||
checkNotNull(maxIntervalColumn);
|
||||
_maxIntervalColumn = maxIntervalColumn;
|
||||
}
|
||||
public String getMapColumn()
|
||||
{
|
||||
return _mapColumn;
|
||||
}
|
||||
public void setMapColumn(String mapColumn)
|
||||
{
|
||||
checkNotNull(mapColumn);
|
||||
_mapColumn = mapColumn;
|
||||
}
|
||||
|
||||
public String getCreateStatementAsString ()
|
||||
{
|
||||
if (_dbAdaptor == null)
|
||||
throw new IllegalStateException ("No DBAdaptor");
|
||||
|
||||
String blobType = _dbAdaptor.getBlobType();
|
||||
String longType = _dbAdaptor.getLongType();
|
||||
|
||||
return "create table "+_tableName+" ("+getRowIdColumn()+" varchar(120), "+_idColumn+" varchar(120), "+
|
||||
_contextPathColumn+" varchar(60), "+_virtualHostColumn+" varchar(60), "+_lastNodeColumn+" varchar(60), "+_accessTimeColumn+" "+longType+", "+
|
||||
_lastAccessTimeColumn+" "+longType+", "+_createTimeColumn+" "+longType+", "+_cookieTimeColumn+" "+longType+", "+
|
||||
_lastSavedTimeColumn+" "+longType+", "+_expiryTimeColumn+" "+longType+", "+_maxIntervalColumn+" "+longType+", "+
|
||||
_mapColumn+" "+blobType+", primary key("+getRowIdColumn()+"))";
|
||||
}
|
||||
|
||||
public String getCreateIndexOverExpiryStatementAsString (String indexName)
|
||||
{
|
||||
return "create index "+indexName+" on "+getTableName()+" ("+getExpiryTimeColumn()+")";
|
||||
}
|
||||
|
||||
public String getCreateIndexOverSessionStatementAsString (String indexName)
|
||||
{
|
||||
return "create index "+indexName+" on "+getTableName()+" ("+getIdColumn()+", "+getContextPathColumn()+")";
|
||||
}
|
||||
|
||||
public String getAlterTableForMaxIntervalAsString ()
|
||||
{
|
||||
if (_dbAdaptor == null)
|
||||
throw new IllegalStateException ("No DBAdaptor");
|
||||
String longType = _dbAdaptor.getLongType();
|
||||
String stem = "alter table "+getTableName()+" add "+getMaxIntervalColumn()+" "+longType;
|
||||
if (_dbAdaptor.getDBName().contains("oracle"))
|
||||
return stem + " default "+ MAX_INTERVAL_NOT_SET + " not null";
|
||||
else
|
||||
return stem +" not null default "+ MAX_INTERVAL_NOT_SET;
|
||||
}
|
||||
|
||||
private void checkNotNull(String s)
|
||||
{
|
||||
if (s == null)
|
||||
throw new IllegalArgumentException(s);
|
||||
}
|
||||
public String getInsertSessionStatementAsString()
|
||||
{
|
||||
return "insert into "+getTableName()+
|
||||
" ("+getRowIdColumn()+", "+getIdColumn()+", "+getContextPathColumn()+", "+getVirtualHostColumn()+", "+getLastNodeColumn()+
|
||||
", "+getAccessTimeColumn()+", "+getLastAccessTimeColumn()+", "+getCreateTimeColumn()+", "+getCookieTimeColumn()+
|
||||
", "+getLastSavedTimeColumn()+", "+getExpiryTimeColumn()+", "+getMaxIntervalColumn()+", "+getMapColumn()+") "+
|
||||
" values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
}
|
||||
public String getDeleteSessionStatementAsString()
|
||||
{
|
||||
return "delete from "+getTableName()+
|
||||
" where "+getRowIdColumn()+" = ?";
|
||||
}
|
||||
public String getUpdateSessionStatementAsString()
|
||||
{
|
||||
return "update "+getTableName()+
|
||||
" set "+getIdColumn()+" = ?, "+getLastNodeColumn()+" = ?, "+getAccessTimeColumn()+" = ?, "+
|
||||
getLastAccessTimeColumn()+" = ?, "+getLastSavedTimeColumn()+" = ?, "+getExpiryTimeColumn()+" = ?, "+
|
||||
getMaxIntervalColumn()+" = ?, "+getMapColumn()+" = ? where "+getRowIdColumn()+" = ?";
|
||||
}
|
||||
public String getUpdateSessionNodeStatementAsString()
|
||||
{
|
||||
return "update "+getTableName()+
|
||||
" set "+getLastNodeColumn()+" = ? where "+getRowIdColumn()+" = ?";
|
||||
}
|
||||
public String getUpdateSessionAccessTimeStatementAsString()
|
||||
{
|
||||
return "update "+getTableName()+
|
||||
" set "+getLastNodeColumn()+" = ?, "+getAccessTimeColumn()+" = ?, "+getLastAccessTimeColumn()+" = ?, "+
|
||||
getLastSavedTimeColumn()+" = ?, "+getExpiryTimeColumn()+" = ?, "+getMaxIntervalColumn()+" = ? where "+getRowIdColumn()+" = ?";
|
||||
}
|
||||
|
||||
public String getBoundedExpiredSessionsStatementAsString()
|
||||
{
|
||||
return "select * from "+getTableName()+" where "+getLastNodeColumn()+" = ? and "+getExpiryTimeColumn()+" >= ? and "+getExpiryTimeColumn()+" <= ?";
|
||||
}
|
||||
|
||||
public String getSelectExpiredSessionsStatementAsString()
|
||||
{
|
||||
return "select * from "+getTableName()+" where "+getExpiryTimeColumn()+" >0 and "+getExpiryTimeColumn()+" <= ?";
|
||||
}
|
||||
|
||||
public PreparedStatement getLoadStatement (Connection connection, String rowId, String contextPath, String virtualHosts)
|
||||
throws SQLException
|
||||
{
|
||||
if (_dbAdaptor == null)
|
||||
throw new IllegalStateException("No DB adaptor");
|
||||
|
||||
|
||||
if (contextPath == null || "".equals(contextPath))
|
||||
{
|
||||
if (_dbAdaptor.isEmptyStringNull())
|
||||
{
|
||||
PreparedStatement statement = connection.prepareStatement("select * from "+getTableName()+
|
||||
" where "+getIdColumn()+" = ? and "+
|
||||
getContextPathColumn()+" is null and "+
|
||||
getVirtualHostColumn()+" = ?");
|
||||
statement.setString(1, rowId);
|
||||
statement.setString(2, virtualHosts);
|
||||
|
||||
return statement;
|
||||
}
|
||||
}
|
||||
|
||||
PreparedStatement statement = connection.prepareStatement("select * from "+getTableName()+
|
||||
" where "+getIdColumn()+" = ? and "+getContextPathColumn()+
|
||||
" = ? and "+getVirtualHostColumn()+" = ?");
|
||||
statement.setString(1, rowId);
|
||||
statement.setString(2, contextPath);
|
||||
statement.setString(3, virtualHosts);
|
||||
|
||||
return statement;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set up the tables in the database
|
||||
* @throws SQLException
|
||||
*/
|
||||
/**
|
||||
* @throws SQLException
|
||||
*/
|
||||
public void prepareTables()
|
||||
throws SQLException
|
||||
{
|
||||
try (Connection connection = _dbAdaptor.getConnection();
|
||||
Statement statement = connection.createStatement())
|
||||
{
|
||||
//make the id table
|
||||
connection.setAutoCommit(true);
|
||||
DatabaseMetaData metaData = connection.getMetaData();
|
||||
_dbAdaptor.adaptTo(metaData);
|
||||
|
||||
|
||||
//make the session table if necessary
|
||||
String tableName = _dbAdaptor.convertIdentifier(getTableName());
|
||||
try (ResultSet result = metaData.getTables(null, null, tableName, null))
|
||||
{
|
||||
if (!result.next())
|
||||
{
|
||||
//table does not exist, so create it
|
||||
statement.executeUpdate(getCreateStatementAsString());
|
||||
}
|
||||
else
|
||||
{
|
||||
//session table exists, check it has maxinterval column
|
||||
ResultSet colResult = null;
|
||||
try
|
||||
{
|
||||
colResult = metaData.getColumns(null, null,
|
||||
_dbAdaptor.convertIdentifier(getTableName()),
|
||||
_dbAdaptor.convertIdentifier(getMaxIntervalColumn()));
|
||||
}
|
||||
catch (SQLException s)
|
||||
{
|
||||
LOG.warn("Problem checking if "+getTableName()+
|
||||
" table contains "+getMaxIntervalColumn()+" column. Ensure table contains column definition: \""
|
||||
+ getMaxIntervalColumn()+" long not null default -999\"");
|
||||
throw s;
|
||||
}
|
||||
try
|
||||
{
|
||||
if (!colResult.next())
|
||||
{
|
||||
try
|
||||
{
|
||||
//add the maxinterval column
|
||||
statement.executeUpdate(getAlterTableForMaxIntervalAsString());
|
||||
}
|
||||
catch (SQLException s)
|
||||
{
|
||||
LOG.warn("Problem adding "+getMaxIntervalColumn()+
|
||||
" column. Ensure table contains column definition: \""+getMaxIntervalColumn()+
|
||||
" long not null default -999\"");
|
||||
throw s;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
colResult.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
//make some indexes on the JettySessions table
|
||||
String index1 = "idx_"+getTableName()+"_expiry";
|
||||
String index2 = "idx_"+getTableName()+"_session";
|
||||
|
||||
boolean index1Exists = false;
|
||||
boolean index2Exists = false;
|
||||
try (ResultSet result = metaData.getIndexInfo(null, null, tableName, false, false))
|
||||
{
|
||||
while (result.next())
|
||||
{
|
||||
String idxName = result.getString("INDEX_NAME");
|
||||
if (index1.equalsIgnoreCase(idxName))
|
||||
index1Exists = true;
|
||||
else if (index2.equalsIgnoreCase(idxName))
|
||||
index2Exists = true;
|
||||
}
|
||||
}
|
||||
if (!index1Exists)
|
||||
statement.executeUpdate(getCreateIndexOverExpiryStatementAsString(index1));
|
||||
if (!index2Exists)
|
||||
statement.executeUpdate(getCreateIndexOverSessionStatementAsString(index2));
|
||||
|
||||
//set up some strings representing the statements for session manipulation
|
||||
_insertSession = getInsertSessionStatementAsString();
|
||||
_deleteSession = getDeleteSessionStatementAsString();
|
||||
_updateSession = getUpdateSessionStatementAsString();
|
||||
_updateSessionNode = getUpdateSessionNodeStatementAsString();
|
||||
_updateSessionAccessTime = getUpdateSessionAccessTimeStatementAsString();
|
||||
_selectBoundedExpiredSessions = getBoundedExpiredSessionsStatementAsString();
|
||||
_selectExpiredSessions = getSelectExpiredSessionsStatementAsString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
@ -72,8 +735,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
@ -85,6 +747,19 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void setDeleteBlockSize (int bsize)
|
||||
{
|
||||
this._deleteBlockSize = bsize;
|
||||
}
|
||||
|
||||
public int getDeleteBlockSize ()
|
||||
{
|
||||
return this._deleteBlockSize;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
@ -95,19 +770,94 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
|||
|
||||
|
||||
|
||||
public void initialize () throws Exception
|
||||
{
|
||||
if (!_initialized)
|
||||
{
|
||||
_initialized = true;
|
||||
|
||||
if (_dbAdaptor == null)
|
||||
_dbAdaptor = new DatabaseAdaptor();
|
||||
|
||||
if (_sessionTableSchema == null)
|
||||
_sessionTableSchema = new SessionTableSchema();
|
||||
|
||||
_dbAdaptor.initializeDatabase();
|
||||
_sessionTableSchema.setDatabaseAdaptor(_dbAdaptor);
|
||||
_sessionTableSchema.prepareTables();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.session.x.SessionDataStore#load(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public SessionData load(String id) throws Exception
|
||||
public SessionData load(SessionKey key) throws Exception
|
||||
{
|
||||
// TODO make jdbc calls to load in the session
|
||||
long created = 0;
|
||||
long accessed = 0;
|
||||
long lastAccessed = 0;
|
||||
long maxInactiveMs = 0;
|
||||
JDBCSessionData data = (JDBCSessionData)newSessionData(id, created, accessed, lastAccessed, maxInactiveMs);
|
||||
|
||||
|
||||
try (Connection connection = _dbAdaptor.getConnection();
|
||||
PreparedStatement statement = _sessionTableSchema.getLoadStatement(connection, key.getId(), key.getCanonicalContextPath(), key.getVhost());
|
||||
ResultSet result = statement.executeQuery())
|
||||
{
|
||||
JDBCSessionData data = null;
|
||||
if (result.next())
|
||||
{
|
||||
long maxInterval = result.getLong(_sessionTableSchema.getMaxIntervalColumn());
|
||||
if (maxInterval == SessionTableSchema.MAX_INTERVAL_NOT_SET)
|
||||
{
|
||||
maxInterval = getMaxInactiveInterval(); //if value not saved for maxInactiveInterval, use current value from sessionmanager
|
||||
}
|
||||
data = (Session)newSession(id, ,
|
||||
,
|
||||
,
|
||||
maxInterval);
|
||||
data = (JDBCSessionData)newSessionData(id,
|
||||
result.getLong(_sessionTableSchema.getCreateTimeColumn()),
|
||||
result.getLong(_sessionTableSchema.getAccessTimeColumn()),
|
||||
result.getLong(_sessionTableSchema.getLastAccessTimeColumn()), maxInactiveMs);
|
||||
data.setRowId(result.getString(_sessionTableSchema.getRowIdColumn()));
|
||||
data.setCookieSetTime(result.getLong(_sessionTableSchema.getCookieTimeColumn()));
|
||||
data.setLastNode(result.getString(_sessionTableSchema.getLastNodeColumn()));
|
||||
data.setLastSaved(result.getLong(_sessionTableSchema.getLastSavedTimeColumn()));
|
||||
data.setExpiryTime(result.getLong(_sessionTableSchema.getExpiryTimeColumn()));
|
||||
data.setCanonicalContext(result.getString(_sessionTableSchema.getContextPathColumn()));
|
||||
data.setVirtualHost(result.getString(_sessionTableSchema.getVirtualHostColumn()));
|
||||
|
||||
try (InputStream is = _dbAdaptor.getBlobInputStream(result, _sessionTableSchema.getMapColumn());
|
||||
ClassLoadingObjectInputStream ois = new ClassLoadingObjectInputStream(is))
|
||||
{
|
||||
Object o = ois.readObject();
|
||||
data.addAttributes((Map<String,Object>)o);
|
||||
}
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("LOADED session "+data);
|
||||
}
|
||||
else
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Failed to load session "+id);
|
||||
_reference.set(data);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_exception.set(e);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// set vhost etc
|
||||
// set row id
|
||||
// set expiry time
|
||||
|
@ -139,6 +889,30 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
|||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.session.x.SessionDataStore#scavenge()
|
||||
*/
|
||||
@Override
|
||||
public void scavenge()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void setDatabaseAdaptor (DatabaseAdaptor dbAdaptor)
|
||||
{
|
||||
_dbAdaptor = dbAdaptor;
|
||||
}
|
||||
|
||||
public void setSessionTableSchema (SessionTableSchema schema)
|
||||
{
|
||||
_sessionTableSchema = schema;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -81,55 +81,49 @@ public class MemorySessionStore extends AbstractSessionStore
|
|||
* @see org.eclipse.jetty.server.session.x.AbstractSessionStore#doGet(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public Session doGet(String id)
|
||||
public Session doGet(SessionKey key)
|
||||
{
|
||||
Session session = _sessions.get(id);
|
||||
Session session = _sessions.get(key.getId());
|
||||
|
||||
if (isStale(session))
|
||||
{
|
||||
//delete from memory
|
||||
doDelete(id);
|
||||
doDelete(key);
|
||||
return null;
|
||||
}
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.session.x.AbstractSessionStore#doPutIfAbsent(java.lang.String, org.eclipse.jetty.server.session.x.Session)
|
||||
*/
|
||||
@Override
|
||||
public Session doPutIfAbsent(String id, Session session)
|
||||
{
|
||||
return _sessions.putIfAbsent(id, session);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.session.x.AbstractSessionStore#doPut(java.lang.String, org.eclipse.jetty.server.session.x.Session)
|
||||
*/
|
||||
@Override
|
||||
public void doPut(String id, Session session)
|
||||
public void doPut(SessionKey key, Session session)
|
||||
{
|
||||
_sessions.put(id, session);
|
||||
_sessions.put(key.getId(), session);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.session.x.AbstractSessionStore#doExists(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean doExists(String id)
|
||||
public boolean doExists(SessionKey key)
|
||||
{
|
||||
return _sessions.containsKey(id);
|
||||
return _sessions.containsKey(key.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.session.x.AbstractSessionStore#doDelete(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void doDelete(String id)
|
||||
public void doDelete(SessionKey key)
|
||||
{
|
||||
_sessions.remove(id);
|
||||
_sessions.remove(key.getId());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void shutdown ()
|
||||
|
@ -153,14 +147,14 @@ public class MemorySessionStore extends AbstractSessionStore
|
|||
session.willPassivate();
|
||||
try
|
||||
{
|
||||
_sessionDataStore.store(session.getId(), session.getSessionData());
|
||||
_sessionDataStore.store(SessionKey.getKey(session.getSessionData()), session.getSessionData());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
doDelete (session.getId()); //remove from memory
|
||||
doDelete (SessionKey.getKey(session.getSessionData())); //remove from memory
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -194,4 +188,17 @@ public class MemorySessionStore extends AbstractSessionStore
|
|||
return new MemorySession (data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.session.x.SessionStore#scavenge()
|
||||
*/
|
||||
@Override
|
||||
public void scavenge()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ public class NullSessionDataStore extends AbstractSessionDataStore
|
|||
* @see org.eclipse.jetty.server.session.x.SessionDataStore#load(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public SessionData load(String id) throws Exception
|
||||
public SessionData load(SessionKey key) throws Exception
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ public class NullSessionDataStore extends AbstractSessionDataStore
|
|||
* @see org.eclipse.jetty.server.session.x.SessionDataStore#delete(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean delete(String id) throws Exception
|
||||
public boolean delete(SessionKey key) throws Exception
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -58,9 +58,18 @@ public class NullSessionDataStore extends AbstractSessionDataStore
|
|||
* @see org.eclipse.jetty.server.session.x.AbstractSessionDataStore#doStore()
|
||||
*/
|
||||
@Override
|
||||
public void doStore() throws Exception
|
||||
public void doStore(SessionKey key, SessionData data) throws Exception
|
||||
{
|
||||
//noop
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.session.x.SessionDataStore#scavenge()
|
||||
*/
|
||||
@Override
|
||||
public void scavenge()
|
||||
{
|
||||
//noop
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
|
||||
package org.eclipse.jetty.server.session.x;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* SessionDataFactory
|
||||
*
|
||||
*
|
||||
*/
|
||||
public interface SessionDataFactory
|
||||
{
|
||||
public SessionData newSessionData (String id, long created, long accessed, long lastAccessed, long maxInactiveMs);
|
||||
public SessionData newSessionData (HttpServletRequest request);
|
||||
}
|
|
@ -33,7 +33,7 @@ public interface SessionDataStore
|
|||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public SessionData load (String id) throws Exception;
|
||||
public SessionData load (SessionKey key) throws Exception;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -51,7 +51,7 @@ public interface SessionDataStore
|
|||
* @param data
|
||||
* @throws Exception
|
||||
*/
|
||||
public void store (String id, SessionData data) throws Exception;
|
||||
public void store (SessionKey key, SessionData data) throws Exception;
|
||||
|
||||
|
||||
|
||||
|
@ -61,8 +61,17 @@ public interface SessionDataStore
|
|||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public boolean delete (String id) throws Exception;
|
||||
public boolean delete (SessionKey key) throws Exception;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Called periodically, this method should search the data store
|
||||
* for sessions that have been expired for a 'reasonable' amount
|
||||
* of time.
|
||||
*/
|
||||
public void scavenge ();
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
|
||||
package org.eclipse.jetty.server.session.x;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* SessionFactory
|
||||
*
|
||||
*
|
||||
*/
|
||||
public interface SessionFactory
|
||||
{
|
||||
public SessionManager.SessionIf newSession (HttpServletRequest request);
|
||||
public SessionManager.SessionIf newSession (SessionData data);
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
|
||||
package org.eclipse.jetty.server.session.x;
|
||||
|
||||
import org.eclipse.jetty.server.handler.ContextHandler.Context;
|
||||
|
||||
/**
|
||||
* SessionKey
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class SessionKey
|
||||
{
|
||||
private String _id;
|
||||
private String _canonicalContextPath;
|
||||
private String _vhost;
|
||||
|
||||
|
||||
public static SessionKey getKey (String id, Context context)
|
||||
{
|
||||
String cpath = getContextPath(context);
|
||||
String vhosts = getVirtualHost(context);
|
||||
return new SessionKey (id, cpath, vhosts);
|
||||
}
|
||||
|
||||
public static SessionKey getKey (SessionData data)
|
||||
{
|
||||
String cpath = data.getContextPath();
|
||||
String vhost = data.getVhost();
|
||||
String id = data.getId();
|
||||
return new SessionKey(id, cpath, vhost);
|
||||
}
|
||||
|
||||
|
||||
private SessionKey (String id, String path, String vhost)
|
||||
{
|
||||
_id = id;
|
||||
_canonicalContextPath = path;
|
||||
_vhost = vhost;
|
||||
}
|
||||
|
||||
public String getId()
|
||||
{
|
||||
return _id;
|
||||
}
|
||||
|
||||
public String getCanonicalContextPath()
|
||||
{
|
||||
return _canonicalContextPath;
|
||||
}
|
||||
|
||||
public String getVhost()
|
||||
{
|
||||
return _vhost;
|
||||
}
|
||||
|
||||
public String toString ()
|
||||
{
|
||||
return _canonicalContextPath +"_"+_vhost+"_"+_id;
|
||||
}
|
||||
|
||||
private static String getContextPath (Context context)
|
||||
{
|
||||
return canonicalize (context.getContextPath());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the first virtual host for the context.
|
||||
*
|
||||
* Used to help identify the exact session/contextPath.
|
||||
*
|
||||
* @return 0.0.0.0 if no virtual host is defined
|
||||
*/
|
||||
private static String getVirtualHost (Context context)
|
||||
{
|
||||
String vhost = "0.0.0.0";
|
||||
|
||||
if (context==null)
|
||||
return vhost;
|
||||
|
||||
String [] vhosts = context.getContextHandler().getVirtualHosts();
|
||||
if (vhosts==null || vhosts.length==0 || vhosts[0]==null)
|
||||
return vhost;
|
||||
|
||||
return vhosts[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an acceptable name from a context path.
|
||||
*
|
||||
* @param path
|
||||
* @return
|
||||
*/
|
||||
private static String canonicalize (String path)
|
||||
{
|
||||
if (path==null)
|
||||
return "";
|
||||
|
||||
return path.replace('/', '_').replace('.','_').replace('\\','_');
|
||||
}
|
||||
}
|
|
@ -29,6 +29,7 @@ import java.util.HashSet;
|
|||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.servlet.SessionCookieConfig;
|
||||
import javax.servlet.SessionTrackingMode;
|
||||
|
@ -54,6 +55,8 @@ import org.eclipse.jetty.util.log.Log;
|
|||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.statistic.CounterStatistic;
|
||||
import org.eclipse.jetty.util.statistic.SampleStatistic;
|
||||
import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
|
||||
import org.eclipse.jetty.util.thread.Scheduler;
|
||||
|
||||
/**
|
||||
* AbstractSessionManager
|
||||
|
@ -62,8 +65,7 @@ import org.eclipse.jetty.util.statistic.SampleStatistic;
|
|||
*/
|
||||
public class SessionManager extends ContainerLifeCycle implements org.eclipse.jetty.server.SessionManager
|
||||
{
|
||||
final static Logger __log = Log.getLogger(SessionManager.class);// TODO SessionHandler.LOG
|
||||
|
||||
private final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session");
|
||||
|
||||
public Set<SessionTrackingMode> __defaultSessionTrackingModes =
|
||||
Collections.unmodifiableSet(
|
||||
|
@ -130,6 +132,37 @@ public class SessionManager extends ContainerLifeCycle implements org.eclipse.je
|
|||
|
||||
protected final CounterStatistic _sessionsStats = new CounterStatistic();
|
||||
protected final SampleStatistic _sessionTimeStats = new SampleStatistic();
|
||||
|
||||
|
||||
protected Scheduler _scheduler; //scheduler for scavenging
|
||||
protected boolean _ownScheduler; //did we create our own scheduler or reuse common one
|
||||
protected Scheduler.Task _task; //scavenge task
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Scavenger
|
||||
*
|
||||
*/
|
||||
protected class Scavenger implements Runnable
|
||||
{
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
scavenge();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_scheduler != null && _scheduler.isRunning())
|
||||
_task = _scheduler.schedule(this, _scavengeIntervalMs, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public SessionManager()
|
||||
|
@ -224,7 +257,7 @@ public class SessionManager extends ContainerLifeCycle implements org.eclipse.je
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
__log.warn(e);
|
||||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -232,6 +265,11 @@ public class SessionManager extends ContainerLifeCycle implements org.eclipse.je
|
|||
@Override
|
||||
public void doStart() throws Exception
|
||||
{
|
||||
if (_sessionStore == null)
|
||||
throw new IllegalStateException("No session store configured");
|
||||
|
||||
|
||||
|
||||
_context=ContextHandler.getCurrentContext();
|
||||
_loader=Thread.currentThread().getContextClassLoader();
|
||||
|
||||
|
@ -300,8 +338,21 @@ public class SessionManager extends ContainerLifeCycle implements org.eclipse.je
|
|||
_checkingRemoteSessionIdEncoding=Boolean.parseBoolean(tmp);
|
||||
}
|
||||
|
||||
if (_sessionStore == null)
|
||||
throw new IllegalStateException("No session store configured");
|
||||
|
||||
|
||||
//try and use a common scheduler, fallback to own
|
||||
_scheduler = server.getBean(Scheduler.class);
|
||||
if (_scheduler == null)
|
||||
{
|
||||
_scheduler = new ScheduledExecutorScheduler();
|
||||
_ownScheduler = true;
|
||||
_scheduler.start();
|
||||
}
|
||||
else if (!_scheduler.isStarted())
|
||||
throw new IllegalStateException("Shared scheduler not started");
|
||||
|
||||
setScavengeInterval(getScavengeInterval());
|
||||
|
||||
|
||||
super.doStart();
|
||||
}
|
||||
|
@ -590,7 +641,7 @@ public class SessionManager extends ContainerLifeCycle implements org.eclipse.je
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
__log.warn(e);
|
||||
LOG.warn(e);
|
||||
}
|
||||
|
||||
_sessionsStats.increment();
|
||||
|
@ -716,7 +767,7 @@ public class SessionManager extends ContainerLifeCycle implements org.eclipse.je
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
__log.warn(e);
|
||||
LOG.warn(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -796,7 +847,7 @@ public class SessionManager extends ContainerLifeCycle implements org.eclipse.je
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
__log.warn(e);
|
||||
LOG.warn(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -853,6 +904,10 @@ public class SessionManager extends ContainerLifeCycle implements org.eclipse.je
|
|||
new CookieConfig();
|
||||
|
||||
|
||||
private long _scavengeIntervalMs;
|
||||
private Scavenger _scavenger;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return total amount of time all sessions remained valid
|
||||
|
@ -926,6 +981,52 @@ public class SessionManager extends ContainerLifeCycle implements org.eclipse.je
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void scavenge ()
|
||||
{
|
||||
//TODO call scavenge on the cache, which calls through to scavenge on the backing store
|
||||
}
|
||||
|
||||
|
||||
public void setScavengeInterval (long sec)
|
||||
{
|
||||
if (sec<=0)
|
||||
sec=60;
|
||||
|
||||
long old_period=_scavengeIntervalMs;
|
||||
long period=sec*1000L;
|
||||
|
||||
_scavengeIntervalMs=period;
|
||||
|
||||
//add a bit of variability into the scavenge time so that not all
|
||||
//nodes with the same scavenge interval sync up
|
||||
long tenPercent = _scavengeIntervalMs/10;
|
||||
if ((System.currentTimeMillis()%2) == 0)
|
||||
_scavengeIntervalMs += tenPercent;
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Scavenging every "+_scavengeIntervalMs+" ms");
|
||||
|
||||
synchronized (this)
|
||||
{
|
||||
//if (_timer!=null && (period!=old_period || _task==null))
|
||||
if (_scheduler != null && (period!=old_period || _task==null))
|
||||
{
|
||||
if (_task!=null)
|
||||
_task.cancel();
|
||||
if (_scavenger == null)
|
||||
_scavenger = new Scavenger();
|
||||
_task = _scheduler.schedule(_scavenger,_scavengeIntervalMs,TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public long getScavengeInterval ()
|
||||
{
|
||||
return _scavengeIntervalMs/1000;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* CookieConfig
|
||||
|
|
|
@ -28,11 +28,11 @@ package org.eclipse.jetty.server.session.x;
|
|||
public interface SessionStore
|
||||
{
|
||||
Session newSession (String id, long created, long accessed, long lastAccessed, long maxInactiveMs);
|
||||
Session get(String id) throws Exception;
|
||||
void put(String id, Session session) throws Exception;
|
||||
boolean exists (String id) throws Exception;
|
||||
Session putIfAbsent(String id, Session session) throws Exception;
|
||||
boolean delete (String id) throws Exception;
|
||||
Session get(SessionKey key) throws Exception;
|
||||
void put(SessionKey key, Session session) throws Exception;
|
||||
boolean exists (SessionKey key) throws Exception;
|
||||
boolean delete (SessionKey key) throws Exception;
|
||||
void shutdown ();
|
||||
void scavenge ();
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue