org.eclipse.jetty.server.session.JDBCSessionDataStore Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jetty-server Show documentation
Show all versions of jetty-server Show documentation
The core jetty server artifact.
//
// ========================================================================
// Copyright (c) 1995-2019 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;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.jetty.util.ClassLoadingObjectInputStream;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/**
* JDBCSessionDataStore
*
* Session data stored in database
*/
@ManagedObject
public class JDBCSessionDataStore extends AbstractSessionDataStore
{
static final Logger LOG = Log.getLogger("org.eclipse.jetty.server.session");
/**
* Used for Oracle and other databases where "" is treated as NULL
*/
public static final String NULL_CONTEXT_PATH = "/";
protected boolean _initialized = false;
protected DatabaseAdaptor _dbAdaptor;
protected SessionTableSchema _sessionTableSchema;
protected boolean _schemaProvided;
/**
* SessionTableSchema
*/
public static class SessionTableSchema
{
public static final int MAX_INTERVAL_NOT_SET = -999;
protected DatabaseAdaptor _dbAdaptor;
protected String _schemaName = null;
protected String _tableName = "JettySessions";
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";
protected void setDatabaseAdaptor(DatabaseAdaptor dbadaptor)
{
_dbAdaptor = dbadaptor;
}
public String getSchemaName()
{
return _schemaName;
}
public void setSchemaName(String schemaName)
{
checkNotNull(schemaName);
_schemaName = schemaName;
}
public String getTableName()
{
return _tableName;
}
public void setTableName(String tableName)
{
checkNotNull(tableName);
_tableName = tableName;
}
private String getSchemaTableName()
{
return (getSchemaName() != null ? getSchemaName() + "." : "") + getTableName();
}
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();
String stringType = _dbAdaptor.getStringType();
return "create table " + _tableName + " (" + _idColumn + " " + stringType + "(120), " +
_contextPathColumn + " " + stringType + "(60), " + _virtualHostColumn + " " + stringType + "(60), " + _lastNodeColumn + " " + stringType + "(60), " + _accessTimeColumn + " " + longType + ", " +
_lastAccessTimeColumn + " " + longType + ", " + _createTimeColumn + " " + longType + ", " + _cookieTimeColumn + " " + longType + ", " +
_lastSavedTimeColumn + " " + longType + ", " + _expiryTimeColumn + " " + longType + ", " + _maxIntervalColumn + " " + longType + ", " +
_mapColumn + " " + blobType + ", primary key(" + _idColumn + ", " + _contextPathColumn + "," + _virtualHostColumn + "))";
}
public String getCreateIndexOverExpiryStatementAsString(String indexName)
{
return "create index " + indexName + " on " + getSchemaTableName() + " (" + getExpiryTimeColumn() + ")";
}
public String getCreateIndexOverSessionStatementAsString(String indexName)
{
return "create index " + indexName + " on " + getSchemaTableName() + " (" + getIdColumn() + ", " + getContextPathColumn() + ")";
}
public String getAlterTableForMaxIntervalAsString()
{
if (_dbAdaptor == null)
throw new IllegalStateException("No DBAdaptor");
String longType = _dbAdaptor.getLongType();
String stem = "alter table " + getSchemaTableName() + " 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 " + getSchemaTableName() +
" (" + getIdColumn() + ", " + getContextPathColumn() + ", " + getVirtualHostColumn() + ", " + getLastNodeColumn() +
", " + getAccessTimeColumn() + ", " + getLastAccessTimeColumn() + ", " + getCreateTimeColumn() + ", " + getCookieTimeColumn() +
", " + getLastSavedTimeColumn() + ", " + getExpiryTimeColumn() + ", " + getMaxIntervalColumn() + ", " + getMapColumn() + ") " +
" values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
}
public PreparedStatement getUpdateSessionStatement(Connection connection, String id, SessionContext context)
throws SQLException
{
String s = "update " + getSchemaTableName() +
" set " + getLastNodeColumn() + " = ?, " + getAccessTimeColumn() + " = ?, " +
getLastAccessTimeColumn() + " = ?, " + getLastSavedTimeColumn() + " = ?, " + getExpiryTimeColumn() + " = ?, " +
getMaxIntervalColumn() + " = ?, " + getMapColumn() + " = ? where " + getIdColumn() + " = ? and " + getContextPathColumn() +
" = ? and " + getVirtualHostColumn() + " = ?";
String cp = context.getCanonicalContextPath();
if (_dbAdaptor.isEmptyStringNull() && StringUtil.isBlank(cp))
cp = NULL_CONTEXT_PATH;
PreparedStatement statement = connection.prepareStatement(s);
statement.setString(8, id);
statement.setString(9, cp);
statement.setString(10, context.getVhost());
return statement;
}
public PreparedStatement getExpiredSessionsStatement(Connection connection, String canonicalContextPath, String vhost, long expiry)
throws SQLException
{
// TODO expiry should be a delay rather than an absolute time.
if (_dbAdaptor == null)
throw new IllegalStateException("No DB adaptor");
String cp = canonicalContextPath;
if (_dbAdaptor.isEmptyStringNull() && StringUtil.isBlank(cp))
cp = NULL_CONTEXT_PATH;
PreparedStatement statement = connection.prepareStatement("select " + getIdColumn() + ", " + getExpiryTimeColumn() +
" from " + getSchemaTableName() + " where " + getContextPathColumn() + " = ? and " +
getVirtualHostColumn() + " = ? and " +
getExpiryTimeColumn() + " >0 and " + getExpiryTimeColumn() + " <= ?");
statement.setString(1, cp);
statement.setString(2, vhost);
statement.setLong(3, expiry);
return statement;
}
public PreparedStatement getMyExpiredSessionsStatement(Connection connection, SessionContext sessionContext, long expiry)
throws SQLException
{
// TODO expiry should be a delay rather than an absolute time.
if (_dbAdaptor == null)
throw new IllegalStateException("No DB adaptor");
String cp = sessionContext.getCanonicalContextPath();
if (_dbAdaptor.isEmptyStringNull() && StringUtil.isBlank(cp))
cp = NULL_CONTEXT_PATH;
PreparedStatement statement = connection.prepareStatement("select " + getIdColumn() + ", " + getExpiryTimeColumn() +
" from " + getSchemaTableName() + " where " +
getLastNodeColumn() + " = ? and " +
getContextPathColumn() + " = ? and " +
getVirtualHostColumn() + " = ? and " +
getExpiryTimeColumn() + " >0 and " + getExpiryTimeColumn() + " <= ?");
statement.setString(1, sessionContext.getWorkerName());
statement.setString(2, cp);
statement.setString(3, sessionContext.getVhost());
statement.setLong(4, expiry);
return statement;
}
public PreparedStatement getAllAncientExpiredSessionsStatement(Connection connection)
throws SQLException
{
if (_dbAdaptor == null)
throw new IllegalStateException("No DB adaptor");
PreparedStatement statement = connection.prepareStatement("select " + getIdColumn() + ", " + getContextPathColumn() + ", " + getVirtualHostColumn() +
" from " + getSchemaTableName() +
" where " + getExpiryTimeColumn() + " >0 and " + getExpiryTimeColumn() + " <= ?");
return statement;
}
public PreparedStatement getCheckSessionExistsStatement(Connection connection, SessionContext context)
throws SQLException
{
if (_dbAdaptor == null)
throw new IllegalStateException("No DB adaptor");
String cp = context.getCanonicalContextPath();
if (_dbAdaptor.isEmptyStringNull() && StringUtil.isBlank(cp))
cp = NULL_CONTEXT_PATH;
PreparedStatement statement = connection.prepareStatement("select " + getIdColumn() + ", " + getExpiryTimeColumn() +
" from " + getSchemaTableName() +
" where " + getIdColumn() + " = ? and " +
getContextPathColumn() + " = ? and " +
getVirtualHostColumn() + " = ?");
statement.setString(2, cp);
statement.setString(3, context.getVhost());
return statement;
}
public PreparedStatement getLoadStatement(Connection connection, String id, SessionContext contextId)
throws SQLException
{
if (_dbAdaptor == null)
throw new IllegalStateException("No DB adaptor");
String cp = contextId.getCanonicalContextPath();
if (_dbAdaptor.isEmptyStringNull() && StringUtil.isBlank(cp))
cp = NULL_CONTEXT_PATH;
PreparedStatement statement = connection.prepareStatement("select * from " + getSchemaTableName() +
" where " + getIdColumn() + " = ? and " + getContextPathColumn() +
" = ? and " + getVirtualHostColumn() + " = ?");
statement.setString(1, id);
statement.setString(2, cp);
statement.setString(3, contextId.getVhost());
return statement;
}
public PreparedStatement getUpdateStatement(Connection connection, String id, SessionContext contextId)
throws SQLException
{
if (_dbAdaptor == null)
throw new IllegalStateException("No DB adaptor");
String cp = contextId.getCanonicalContextPath();
if (_dbAdaptor.isEmptyStringNull() && StringUtil.isBlank(cp))
cp = NULL_CONTEXT_PATH;
String s = "update " + getSchemaTableName() +
" set " + getLastNodeColumn() + " = ?, " + getAccessTimeColumn() + " = ?, " +
getLastAccessTimeColumn() + " = ?, " + getLastSavedTimeColumn() + " = ?, " + getExpiryTimeColumn() + " = ?, " +
getMaxIntervalColumn() + " = ?, " + getMapColumn() + " = ? where " + getIdColumn() + " = ? and " + getContextPathColumn() +
" = ? and " + getVirtualHostColumn() + " = ?";
PreparedStatement statement = connection.prepareStatement(s);
statement.setString(8, id);
statement.setString(9, cp);
statement.setString(10, contextId.getVhost());
return statement;
}
public PreparedStatement getDeleteStatement(Connection connection, String id, SessionContext contextId)
throws Exception
{
if (_dbAdaptor == null)
throw new IllegalStateException("No DB adaptor");
String cp = contextId.getCanonicalContextPath();
if (_dbAdaptor.isEmptyStringNull() && StringUtil.isBlank(cp))
cp = NULL_CONTEXT_PATH;
PreparedStatement statement = connection.prepareStatement("delete from " + getSchemaTableName() +
" where " + getIdColumn() + " = ? and " + getContextPathColumn() +
" = ? and " + getVirtualHostColumn() + " = ?");
statement.setString(1, id);
statement.setString(2, cp);
statement.setString(3, contextId.getVhost());
return statement;
}
/**
* Set up the tables in the database
*
* @throws SQLException if unable to prepare tables
*/
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());
String schemaName = _dbAdaptor.convertIdentifier(getSchemaName());
try (ResultSet result = metaData.getTables(null, schemaName, 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, schemaName, tableName,
_dbAdaptor.convertIdentifier(getMaxIntervalColumn()));
}
catch (SQLException sqlEx)
{
LOG.warn("Problem checking if " + getTableName() +
" table contains " + getMaxIntervalColumn() + " column. Ensure table contains column definition: \"" +
getMaxIntervalColumn() + " long not null default -999\"");
throw sqlEx;
}
try
{
if (!colResult.next())
{
try
{
//add the maxinterval column
statement.executeUpdate(getAlterTableForMaxIntervalAsString());
}
catch (SQLException sqlEx)
{
LOG.warn("Problem adding " + getMaxIntervalColumn() +
" column. Ensure table contains column definition: \"" + getMaxIntervalColumn() +
" long not null default -999\"");
throw sqlEx;
}
}
}
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, schemaName, tableName, false, true))
{
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));
}
}
@Override
public String toString()
{
return String.format("%s[%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s]", super.toString(),
_schemaName, _tableName, _idColumn, _contextPathColumn, _virtualHostColumn, _cookieTimeColumn, _createTimeColumn,
_expiryTimeColumn, _accessTimeColumn, _lastAccessTimeColumn, _lastNodeColumn, _lastSavedTimeColumn, _maxIntervalColumn);
}
}
public JDBCSessionDataStore()
{
super();
}
@Override
protected void doStart() throws Exception
{
if (_dbAdaptor == null)
throw new IllegalStateException("No jdbc config");
initialize();
super.doStart();
}
@Override
protected void doStop() throws Exception
{
super.doStop();
_initialized = false;
if (!_schemaProvided)
_sessionTableSchema = null;
}
public void initialize() throws Exception
{
if (!_initialized)
{
_initialized = true;
//taking the defaults if one not set
if (_sessionTableSchema == null)
{
_sessionTableSchema = new SessionTableSchema();
addBean(_sessionTableSchema, true);
}
_dbAdaptor.initialize();
_sessionTableSchema.setDatabaseAdaptor(_dbAdaptor);
_sessionTableSchema.prepareTables();
}
}
@Override
public SessionData doLoad(String id) throws Exception
{
try (Connection connection = _dbAdaptor.getConnection();
PreparedStatement statement = _sessionTableSchema.getLoadStatement(connection, id, _context);
ResultSet result = statement.executeQuery())
{
SessionData data = null;
if (result.next())
{
data = newSessionData(id,
result.getLong(_sessionTableSchema.getCreateTimeColumn()),
result.getLong(_sessionTableSchema.getAccessTimeColumn()),
result.getLong(_sessionTableSchema.getLastAccessTimeColumn()),
result.getLong(_sessionTableSchema.getMaxIntervalColumn()));
data.setCookieSet(result.getLong(_sessionTableSchema.getCookieTimeColumn()));
data.setLastNode(result.getString(_sessionTableSchema.getLastNodeColumn()));
data.setLastSaved(result.getLong(_sessionTableSchema.getLastSavedTimeColumn()));
data.setExpiry(result.getLong(_sessionTableSchema.getExpiryTimeColumn()));
data.setContextPath(_context.getCanonicalContextPath());
data.setVhost(_context.getVhost());
try (InputStream is = _dbAdaptor.getBlobInputStream(result, _sessionTableSchema.getMapColumn());
ClassLoadingObjectInputStream ois = new ClassLoadingObjectInputStream(is))
{
SessionData.deserializeAttributes(data, ois);
}
catch (Exception e)
{
throw new UnreadableSessionDataException(id, _context, e);
}
if (LOG.isDebugEnabled())
LOG.debug("LOADED session {}", data);
}
else if (LOG.isDebugEnabled())
LOG.debug("No session {}", id);
return data;
}
}
@Override
public boolean delete(String id) throws Exception
{
try (Connection connection = _dbAdaptor.getConnection();
PreparedStatement statement = _sessionTableSchema.getDeleteStatement(connection, id, _context))
{
connection.setAutoCommit(true);
int rows = statement.executeUpdate();
if (LOG.isDebugEnabled())
LOG.debug("Deleted Session {}:{}", id, (rows > 0));
return rows > 0;
}
}
@Override
public void doStore(String id, SessionData data, long lastSaveTime) throws Exception
{
if (data == null || id == null)
return;
if (lastSaveTime <= 0)
{
doInsert(id, data);
}
else
{
doUpdate(id, data);
}
}
protected void doInsert(String id, SessionData data)
throws Exception
{
String s = _sessionTableSchema.getInsertSessionStatementAsString();
try (Connection connection = _dbAdaptor.getConnection())
{
connection.setAutoCommit(true);
try (PreparedStatement statement = connection.prepareStatement(s))
{
statement.setString(1, id); //session id
String cp = _context.getCanonicalContextPath();
if (_dbAdaptor.isEmptyStringNull() && StringUtil.isBlank(cp))
cp = NULL_CONTEXT_PATH;
statement.setString(2, cp); //context path
statement.setString(3, _context.getVhost()); //first vhost
statement.setString(4, data.getLastNode());//my node id
statement.setLong(5, data.getAccessed());//accessTime
statement.setLong(6, data.getLastAccessed()); //lastAccessTime
statement.setLong(7, data.getCreated()); //time created
statement.setLong(8, data.getCookieSet());//time cookie was set
statement.setLong(9, data.getLastSaved()); //last saved time
statement.setLong(10, data.getExpiry());
statement.setLong(11, data.getMaxInactiveMs());
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos))
{
SessionData.serializeAttributes(data, oos);
byte[] bytes = baos.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
statement.setBinaryStream(12, bais, bytes.length);//attribute map as blob
statement.executeUpdate();
if (LOG.isDebugEnabled())
LOG.debug("Inserted session " + data);
}
}
}
}
protected void doUpdate(String id, SessionData data)
throws Exception
{
try (Connection connection = _dbAdaptor.getConnection())
{
connection.setAutoCommit(true);
try (PreparedStatement statement = _sessionTableSchema.getUpdateSessionStatement(connection, data.getId(), _context))
{
statement.setString(1, data.getLastNode());//should be my node id
statement.setLong(2, data.getAccessed());//accessTime
statement.setLong(3, data.getLastAccessed()); //lastAccessTime
statement.setLong(4, data.getLastSaved()); //last saved time
statement.setLong(5, data.getExpiry());
statement.setLong(6, data.getMaxInactiveMs());
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos))
{
SessionData.serializeAttributes(data, oos);
byte[] bytes = baos.toByteArray();
try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes))
{
statement.setBinaryStream(7, bais, bytes.length);//attribute map as blob
statement.executeUpdate();
if (LOG.isDebugEnabled())
LOG.debug("Updated session " + data);
}
}
}
}
}
@Override
public Set doGetExpired(Set candidates)
{
if (LOG.isDebugEnabled())
LOG.debug("Getting expired sessions at time {}", System.currentTimeMillis());
long now = System.currentTimeMillis();
Set expiredSessionKeys = new HashSet<>();
try (Connection connection = _dbAdaptor.getConnection())
{
connection.setAutoCommit(true);
/*
* 1. Select sessions managed by this node for our context that have expired
*/
long upperBound = now;
if (LOG.isDebugEnabled())
LOG.debug("{}- Pass 1: Searching for sessions for context {} managed by me and expired before {}", _context.getWorkerName(), _context.getCanonicalContextPath(), upperBound);
try (PreparedStatement statement = _sessionTableSchema.getExpiredSessionsStatement(connection, _context.getCanonicalContextPath(), _context.getVhost(), upperBound))
{
try (ResultSet result = statement.executeQuery())
{
while (result.next())
{
String sessionId = result.getString(_sessionTableSchema.getIdColumn());
long exp = result.getLong(_sessionTableSchema.getExpiryTimeColumn());
expiredSessionKeys.add(sessionId);
if (LOG.isDebugEnabled())
LOG.debug(_context.getCanonicalContextPath() + "- Found expired sessionId=" + sessionId);
}
}
}
/*
* 2. Select sessions for any node or context that have expired
* at least 1 graceperiod since the last expiry check. If we haven't done previous expiry checks, then check
* those that have expired at least 3 graceperiod ago.
*/
try (PreparedStatement selectExpiredSessions = _sessionTableSchema.getAllAncientExpiredSessionsStatement(connection))
{
if (_lastExpiryCheckTime <= 0)
upperBound = (now - (3 * (1000L * _gracePeriodSec)));
else
upperBound = _lastExpiryCheckTime - (1000L * _gracePeriodSec);
if (LOG.isDebugEnabled())
LOG.debug("{}- Pass 2: Searching for sessions expired before {}", _context.getWorkerName(), upperBound);
selectExpiredSessions.setLong(1, upperBound);
try (ResultSet result = selectExpiredSessions.executeQuery())
{
while (result.next())
{
String sessionId = result.getString(_sessionTableSchema.getIdColumn());
String ctxtpth = result.getString(_sessionTableSchema.getContextPathColumn());
String vh = result.getString(_sessionTableSchema.getVirtualHostColumn());
expiredSessionKeys.add(sessionId);
if (LOG.isDebugEnabled())
LOG.debug("{}- Found expired sessionId=", _context.getWorkerName(), sessionId);
}
}
}
Set notExpiredInDB = new HashSet<>();
for (String k : candidates)
{
//there are some keys that the session store thought had expired, but were not
//found in our sweep either because it is no longer in the db, or its
//expiry time was updated
if (!expiredSessionKeys.contains(k))
notExpiredInDB.add(k);
}
if (!notExpiredInDB.isEmpty())
{
//we have some sessions to check
try (PreparedStatement checkSessionExists = _sessionTableSchema.getCheckSessionExistsStatement(connection, _context))
{
for (String k : notExpiredInDB)
{
checkSessionExists.setString(1, k);
try (ResultSet result = checkSessionExists.executeQuery())
{
if (!result.next())
{
//session doesn't exist any more, can be expired
expiredSessionKeys.add(k);
}
//else its expiry time has not been reached
}
catch (Exception e)
{
LOG.warn("{} Problem checking if potentially expired session {} exists in db", _context.getWorkerName(), k, e);
}
}
}
}
return expiredSessionKeys;
}
catch (Exception e)
{
LOG.warn(e);
return expiredSessionKeys; //return whatever we got
}
}
public void setDatabaseAdaptor(DatabaseAdaptor dbAdaptor)
{
checkStarted();
updateBean(_dbAdaptor, dbAdaptor);
_dbAdaptor = dbAdaptor;
}
public void setSessionTableSchema(SessionTableSchema schema)
{
checkStarted();
updateBean(_sessionTableSchema, schema);
_sessionTableSchema = schema;
_schemaProvided = true;
}
@Override
@ManagedAttribute(value = "does this store serialize sessions", readonly = true)
public boolean isPassivating()
{
return true;
}
@Override
public boolean exists(String id)
throws Exception
{
try (Connection connection = _dbAdaptor.getConnection())
{
connection.setAutoCommit(true);
//non-expired session exists?
try (PreparedStatement checkSessionExists = _sessionTableSchema.getCheckSessionExistsStatement(connection, _context))
{
checkSessionExists.setString(1, id);
try (ResultSet result = checkSessionExists.executeQuery())
{
if (!result.next())
{
return false; //no such session
}
else
{
long expiry = result.getLong(_sessionTableSchema.getExpiryTimeColumn());
if (expiry <= 0) //never expires
return true;
else
return (expiry > System.currentTimeMillis()); //hasn't already expired
}
}
}
}
}
}