More implementation.
This commit is contained in:
parent
fa8232d3c8
commit
e2ecf7ca14
|
@ -46,6 +46,4 @@ public abstract class AbstractSessionDataStore extends AbstractLifeCycle impleme
|
||||||
data.setDirty(false);
|
data.setDirty(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||||
public abstract class AbstractSessionStore extends AbstractLifeCycle implements SessionStore
|
public abstract class AbstractSessionStore extends AbstractLifeCycle implements SessionStore
|
||||||
{
|
{
|
||||||
protected SessionDataStore _sessionDataStore;
|
protected SessionDataStore _sessionDataStore;
|
||||||
|
protected StalenessStrategy _staleStrategy;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -78,6 +79,16 @@ public abstract class AbstractSessionStore extends AbstractLifeCycle implements
|
||||||
_sessionDataStore = sessionDataStore;
|
_sessionDataStore = sessionDataStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public StalenessStrategy getStaleStrategy()
|
||||||
|
{
|
||||||
|
return _staleStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStaleStrategy(StalenessStrategy staleStrategy)
|
||||||
|
{
|
||||||
|
_staleStrategy = staleStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a session object.
|
* Get a session object.
|
||||||
*
|
*
|
||||||
|
@ -161,7 +172,6 @@ public abstract class AbstractSessionStore extends AbstractLifeCycle implements
|
||||||
public boolean delete(SessionKey key) throws Exception
|
public boolean delete(SessionKey key) throws Exception
|
||||||
{
|
{
|
||||||
boolean deleted = true;
|
boolean deleted = true;
|
||||||
//TODO synchronization???
|
|
||||||
if (_sessionDataStore != null)
|
if (_sessionDataStore != null)
|
||||||
deleted = _sessionDataStore.delete(key);
|
deleted = _sessionDataStore.delete(key);
|
||||||
doDelete(key);
|
doDelete(key);
|
||||||
|
@ -170,7 +180,21 @@ public abstract class AbstractSessionStore extends AbstractLifeCycle implements
|
||||||
|
|
||||||
public boolean isStale (Session session)
|
public boolean isStale (Session session)
|
||||||
{
|
{
|
||||||
//TODO implement (pluggable?) algorithm for deciding if memory is stale
|
if (_staleStrategy != null)
|
||||||
|
return _staleStrategy.isStale(session);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.eclipse.jetty.server.session.x.SessionStore#scavenge()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void scavenge()
|
||||||
|
{
|
||||||
|
if (!isStarted())
|
||||||
|
return;
|
||||||
|
_sessionDataStore.scavenge();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AlwaysStale
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class AlwaysStaleStrategy implements StalenessStrategy
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.eclipse.jetty.server.session.x.StalenessStrategy#isStale(org.eclipse.jetty.server.session.x.Session)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isStale(Session session)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -29,7 +29,9 @@ import java.io.InputStream;
|
||||||
import java.io.ObjectOutputStream;
|
import java.io.ObjectOutputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.eclipse.jetty.util.ClassLoadingObjectInputStream;
|
import org.eclipse.jetty.util.ClassLoadingObjectInputStream;
|
||||||
import org.eclipse.jetty.util.log.Log;
|
import org.eclipse.jetty.util.log.Log;
|
||||||
|
@ -182,13 +184,15 @@ public class FileSessionDataStore extends AbstractSessionDataStore
|
||||||
if (size>0)
|
if (size>0)
|
||||||
{
|
{
|
||||||
// input stream should not be closed here
|
// input stream should not be closed here
|
||||||
|
Map<String,Object> attributes = new HashMap<String,Object>();
|
||||||
ClassLoadingObjectInputStream ois = new ClassLoadingObjectInputStream(is);
|
ClassLoadingObjectInputStream ois = new ClassLoadingObjectInputStream(is);
|
||||||
for (int i=0; i<size;i++)
|
for (int i=0; i<size;i++)
|
||||||
{
|
{
|
||||||
String key = ois.readUTF();
|
String key = ois.readUTF();
|
||||||
Object value = ois.readObject();
|
Object value = ois.readObject();
|
||||||
data.setAttribute(key,value);
|
attributes.put(key,value);
|
||||||
}
|
}
|
||||||
|
data.putAllAttributes(attributes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,11 +32,12 @@ import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.naming.InitialContext;
|
import javax.naming.InitialContext;
|
||||||
import javax.naming.NameNotFoundException;
|
|
||||||
import javax.naming.NamingException;
|
import javax.naming.NamingException;
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
@ -57,6 +58,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
||||||
|
|
||||||
protected int _deleteBlockSize = 10; //number of ids to include in where 'in' clause for finding long expired sessions
|
protected int _deleteBlockSize = 10; //number of ids to include in where 'in' clause for finding long expired sessions
|
||||||
protected boolean _initialized = false;
|
protected boolean _initialized = false;
|
||||||
|
protected long _lastScavengeTime = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -321,19 +323,6 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
||||||
protected String _maxIntervalColumn = "maxInterval";
|
protected String _maxIntervalColumn = "maxInterval";
|
||||||
protected String _mapColumn = "map";
|
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)
|
protected void setDatabaseAdaptor(DatabaseAdaptor dbadaptor)
|
||||||
|
@ -522,34 +511,34 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
||||||
public String getInsertSessionStatementAsString()
|
public String getInsertSessionStatementAsString()
|
||||||
{
|
{
|
||||||
return "insert into "+getTableName()+
|
return "insert into "+getTableName()+
|
||||||
" ("+getRowIdColumn()+", "+getIdColumn()+", "+getContextPathColumn()+", "+getVirtualHostColumn()+", "+getLastNodeColumn()+
|
" ("+getIdColumn()+", "+getContextPathColumn()+", "+getVirtualHostColumn()+", "+getLastNodeColumn()+
|
||||||
", "+getAccessTimeColumn()+", "+getLastAccessTimeColumn()+", "+getCreateTimeColumn()+", "+getCookieTimeColumn()+
|
", "+getAccessTimeColumn()+", "+getLastAccessTimeColumn()+", "+getCreateTimeColumn()+", "+getCookieTimeColumn()+
|
||||||
", "+getLastSavedTimeColumn()+", "+getExpiryTimeColumn()+", "+getMaxIntervalColumn()+", "+getMapColumn()+") "+
|
", "+getLastSavedTimeColumn()+", "+getExpiryTimeColumn()+", "+getMaxIntervalColumn()+", "+getMapColumn()+") "+
|
||||||
" values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
" values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||||
}
|
}
|
||||||
public String getDeleteSessionStatementAsString()
|
|
||||||
|
public String getUpdateSessionStatementAsString(SessionKey key)
|
||||||
{
|
{
|
||||||
return "delete from "+getTableName()+
|
String s = "update "+getTableName()+
|
||||||
" where "+getRowIdColumn()+" = ?";
|
|
||||||
}
|
|
||||||
public String getUpdateSessionStatementAsString()
|
|
||||||
{
|
|
||||||
return "update "+getTableName()+
|
|
||||||
" set "+getIdColumn()+" = ?, "+getLastNodeColumn()+" = ?, "+getAccessTimeColumn()+" = ?, "+
|
" set "+getIdColumn()+" = ?, "+getLastNodeColumn()+" = ?, "+getAccessTimeColumn()+" = ?, "+
|
||||||
getLastAccessTimeColumn()+" = ?, "+getLastSavedTimeColumn()+" = ?, "+getExpiryTimeColumn()+" = ?, "+
|
getLastAccessTimeColumn()+" = ?, "+getLastSavedTimeColumn()+" = ?, "+getExpiryTimeColumn()+" = ?, "+
|
||||||
getMaxIntervalColumn()+" = ?, "+getMapColumn()+" = ? where "+getRowIdColumn()+" = ?";
|
getMaxIntervalColumn()+" = ?, "+getMapColumn()+" = ? where ";
|
||||||
}
|
|
||||||
public String getUpdateSessionNodeStatementAsString()
|
if (key.getCanonicalContextPath() == null || "".equals(key.getCanonicalContextPath()))
|
||||||
{
|
{
|
||||||
return "update "+getTableName()+
|
if (_dbAdaptor.isEmptyStringNull())
|
||||||
" set "+getLastNodeColumn()+" = ? where "+getRowIdColumn()+" = ?";
|
|
||||||
}
|
|
||||||
public String getUpdateSessionAccessTimeStatementAsString()
|
|
||||||
{
|
{
|
||||||
return "update "+getTableName()+
|
return s+getIdColumn()+" = ? and "+
|
||||||
" set "+getLastNodeColumn()+" = ?, "+getAccessTimeColumn()+" = ?, "+getLastAccessTimeColumn()+" = ?, "+
|
getContextPathColumn()+" is null and "+
|
||||||
getLastSavedTimeColumn()+" = ?, "+getExpiryTimeColumn()+" = ?, "+getMaxIntervalColumn()+" = ? where "+getRowIdColumn()+" = ?";
|
getVirtualHostColumn()+" = ?";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s+getIdColumn()+" = ? and "+getContextPathColumn()+
|
||||||
|
" = ? and "+getVirtualHostColumn()+" = ?";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public String getBoundedExpiredSessionsStatementAsString()
|
public String getBoundedExpiredSessionsStatementAsString()
|
||||||
{
|
{
|
||||||
|
@ -594,6 +583,42 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public PreparedStatement getUpdateStatement (Connection connection, SessionKey key)
|
||||||
|
throws SQLException
|
||||||
|
{
|
||||||
|
if (_dbAdaptor == null)
|
||||||
|
throw new IllegalStateException("No DB adaptor");
|
||||||
|
|
||||||
|
String s = "update "+getTableName()+
|
||||||
|
" set "+getIdColumn()+" = ?, "+getLastNodeColumn()+" = ?, "+getAccessTimeColumn()+" = ?, "+
|
||||||
|
getLastAccessTimeColumn()+" = ?, "+getLastSavedTimeColumn()+" = ?, "+getExpiryTimeColumn()+" = ?, "+
|
||||||
|
getMaxIntervalColumn()+" = ?, "+getMapColumn()+" = ? where ";
|
||||||
|
|
||||||
|
if (key.getCanonicalContextPath() == null || "".equals(key.getCanonicalContextPath()))
|
||||||
|
{
|
||||||
|
if (_dbAdaptor.isEmptyStringNull())
|
||||||
|
{
|
||||||
|
PreparedStatement statement = connection.prepareStatement(s+getIdColumn()+" = ? and "+
|
||||||
|
getContextPathColumn()+" is null and "+
|
||||||
|
getVirtualHostColumn()+" = ?");
|
||||||
|
statement.setString(1, key.getId());
|
||||||
|
statement.setString(2, key.getVhost());
|
||||||
|
return statement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PreparedStatement statement = connection.prepareStatement(s+getIdColumn()+" = ? and "+getContextPathColumn()+
|
||||||
|
" = ? and "+getVirtualHostColumn()+" = ?");
|
||||||
|
statement.setString(1, key.getId());
|
||||||
|
statement.setString(2, key.getCanonicalContextPath());
|
||||||
|
statement.setString(3, key.getVhost());
|
||||||
|
|
||||||
|
return statement;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public PreparedStatement getDeleteStatement (Connection connection, SessionKey key)
|
public PreparedStatement getDeleteStatement (Connection connection, SessionKey key)
|
||||||
throws Exception
|
throws Exception
|
||||||
{
|
{
|
||||||
|
@ -717,91 +742,13 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
||||||
statement.executeUpdate(getCreateIndexOverExpiryStatementAsString(index1));
|
statement.executeUpdate(getCreateIndexOverExpiryStatementAsString(index1));
|
||||||
if (!index2Exists)
|
if (!index2Exists)
|
||||||
statement.executeUpdate(getCreateIndexOverSessionStatementAsString(index2));
|
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JDBCSessionData
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class JDBCSessionData extends SessionData
|
|
||||||
{
|
|
||||||
protected String _rowId;
|
|
||||||
protected long _lastSaved; //time in msec since last save
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param id
|
|
||||||
* @param created
|
|
||||||
* @param accessed
|
|
||||||
* @param lastAccessed
|
|
||||||
* @param maxInactiveMs
|
|
||||||
*/
|
|
||||||
public JDBCSessionData(String id, long created, long accessed, long lastAccessed, long maxInactiveMs)
|
|
||||||
{
|
|
||||||
super(id, created, accessed, lastAccessed, maxInactiveMs);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public String getRowId()
|
|
||||||
{
|
|
||||||
return _rowId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRowId(String rowId)
|
|
||||||
{
|
|
||||||
_rowId = rowId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public long getLastSaved()
|
|
||||||
{
|
|
||||||
return _lastSaved;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void setLastSaved(long lastSaved)
|
|
||||||
{
|
|
||||||
_lastSaved = lastSaved;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setAttributes (Map<String, Object> attributes)
|
|
||||||
{
|
|
||||||
_attributes.putAll(attributes);
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO immutable??
|
|
||||||
public Map<String,Object> getAttributes ()
|
|
||||||
{
|
|
||||||
return _attributes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public JDBCSessionDataStore ()
|
public JDBCSessionDataStore ()
|
||||||
{
|
{
|
||||||
super ();
|
super ();
|
||||||
|
@ -826,7 +773,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
||||||
@Override
|
@Override
|
||||||
public SessionData newSessionData(String id, long created, long accessed, long lastAccessed, long maxInactiveMs)
|
public SessionData newSessionData(String id, long created, long accessed, long lastAccessed, long maxInactiveMs)
|
||||||
{
|
{
|
||||||
return new JDBCSessionData(id, created, accessed, lastAccessed, maxInactiveMs);
|
return new SessionData(id, created, accessed, lastAccessed, maxInactiveMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -881,15 +828,14 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
||||||
PreparedStatement statement = _sessionTableSchema.getLoadStatement(connection, key);
|
PreparedStatement statement = _sessionTableSchema.getLoadStatement(connection, key);
|
||||||
ResultSet result = statement.executeQuery())
|
ResultSet result = statement.executeQuery())
|
||||||
{
|
{
|
||||||
JDBCSessionData data = null;
|
SessionData data = null;
|
||||||
if (result.next())
|
if (result.next())
|
||||||
{
|
{
|
||||||
data = (JDBCSessionData)newSessionData(key.getId(),
|
data = newSessionData(key.getId(),
|
||||||
result.getLong(_sessionTableSchema.getCreateTimeColumn()),
|
result.getLong(_sessionTableSchema.getCreateTimeColumn()),
|
||||||
result.getLong(_sessionTableSchema.getAccessTimeColumn()),
|
result.getLong(_sessionTableSchema.getAccessTimeColumn()),
|
||||||
result.getLong(_sessionTableSchema.getLastAccessTimeColumn()),
|
result.getLong(_sessionTableSchema.getLastAccessTimeColumn()),
|
||||||
result.getLong(_sessionTableSchema.getMaxIntervalColumn()));
|
result.getLong(_sessionTableSchema.getMaxIntervalColumn()));
|
||||||
data.setRowId(result.getString(_sessionTableSchema.getRowIdColumn()));
|
|
||||||
data.setCookieSet(result.getLong(_sessionTableSchema.getCookieTimeColumn()));
|
data.setCookieSet(result.getLong(_sessionTableSchema.getCookieTimeColumn()));
|
||||||
data.setLastNode(result.getString(_sessionTableSchema.getLastNodeColumn()));
|
data.setLastNode(result.getString(_sessionTableSchema.getLastNodeColumn()));
|
||||||
data.setLastSaved(result.getLong(_sessionTableSchema.getLastSavedTimeColumn()));
|
data.setLastSaved(result.getLong(_sessionTableSchema.getLastSavedTimeColumn()));
|
||||||
|
@ -901,7 +847,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
||||||
ClassLoadingObjectInputStream ois = new ClassLoadingObjectInputStream(is))
|
ClassLoadingObjectInputStream ois = new ClassLoadingObjectInputStream(is))
|
||||||
{
|
{
|
||||||
Object o = ois.readObject();
|
Object o = ois.readObject();
|
||||||
data.setAttributes((Map<String,Object>)o);
|
data.putAllAttributes((Map<String,Object>)o);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -946,41 +892,109 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
||||||
@Override
|
@Override
|
||||||
public void doStore(SessionKey key, SessionData data) throws Exception
|
public void doStore(SessionKey key, SessionData data) throws Exception
|
||||||
{
|
{
|
||||||
// TODO write session data to jdbc
|
|
||||||
if (data==null || key==null)
|
if (data==null || key==null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
try (Connection connection = _dbAdaptor.getConnection();
|
try (Connection connection = _dbAdaptor.getConnection())
|
||||||
PreparedStatement statement = connection.prepareStatement(_sessionTableSchema.getUpdateSessionStatementAsString()))
|
|
||||||
{
|
{
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
connection.setAutoCommit(true);
|
connection.setAutoCommit(true);
|
||||||
statement.setString(1, key.getId());
|
|
||||||
statement.setString(2, data.getLastNode());//should be my node id
|
//If last saved field not set, then this is a fresh session that has never been persisted
|
||||||
statement.setLong(3, data.getAccessed());//accessTime
|
if (data.getLastSaved() <= 0)
|
||||||
statement.setLong(4, data.getLastAccessed()); //lastAccessTime
|
{
|
||||||
statement.setLong(5, now); //last saved time
|
doInsert(connection, key, data);
|
||||||
statement.setLong(6, data.getExpiry());
|
}
|
||||||
statement.setLong(7, data.getMaxInactiveMs());
|
else
|
||||||
|
{
|
||||||
|
doUpdate(connection, key, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void doInsert (Connection connection, SessionKey key, SessionData data)
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
|
String s = _sessionTableSchema.getInsertSessionStatementAsString();
|
||||||
|
|
||||||
|
try (PreparedStatement statement = connection.prepareStatement(s))
|
||||||
|
{
|
||||||
|
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
|
||||||
|
|
||||||
|
statement.setString(1, key.getId()); //session id
|
||||||
|
statement.setString(2, key.getCanonicalContextPath()); //context path
|
||||||
|
statement.setString(3, key.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, now); //last saved time
|
||||||
|
statement.setLong(10, data.getExpiry());
|
||||||
|
statement.setLong(11, data.getMaxInactiveMs());
|
||||||
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||||
oos.writeObject(((JDBCSessionData)data).getAttributes());
|
oos.writeObject(data.getAllAttributes());
|
||||||
|
oos.flush();
|
||||||
|
byte[] bytes = baos.toByteArray();
|
||||||
|
|
||||||
|
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
|
||||||
|
statement.setBinaryStream(12, bais, bytes.length);//attribute map as blob
|
||||||
|
statement.executeUpdate();
|
||||||
|
data.setLastSaved(now);
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("Inserted session "+data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doUpdate (Connection connection, SessionKey key, SessionData data)
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
|
try (PreparedStatement statement = connection.prepareStatement(_sessionTableSchema.getUpdateSessionStatementAsString(key)))
|
||||||
|
{
|
||||||
|
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
|
||||||
|
|
||||||
|
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, now); //last saved time
|
||||||
|
statement.setLong(5, data.getExpiry());
|
||||||
|
statement.setLong(6, data.getMaxInactiveMs());
|
||||||
|
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||||
|
oos.writeObject(data.getAllAttributes());
|
||||||
oos.flush();
|
oos.flush();
|
||||||
byte[] bytes = baos.toByteArray();
|
byte[] bytes = baos.toByteArray();
|
||||||
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
|
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
|
||||||
|
statement.setBinaryStream(7, bais, bytes.length);//attribute map as blob
|
||||||
|
|
||||||
|
if ((key.getCanonicalContextPath() == null || "".equals(key.getCanonicalContextPath())) && _dbAdaptor.isEmptyStringNull())
|
||||||
|
{
|
||||||
|
statement.setString(8, key.getId());
|
||||||
|
statement.setString(9, key.getVhost());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
statement.setString(8, key.getId());
|
||||||
|
statement.setString(9, key.getCanonicalContextPath());
|
||||||
|
statement.setString(10, key.getVhost());
|
||||||
|
}
|
||||||
|
|
||||||
statement.setBinaryStream(8, bais, bytes.length);//attribute map as blob
|
|
||||||
statement.setString(9, ((JDBCSessionData)data).getRowId()); //rowId
|
|
||||||
statement.executeUpdate();
|
statement.executeUpdate();
|
||||||
|
|
||||||
((JDBCSessionData)data).setLastSaved(now);
|
data.setLastSaved(now);
|
||||||
}
|
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("Updated session "+data);
|
LOG.debug("Updated session "+data);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -989,7 +1003,24 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
|
||||||
@Override
|
@Override
|
||||||
public void scavenge()
|
public void scavenge()
|
||||||
{
|
{
|
||||||
// TODO Auto-generated method stub
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("Scavenge sweep started at "+System.currentTimeMillis());
|
||||||
|
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
|
||||||
|
//first time we're called, don't scavenge
|
||||||
|
if (_lastScavengeTime == 0)
|
||||||
|
{
|
||||||
|
_lastScavengeTime = now;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*TODO
|
||||||
|
* 1. Select sessions for our node and our context that have expired since our last pass, giving some leeway
|
||||||
|
* 2. Select sessions for our node that have expired some time ago
|
||||||
|
* 3. Select sessions for any node that have expired quite a while ago
|
||||||
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,7 @@ public class MemorySessionStore extends AbstractSessionStore
|
||||||
|
|
||||||
if (isStale(session))
|
if (isStale(session))
|
||||||
{
|
{
|
||||||
//delete from memory
|
//delete from memory so should reload
|
||||||
doDelete(key);
|
doDelete(key);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -193,16 +193,4 @@ public class MemorySessionStore extends AbstractSessionStore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see org.eclipse.jetty.server.session.x.SessionStore#scavenge()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void scavenge()
|
|
||||||
{
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NeverStale
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class NeverStaleStrategy implements StalenessStrategy
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.eclipse.jetty.server.session.x.StalenessStrategy#isStale(org.eclipse.jetty.server.session.x.Session)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isStale(Session session)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.server.session.x;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -33,6 +34,9 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||||
*/
|
*/
|
||||||
public class SessionData implements Serializable
|
public class SessionData implements Serializable
|
||||||
{
|
{
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
protected String _id;
|
protected String _id;
|
||||||
|
|
||||||
protected String _contextPath;
|
protected String _contextPath;
|
||||||
|
@ -50,7 +54,7 @@ public class SessionData implements Serializable
|
||||||
protected long _maxInactiveMs;
|
protected long _maxInactiveMs;
|
||||||
protected Map<String,Object> _attributes = new ConcurrentHashMap<String, Object>();
|
protected Map<String,Object> _attributes = new ConcurrentHashMap<String, Object>();
|
||||||
protected boolean _dirty;
|
protected boolean _dirty;
|
||||||
|
protected long _lastSaved; //time in msec since last save
|
||||||
|
|
||||||
|
|
||||||
public SessionData (String id, long created, long accessed, long lastAccessed, long maxInactiveMs)
|
public SessionData (String id, long created, long accessed, long lastAccessed, long maxInactiveMs)
|
||||||
|
@ -62,6 +66,20 @@ public class SessionData implements Serializable
|
||||||
_maxInactiveMs = maxInactiveMs;
|
_maxInactiveMs = maxInactiveMs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public long getLastSaved()
|
||||||
|
{
|
||||||
|
return _lastSaved;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public void setLastSaved(long lastSaved)
|
||||||
|
{
|
||||||
|
_lastSaved = lastSaved;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean isDirty()
|
public boolean isDirty()
|
||||||
{
|
{
|
||||||
return _dirty;
|
return _dirty;
|
||||||
|
@ -93,6 +111,16 @@ public class SessionData implements Serializable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void putAllAttributes (Map<String,Object> attributes)
|
||||||
|
{
|
||||||
|
_attributes.putAll(attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String,Object> getAllAttributes()
|
||||||
|
{
|
||||||
|
return Collections.unmodifiableMap(_attributes);
|
||||||
|
}
|
||||||
|
|
||||||
public String getId()
|
public String getId()
|
||||||
{
|
{
|
||||||
return _id;
|
return _id;
|
||||||
|
|
|
@ -764,11 +764,14 @@ public class SessionManager extends ContainerLifeCycle implements org.eclipse.je
|
||||||
Session session = _sessionStore.get(key);
|
Session session = _sessionStore.get(key);
|
||||||
if (session != null)
|
if (session != null)
|
||||||
{
|
{
|
||||||
//TODO consider not allowing load of expired sessions inside stores
|
//If the session we got back has expired
|
||||||
//if the session we loaded has expired
|
|
||||||
if (session.isExpiredAt(System.currentTimeMillis()))
|
if (session.isExpiredAt(System.currentTimeMillis()))
|
||||||
{
|
{
|
||||||
//Remove the expired session from cache and backing persistent store
|
//Tell the id manager that this session id should not be used in case other threads
|
||||||
|
//try to use the same session id in other contexts
|
||||||
|
_sessionIdManager.removeId(id);
|
||||||
|
|
||||||
|
//Remove the expired session from cache and any backing persistent store
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_sessionStore.delete(key);
|
_sessionStore.delete(key);
|
||||||
|
@ -778,10 +781,6 @@ public class SessionManager extends ContainerLifeCycle implements org.eclipse.je
|
||||||
LOG.warn("Unable to delete expired session {}", key);
|
LOG.warn("Unable to delete expired session {}", key);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Tell the id manager that this session id should not be used in case other threads
|
|
||||||
//try to use the same session id in other contexts
|
|
||||||
_sessionIdManager.removeId(id);
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -799,9 +798,9 @@ public class SessionManager extends ContainerLifeCycle implements org.eclipse.je
|
||||||
_sessionIdManager.removeId(id);
|
_sessionIdManager.removeId(id);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
catch (Exception e1)
|
catch (Exception other)
|
||||||
{
|
{
|
||||||
LOG.warn(e1);
|
LOG.warn(other);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -996,24 +995,48 @@ public class SessionManager extends ContainerLifeCycle implements org.eclipse.je
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* Tell the HttpSessionIdListeners the id changed.
|
* Change the session id and tell the HttpSessionIdListeners the id changed.
|
||||||
* NOTE: this method must be called LAST in subclass overrides, after the session has been updated
|
*
|
||||||
* with the new id.
|
|
||||||
* @see org.eclipse.jetty.server.SessionManager#renewSessionId(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void renewSessionId(String oldClusterId, String oldNodeId, String newClusterId, String newNodeId)
|
public void renewSessionId(String oldId, String oldExtendedId, String newId, String newExtendedId)
|
||||||
{
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SessionKey oldKey = SessionKey.getKey(oldId, _context);
|
||||||
|
SessionKey newKey = SessionKey.getKey(newId, _context);
|
||||||
|
|
||||||
|
Session session = _sessionStore.get(oldKey);
|
||||||
|
if (session == null)
|
||||||
|
{
|
||||||
|
LOG.warn("Unable to renew id to "+newId+" for non-existant session "+oldId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//save session with new id
|
||||||
|
session.getSessionData().setId(newId);
|
||||||
|
session.setExtendedId(newExtendedId);
|
||||||
|
session.getSessionData().setLastSaved(0); //forces an insert
|
||||||
|
_sessionStore.put(newKey, session);
|
||||||
|
|
||||||
|
//remove session with old id
|
||||||
|
_sessionStore.delete(oldKey);
|
||||||
|
|
||||||
|
//inform the listeners
|
||||||
if (!_sessionIdListeners.isEmpty())
|
if (!_sessionIdListeners.isEmpty())
|
||||||
{
|
{
|
||||||
Session session = getSession(newClusterId);
|
|
||||||
HttpSessionEvent event = new HttpSessionEvent(session);
|
HttpSessionEvent event = new HttpSessionEvent(session);
|
||||||
for (HttpSessionIdListener l:_sessionIdListeners)
|
for (HttpSessionIdListener l:_sessionIdListeners)
|
||||||
{
|
{
|
||||||
l.sessionIdChanged(event, oldClusterId);
|
l.sessionIdChanged(event, oldId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
LOG.warn(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void scavenge ()
|
public void scavenge ()
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StalePeriodStrategy
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class StalePeriodStrategy implements StalenessStrategy
|
||||||
|
{
|
||||||
|
protected long _staleMs = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.eclipse.jetty.server.session.x.StalenessStrategy#isStale(org.eclipse.jetty.server.session.x.Session)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isStale (Session session)
|
||||||
|
{
|
||||||
|
if (session == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
//never persisted, must be fresh session
|
||||||
|
if (session.getSessionData().getLastSaved() == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (_staleMs <= 0)
|
||||||
|
{
|
||||||
|
//TODO always stale, never stale??
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return (session.getSessionData().getAccessed() - session.getSessionData().getLastSaved() >= _staleMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public long getStaleSec ()
|
||||||
|
{
|
||||||
|
return (_staleMs<=0?0L:_staleMs/1000L);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStaleSec (long sec)
|
||||||
|
{
|
||||||
|
if (sec == 0)
|
||||||
|
_staleMs = 0L;
|
||||||
|
else
|
||||||
|
_staleMs = sec * 1000L;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StalenessStrategy
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface StalenessStrategy
|
||||||
|
{
|
||||||
|
boolean isStale (Session session);
|
||||||
|
}
|
Loading…
Reference in New Issue