Remove necessity for SessionIdManager specializations.

This commit is contained in:
Jan Bartel 2016-03-17 12:27:52 +11:00
parent c1b03c6d8c
commit add04e8fba
65 changed files with 690 additions and 2367 deletions

View File

@ -3,33 +3,11 @@
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<!-- ============================================================================================== -->
<!-- GCloud configuration. -->
<!-- Note: passwords can use jetty obfuscation. See -->
<!-- https://www.eclipse.org/jetty/documentation/current/configuring-security-secure-passwords.html -->
<!-- See your start.ini or gcloud-sessions.ini file for more configuration information. -->
<!-- ============================================================================================== -->
<New id="gconf" class="org.eclipse.jetty.gcloud.session.GCloudConfiguration">
<!-- Either set jetty.gcloudSession.projectId or use system property/env var DATASTORE_DATASET-->
<Set name="projectId"><Property name="jetty.gcloudSession.projectId"/></Set>
<!-- To contact remote gclouddatastore set the following properties in start.ini -->
<Set name="p12File"><Property name="jetty.gcloudSession.p12File"/></Set>
<Set name="serviceAccount"><Property name="jetty.gcloudSession.serviceAccount"/></Set>
<Set name="password"><Property name="jetty.gcloudSession.password"/></Set>
</New>
<!-- ===================================================================== -->
<!-- Configure a GCloudSessionIdManager -->
<!-- ===================================================================== -->
<Set name="sessionIdManager">
<New id="idMgr" class="org.eclipse.jetty.gcloud.session.GCloudSessionIdManager">
<Arg>
<Ref id="Server"/>
</Arg>
<Set name="workerName"><Property name="jetty.gcloudSession.workerName"><Default>node<Env name="GAE_MODULE_INSTANCE" default="0"/></Default></Property></Set>
<Set name="config"><Ref id="gconf"/></Set>
</New>
</Set>
<Get name="sessionIdManager">
<Set name="workerName"><Property name="jetty.sessionIdManager.workerName"><Default>node<Env name="GAE_MODULE_INSTANCE" default="0"/></Default></Property></Set>
</Get>
</Configure>

View File

@ -1,5 +1,5 @@
[description]
Enables the GCloudDatastore Session Mananger module.
Enables GCloudDatastore session management.
[depend]
annotations
@ -43,18 +43,17 @@ maven://com.google.apis/google-api-services-datastore/v1beta2-rev23-1.19.0|lib/g
lib/jetty-gcloud-session-manager-${jetty.version}.jar
lib/gcloud/*.jar
[xml]
etc/jetty-gcloud-sessions.xml
[license]
GCloudDatastore is an open source project hosted on Github and released under the Apache 2.0 license.
https://github.com/GoogleCloudPlatform/gcloud-java
http://www.apache.org/licenses/LICENSE-2.0.html
[xml]
etc/jetty-gcloud-sessions.xml
[ini-template]
## Unique identifier to force the workername for this node in the cluster
## If not set, will default to the string "node" plus the Env variable $GAE_MODULE_INSTANCE
# jetty.gcloudSession.workerName=node1
## GCloudDatastore Session config

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<!-- ============================================================================================== -->
<!-- GCloud configuration. -->
<!-- Note: passwords can use jetty obfuscation. See -->
<!-- https://www.eclipse.org/jetty/documentation/current/configuring-security-secure-passwords.html -->
<!-- See your start.ini or gcloud-sessions.ini file for more configuration information. -->
<!-- ============================================================================================== -->
<New id="gconf" class="org.eclipse.jetty.gcloud.session.GCloudConfiguration">
<!-- Either set jetty.gcloudSession.projectId or use system property/env var DATASTORE_DATASET-->
<Set name="projectId"><Property name="jetty.gcloudSession.projectId"/></Set>
<!-- To contact remote gclouddatastore set the following properties in start.ini -->
<Set name="p12File"><Property name="jetty.gcloudSession.p12File"/></Set>
<Set name="serviceAccount"><Property name="jetty.gcloudSession.serviceAccount"/></Set>
<Set name="password"><Property name="jetty.gcloudSession.password"/></Set>
</New>
<Get name="sessionHandler">
<Set name="sessionManager">
<New class="org.eclipse.jetty.gcloud.session.GCloudSessionManager">
<Set name="maxInactiveInterval">seconds</Set>
<Get name="sessionDataStore">
<Set name="gcloudConfiguration">
<Ref id="gconf"/>
</Set>
<Set name="maxResults">integer</Set>
</Get>
<Get name="sessionStore">
<Set name="idlePassivationTimeoutSec">seconds</Set>
<Set name="expiryTimeoutSec">seconds</Set>
</Get>
</New>
</Set>
</Get>
</Configure>

View File

@ -273,6 +273,34 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
/**
* @see org.eclipse.jetty.server.session.SessionDataStore#exists(java.lang.String)
*/
@Override
public boolean exists(String id) throws Exception
{
ProjectionEntityQueryBuilder pbuilder = Query.projectionEntityQueryBuilder();
pbuilder.addProjection(Projection.property(EXPIRY));
pbuilder.filter(PropertyFilter.eq(ID, id));
pbuilder.kind(KIND);
StructuredQuery<ProjectionEntity> pquery = pbuilder.build();
QueryResults<ProjectionEntity> presults = _datastore.run(pquery);
if (presults.hasNext())
{
ProjectionEntity pe = presults.next();
long expiry = pe.getLong(EXPIRY);
if (expiry <= 0)
return true; //never expires
else
return (expiry > System.currentTimeMillis()); //not expired yet
}
else
return false;
}
/**
* @see org.eclipse.jetty.server.session.AbstractSessionDataStore#doStore(java.lang.String, org.eclipse.jetty.server.session.SessionData, long)
*/

View File

@ -1,231 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2016 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.gcloud.session;
import java.util.Random;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.session.AbstractSessionIdManager;
import org.eclipse.jetty.server.session.Session;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import com.google.gcloud.datastore.Datastore;
import com.google.gcloud.datastore.DatastoreFactory;
import com.google.gcloud.datastore.Entity;
import com.google.gcloud.datastore.Key;
import com.google.gcloud.datastore.KeyFactory;
/**
* GCloudSessionIdManager
*
*
*
*/
public class GCloudSessionIdManager extends AbstractSessionIdManager
{
private final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session");
public static final int DEFAULT_IDLE_EXPIRY_MULTIPLE = 2;
public static final String KIND = "GCloudSessionId";
private Datastore _datastore;
private KeyFactory _keyFactory;
private GCloudConfiguration _config;
/**
* @param server
*/
public GCloudSessionIdManager(Server server)
{
super(server);
}
/**
* @param server
* @param random
*/
public GCloudSessionIdManager(Server server, Random random)
{
super(server,random);
}
/**
* Start the id manager.
* @see org.eclipse.jetty.server.session.AbstractSessionIdManager#doStart()
*/
@Override
protected void doStart() throws Exception
{
if (_config == null)
throw new IllegalStateException("No gcloud configuration specified");
_datastore = DatastoreFactory.instance().get(_config.getDatastoreOptions());
_keyFactory = _datastore.newKeyFactory().kind(KIND);
super.doStart();
}
/**
* Stop the id manager
* @see org.eclipse.jetty.server.session.AbstractSessionIdManager#doStop()
*/
@Override
protected void doStop() throws Exception
{
super.doStop();
}
public GCloudConfiguration getConfig()
{
return _config;
}
public void setConfig(GCloudConfiguration config)
{
_config = config;
}
/**
* Ask the datastore if a particular id exists.
*
* @param id
* @return
*/
protected boolean exists (String id)
{
if (_datastore == null)
throw new IllegalStateException ("No DataStore");
Key key = _keyFactory.newKey(id);
return _datastore.get(key) != null;
}
/**
* Put a session id into the cluster.
*
* @param id
*/
protected void insert (String id)
{
if (_datastore == null)
throw new IllegalStateException ("No DataStore");
Entity entity = Entity.builder(makeKey(id))
.set("id", id).build();
_datastore.put(entity);
}
/**
* Remove a session id from the cluster.
*
* @param id
*/
protected boolean delete (String id)
{
if (_datastore == null)
throw new IllegalStateException ("No DataStore");
_datastore.delete(makeKey(id));
return true; //gcloud does not distinguish between first and subsequent removes
}
/**
* Generate a unique key from the session id.
*
* @param id
* @return
*/
protected Key makeKey (String id)
{
return _keyFactory.newKey(id);
}
/**
* @see org.eclipse.jetty.server.SessionIdManager#isIdInUse(java.lang.String)
*/
@Override
public boolean isIdInUse(String id)
{
if (id == null)
return false;
//ask the cluster - this should also tickle the idle expiration timer on the sessionid entry
//keeping it valid
try
{
return exists(id);
}
catch (Exception e)
{
LOG.warn("Problem checking inUse for id="+id, e);
return false;
}
}
/**
* @see org.eclipse.jetty.server.SessionIdManager#useId(org.eclipse.jetty.server.session.Session)
*/
@Override
public void useId(Session session)
{
if (session == null)
return;
//insert into the store
insert (session.getId());
}
/**
* @see org.eclipse.jetty.server.SessionIdManager#removeId(java.lang.String)
*/
@Override
public boolean removeId(String id)
{
if (id == null)
return false;
return delete(id);
}
}

View File

@ -29,6 +29,7 @@ import org.eclipse.jetty.util.log.Logger;
/**
* GCloudSessionManager
*
* Convenience class to link up a MemorySessionStore with the GCloudSessionDataStore.
*
*/
public class GCloudSessionManager extends SessionManager
@ -36,232 +37,9 @@ public class GCloudSessionManager extends SessionManager
private final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session");
private GCloudSessionDataStore _sessionDataStore = null;
/* *
* Session
*
* Representation of a session in local memory.
*//*
public class Session extends MemSession
{
private ReentrantLock _lock = new ReentrantLock();
private long _lastSyncTime;
private AtomicInteger _activeThreads = new AtomicInteger(0);
protected Session (HttpServletRequest request)
{
_activeThreads.incrementAndGet(); //access will not be called on a freshly created session so increment here
}
*/
/* *
* Called on entry to the session.
*
* @see org.eclipse.jetty.server.session.AbstractSession#access(long)
*//*
@Override
protected boolean access(long time)
{
if (LOG.isDebugEnabled())
LOG.debug("Access session({}) for context {} on worker {}", getId(), getContextPath(), getSessionIdManager().getWorkerName());
try
{
long now = System.currentTimeMillis();
//lock so that no other thread can call access or complete until the first one has refreshed the session object if necessary
_lock.lock();
//a request thread is entering
if (_activeThreads.incrementAndGet() == 1)
{
//if the first thread, check that the session in memory is not stale, if we're checking for stale sessions
if (getStaleIntervalSec() > 0 && (now - getLastSyncTime()) >= (getStaleIntervalSec() * 1000L))
{
if (LOG.isDebugEnabled())
LOG.debug("Acess session({}) for context {} on worker {} stale session. Reloading.", getId(), getContextPath(), getSessionIdManager().getWorkerName());
refresh();
}
}
}
catch (Exception e)
{
LOG.warn(e);
}
finally
{
_lock.unlock();
}
if (super.access(time))
{
int maxInterval=getMaxInactiveInterval();
_expiryTime = (maxInterval <= 0 ? 0 : (time + maxInterval*1000L));
return true;
}
return false;
}
*//* *
* Exit from session
* @see org.eclipse.jetty.server.session.AbstractSession#complete()
*//*
@Override
protected void complete()
{
super.complete();
//lock so that no other thread that might be calling access can proceed until this complete is done
_lock.lock();
try
{
//if this is the last request thread to be in the session
if (_activeThreads.decrementAndGet() == 0)
{
try
{
//an invalid session will already have been removed from the
//local session map and deleted from the cluster. If its valid save
//it to the cluster.
//TODO consider doing only periodic saves if only the last access
//time to the session changes
if (isValid())
{
//if session still valid && its dirty or stale or never been synced, write it to the cluster
//otherwise, we just keep the updated last access time in memory
if (_dirty || getLastSyncTime() == 0 || isStale(System.currentTimeMillis()))
{
willPassivate();
save(this);
didActivate();
}
}
}
catch (Exception e)
{
LOG.warn("Problem saving session({})",getId(), e);
}
finally
{
_dirty = false;
}
}
}
finally
{
_lock.unlock();
}
}
*//* * Test if the session is stale
* @param atTime
* @return
*//*
protected boolean isStale (long atTime)
{
return (getStaleIntervalSec() > 0) && (atTime - getLastSyncTime() >= (getStaleIntervalSec()*1000L));
}
*//* *
* Reload the session from the cluster. If the node that
* last managed the session from the cluster is ourself,
* then the session does not need refreshing.
* NOTE: this method MUST be called with sufficient locks
* in place to prevent 2 or more concurrent threads from
* simultaneously updating the session.
*//*
private void refresh ()
throws Exception
{
//get fresh copy from the cluster
Session fresh = load(makeKey(getClusterId(), _context));
//if the session no longer exists, invalidate
if (fresh == null)
{
invalidate();
return;
}
//cluster copy assumed to be the same as we were the last
//node to manage it
if (fresh.getLastNode().equals(getLastNode()))
return;
setLastNode(getSessionIdManager().getWorkerName());
//prepare for refresh
willPassivate();
//if fresh has no attributes, remove them
if (fresh.getAttributes() == 0)
this.clearAttributes();
else
{
//reconcile attributes
for (String key:fresh.getAttributeMap().keySet())
{
Object freshvalue = fresh.getAttribute(key);
//session does not already contain this attribute, so bind it
if (getAttribute(key) == null)
{
doPutOrRemove(key,freshvalue);
bindValue(key,freshvalue);
}
else //session already contains this attribute, update its value
{
doPutOrRemove(key,freshvalue);
}
}
// cleanup, remove values from session, that don't exist in data anymore:
for (String key : getNames())
{
if (fresh.getAttribute(key) == null)
{
Object oldvalue = getAttribute(key);
doPutOrRemove(key,null);
unbindValue(key,oldvalue);
}
}
}
//finish refresh
didActivate();
}
public void swapId (String newId, String newNodeId)
{
//TODO probably synchronize rather than use the access/complete lock?
_lock.lock();
setClusterId(newId);
setNodeId(newNodeId);
_lock.unlock();
}
}
*/
/**
*
*/
@ -309,15 +87,4 @@ public class GCloudSessionManager extends SessionManager
{
super.doStop();
}
protected void scavengeGCloudDataStore()
throws Exception
{
}
}

View File

@ -24,6 +24,7 @@ package org.eclipse.jetty.gcloud.session;
import org.eclipse.jetty.security.HashLoginService;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.AllowSymLinkAliasChecker;
import org.eclipse.jetty.server.session.DefaultSessionIdManager;
import org.eclipse.jetty.server.session.SessionHandler;
import org.eclipse.jetty.webapp.WebAppContext;
@ -48,8 +49,7 @@ public class GCloudSessionTester
config.setPassword(args[2]);
config.setServiceAccount(args[3]);
GCloudSessionIdManager idmgr = new GCloudSessionIdManager(server);
idmgr.setConfig(config);
DefaultSessionIdManager idmgr = new DefaultSessionIdManager(server);
idmgr.setWorkerName("w1");
server.setSessionIdManager(idmgr);
@ -59,6 +59,7 @@ public class GCloudSessionTester
webapp.setWar("../../jetty-distribution/target/distribution/demo-base/webapps/test.war");
webapp.addAliasCheck(new AllowSymLinkAliasChecker());
GCloudSessionManager mgr = new GCloudSessionManager();
mgr.getSessionDataStore().setGCloudConfiguration(config);
mgr.setSessionIdManager(idmgr);
webapp.setSessionHandler(new SessionHandler(mgr));

View File

@ -17,17 +17,9 @@ maven://org.jboss.logging/jboss-logging/3.1.2.GA|lib/infinispan/jboss-logging-3.
lib/jetty-infinispan-${jetty.version}.jar
lib/infinispan/*.jar
[xml]
etc/jetty-infinispan.xml
[license]
Infinispan is an open source project hosted on Github and released under the Apache 2.0 license.
http://infinispan.org/
http://www.apache.org/licenses/LICENSE-2.0.html
[ini-template]
## Infinispan Session config
## Unique identifier for this node in the cluster
# jetty.infinispanSession.workerName=node1

View File

@ -1,7 +1,8 @@
<?xml version="1.0"?>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<!-- ===================================================================== -->
<!-- Get a reference to the default local cache. -->
@ -23,17 +24,21 @@
-->
<!-- ===================================================================== -->
<!-- Configure a SessionIdManager with the cache selected above. -->
<!-- ===================================================================== -->
<Set name="sessionIdManager">
<New id="idMgr" class="org.eclipse.jetty.session.infinispan.InfinispanSessionIdManager">
<Arg>
<Ref refid="Server"/>
</Arg>
<Set name="workerName"><Property name="jetty.infinispanSession.workerName" default="node1"/></Set>
<Set name="cache"><Ref refid="cache"/></Set>
</New>
</Set>
<Get name="sessionHandler">
<Set name="sessionManager">
<New class="org.eclipse.jetty.server.session.infinispan.InfinispanSessionManager">
<Set name="maxInactiveInterval">seconds</Set>
<Get name="sessionDataStore">
<Set name="cache">
<Ref id="cache"/>
</Set>
</Get>
<Get name="sessionStore">
<Set name="idlePassivationTimeoutSec">seconds</Set>
<Set name="expiryTimeoutSec">seconds</Set>
</Get>
</New>
</Set>
</Get>
</Configure>

View File

@ -100,7 +100,7 @@ public class InfinispanSessionDataStore extends AbstractSessionDataStore
if (LOG.isDebugEnabled())
LOG.debug("Loading session {} from infinispan", id);
SessionData sd = (SessionData)_cache.get(getCacheKey(id, _context));
SessionData sd = (SessionData)_cache.get(getCacheKey(id));
reference.set(sd);
}
catch (Exception e)
@ -127,7 +127,7 @@ public class InfinispanSessionDataStore extends AbstractSessionDataStore
{
if (LOG.isDebugEnabled())
LOG.debug("Deleting session with id {} from infinispan", id);
return (_cache.remove(getCacheKey(id, _context)) != null);
return (_cache.remove(getCacheKey(id)) != null);
}
/**
@ -143,8 +143,8 @@ public class InfinispanSessionDataStore extends AbstractSessionDataStore
Set<String> expired = new HashSet<String>();
//TODO if there is NOT an idle timeout set, need to check other sessions that
//might have expired
//TODO if there is NOT an idle timeout set on entries in infinispan, need to check other sessions
//that are not currently in the SessionStore (eg they've been passivated)
for (String candidate:candidates)
{
@ -212,18 +212,13 @@ public class InfinispanSessionDataStore extends AbstractSessionDataStore
//scavenges the session before this timeout occurs, the session will be removed.
//NOTE: that no session listeners can be called for this.
if (data.getMaxInactiveMs() > 0 && getInfinispanIdleTimeoutSec() > 0)
_cache.put(getCacheKey(id, _context), data, -1, TimeUnit.MILLISECONDS, getInfinispanIdleTimeoutSec(), TimeUnit.SECONDS);
_cache.put(getCacheKey(id), data, -1, TimeUnit.MILLISECONDS, getInfinispanIdleTimeoutSec(), TimeUnit.SECONDS);
else
_cache.put(getCacheKey(id, _context), data);
_cache.put(getCacheKey(id), data);
if (LOG.isDebugEnabled())
LOG.debug("Session {} saved to infinispan, expires {} ", id, data.getExpiry());
//tickle the session id manager to keep the sessionid entry for this session up-to-date
if (_idMgr != null && _idMgr instanceof InfinispanSessionIdManager)
{
((InfinispanSessionIdManager)_idMgr).touch(id);
}
}
@ -232,9 +227,9 @@ public class InfinispanSessionDataStore extends AbstractSessionDataStore
* @param context
* @return
*/
public static String getCacheKey (String id, SessionContext context)
public String getCacheKey (String id)
{
return context.getCanonicalContextPath()+"_"+context.getVhost()+"_"+id;
return _context.getCanonicalContextPath()+"_"+_context.getVhost()+"_"+id;
}
@ -263,6 +258,53 @@ public class InfinispanSessionDataStore extends AbstractSessionDataStore
/**
* @see org.eclipse.jetty.server.session.SessionDataStore#exists(java.lang.String)
*/
@Override
public boolean exists(String id) throws Exception
{
// TODO find a better way to do this that does not pull into memory the
// whole session object
final AtomicReference<Boolean> reference = new AtomicReference<Boolean>();
final AtomicReference<Exception> exception = new AtomicReference<Exception>();
Runnable load = new Runnable()
{
public void run ()
{
try
{
SessionData sd = load(id);
if (sd == null)
{
reference.set(Boolean.FALSE);
return;
}
if (sd.getExpiry() <= 0)
reference.set(Boolean.TRUE); //never expires
else
reference.set(Boolean.valueOf(sd.getExpiry() > System.currentTimeMillis())); //not expired yet
}
catch (Exception e)
{
exception.set(e);
}
}
};
//ensure the load runs in the context classloader scope
_context.run(load);
if (exception.get() != null)
throw exception.get();
return reference.get();
}
/**
* @param sec the infinispan-specific idle timeout in sec or 0 if not set
*/

View File

@ -1,291 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2016 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.session.infinispan;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.session.AbstractSessionIdManager;
import org.eclipse.jetty.server.session.Session;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.infinispan.commons.api.BasicCache;
/**
* InfinispanSessionIdManager
*
* Maintain a set of in-use session ids. This session id manager does NOT locally store
* a list of in-use sesssion ids, but rather stores them in the cluster cache. Thus,
* all operations to this session manager involve interaction with a possibly remote
* cache.
*
* For each session id that is in-use, an entry of the following form is put into
* the cluster cache:
* <pre>
* ("__o.e.j.s.infinispanIdMgr__"+[id], [id])
* </pre>
* where [id] is the id of the session.
*
* If the first session to be added is not immortal (ie it has a timeout on it) then
* the corresponding session id is entered into infinispan with an idle expiry timeout
* equivalent to double the session's timeout (the multiplier is configurable).
*
*
* Having one entry per in-use session id means that there is no contention on
* cache entries (as would be the case if a single entry was kept containing a
* list of in-use session ids).
*
*
*/
public class InfinispanSessionIdManager extends AbstractSessionIdManager
{
private final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session");
public final static String ID_KEY = "__o.e.j.s.infinispanIdMgr__";
protected BasicCache<String,Object> _cache;
private int _infinispanIdleTimeoutSec = 0;
public InfinispanSessionIdManager(Server server)
{
super(server);
}
public InfinispanSessionIdManager(Server server, Random random)
{
super(server, random);
}
/**
* Start the id manager.
* @see org.eclipse.jetty.server.session.AbstractSessionIdManager#doStart()
*/
@Override
protected void doStart() throws Exception
{
super.doStart();
}
/**
* Stop the id manager
* @see org.eclipse.jetty.server.session.AbstractSessionIdManager#doStop()
*/
@Override
protected void doStop() throws Exception
{
super.doStop();
}
/**
* Check to see if the given session id is being
* used by a session in any context.
*
* This method will consult the cluster.
*
* @see org.eclipse.jetty.server.SessionIdManager#isIdInUse(java.lang.String)
*/
@Override
public boolean isIdInUse(String id)
{
if (id == null)
return false;
String clusterId = getId(id);
//ask the cluster - this should also tickle the idle expiration timer on the sessionid entry
//keeping it valid
try
{
return exists(clusterId);
}
catch (Exception e)
{
LOG.warn("Problem checking inUse for id="+clusterId, e);
return false;
}
}
public void setInfinispanIdleTimeoutSec (int sec)
{
if (sec <= 1)
{
LOG.warn("Idle expiry multiple of {} for session ids set to less than minimum. Using value of {} instead.", sec, 0);
_infinispanIdleTimeoutSec = 0;
}
else
_infinispanIdleTimeoutSec = sec;
}
public int getInfinispanIdleTimeoutSec()
{
return _infinispanIdleTimeoutSec;
}
/**
* Get the cache.
* @return the cache
*/
public BasicCache<String,Object> getCache()
{
return _cache;
}
/**
* Set the cache.
* @param cache the cache
*/
public void setCache(BasicCache<String,Object> cache)
{
this._cache = cache;
}
/**
* Do any operation to the session id in the cache to
* ensure its idle expiry time moves forward
* @param id the session id
*/
public void touch (String id)
{
exists(id);
}
/**
* Ask the cluster if a particular id exists.
*
* @param id the session id
* @return true if exists
*/
protected boolean exists (String id)
{
if (_cache == null)
throw new IllegalStateException ("No cache");
return _cache.containsKey(makeKey(id));
}
/**
* Put a session id into the cluster.
*
* @param id the session id
*/
protected void insert (String id)
{
if (_cache == null)
throw new IllegalStateException ("No cache");
_cache.putIfAbsent(makeKey(id), id);
}
/**
* Put a session id into the cluster with an idle expiry.
*
* @param id the session id
* @param idleTimeOutSec idle timeout in seconds
*/
protected void insert (String id, long idleTimeOutSec)
{
if (_cache == null)
throw new IllegalStateException ("No cache");
_cache.putIfAbsent(makeKey(id),id,-1L, TimeUnit.SECONDS, idleTimeOutSec, TimeUnit.SECONDS);
}
/**
* Remove a session id from the cluster.
*
* @param id the session id
*/
protected boolean delete (String id)
{
if (_cache == null)
throw new IllegalStateException ("No cache");
return _cache.remove(makeKey(id)) != null;
}
/**
* Generate a unique cache key from the session id.
*
* @param id the session id
* @return unique cache id
*/
public String makeKey (String id)
{
return ID_KEY+id;
}
/**
* @see org.eclipse.jetty.server.SessionIdManager#useId(Session)
*/
@Override
public void useId(Session session)
{
if (session == null)
return;
if (session.getMaxInactiveInterval() > 0 && getInfinispanIdleTimeoutSec() > 0)
insert (session.getId(), getInfinispanIdleTimeoutSec());
else
insert (session.getId());
}
/**
* @see org.eclipse.jetty.server.SessionIdManager#removeId(java.lang.String)
*/
@Override
public boolean removeId(String id)
{
return delete (id);
}
}

View File

@ -1,19 +0,0 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<!-- ===================================================================== -->
<!-- Configure a MongoSessionIdManager -->
<!-- ===================================================================== -->
<Set name="sessionIdManager">
<New id="sessionIdMgr" class="org.eclipse.jetty.nosql.mongodb.MongoSessionIdManager">
<Arg>
<Ref refid="Server"/>
</Arg>
<Set name="workerName"><Property name="jetty.nosqlSession.workerName" default="node1"/></Set>
<Set name="scavengePeriod"><Property name="jetty.nosqlSession.scavenge" default="1800"/></Set>
</New>
</Set>
</Configure>

View File

@ -11,20 +11,9 @@ maven://org.mongodb/mongo-java-driver/2.6.1|lib/nosql/mongo-java-driver-2.6.1.ja
lib/jetty-nosql-${jetty.version}.jar
lib/nosql/*.jar
[xml]
etc/jetty-nosql.xml
[license]
The java driver for the MongoDB document-based database system is hosted on GitHub and released under the Apache 2.0 license.
http://www.mongodb.org/
http://www.apache.org/licenses/LICENSE-2.0.html
[ini-template]
## MongoDB SessionIdManager config
## Unique identifier for this node in the cluster
# jetty.nosqlSession.workerName=node1
## Interval in seconds between scavenging expired sessions
# jetty.nosqlSession.scavenge=1800

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<!-- ===================================================================== -->
<!-- Get a reference to the session collection -->
<!-- ===================================================================== -->
<New class="com.mongodb.Mongo">
<Call id="sessiondb" name="getDB">
<Arg>HttpSessions</Arg>
<Call id="sessioncollection" name="getCollection">
<Arg>sessions</Arg>
</Call>
</Call>
</New>
<Get name="sessionHandler">
<Set name="sessionManager">
<New class="org.eclipse.jetty.nosql.mongodb.MongoSessionManager">
<Set name="maxInactiveInterval">seconds</Set>
<Get name="sessionDataStore">
<Set name="dBCollection">
<Ref id="sessioncollection"/>
</Set>
</Get>
<Get name="sessionStore">
<Set name="idlePassivationTimeoutSec">seconds</Set>
<Set name="expiryTimeoutSec">seconds</Set>
</Get>
</New>
</Set>
</Get>
</Configure>

View File

@ -315,6 +315,35 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore
}
/**
* @see org.eclipse.jetty.server.session.SessionDataStore#exists(java.lang.String)
*/
@Override
public boolean exists(String id) throws Exception
{
DBObject fields = new BasicDBObject();
fields.put(__EXPIRY, 1);
fields.put(__VALID, 1);
DBObject sessionDocument = _dbSessions.findOne(new BasicDBObject(__ID, id), fields);
if (sessionDocument == null)
return false; //doesn't exist
Boolean valid = (Boolean)sessionDocument.get(__VALID);
if (!valid)
return false; //invalid - nb should not happen
Long expiry = (Long)sessionDocument.get(__EXPIRY);
if (expiry.longValue() <= 0)
return false; //never expires, its good
return (expiry.longValue() > System.currentTimeMillis()); //expires later
}
/**
* @see org.eclipse.jetty.server.session.SessionDataStore#getExpired(Set, int)
*/

View File

@ -1,177 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2016 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.nosql.mongodb;
import java.net.UnknownHostException;
import java.util.Random;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.session.AbstractSessionIdManager;
import org.eclipse.jetty.server.session.Session;
import org.eclipse.jetty.util.ConcurrentHashSet;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import com.mongodb.BasicDBObject;
import com.mongodb.BasicDBObjectBuilder;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.Mongo;
import com.mongodb.MongoException;
/**
* Manager of session ids based on sessions stored in Mongo.
*
*/
public class MongoSessionIdManager extends AbstractSessionIdManager
{
private final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session");
final static DBObject __version_1 = new BasicDBObject(MongoSessionDataStore.__VERSION,1);
final static DBObject __valid_false = new BasicDBObject(MongoSessionDataStore.__VALID,false);
final static DBObject __valid_true = new BasicDBObject(MongoSessionDataStore.__VALID,true);
final static DBObject __expiry = new BasicDBObject(MongoSessionDataStore.__EXPIRY, 1);
final DBCollection _sessions;
/**
* the collection of session ids known to this manager
*/
protected final Set<String> _sessionsIds = new ConcurrentHashSet<>();
/* ------------------------------------------------------------ */
public MongoSessionIdManager(Server server) throws UnknownHostException, MongoException
{
this(server, new Mongo().getDB("HttpSessions").getCollection("sessions"));
}
/* ------------------------------------------------------------ */
public MongoSessionIdManager(Server server, DBCollection sessions)
{
super(server, new Random());
_sessions = sessions;
_sessions.ensureIndex(
BasicDBObjectBuilder.start().add("id",1).get(),
BasicDBObjectBuilder.start().add("unique",true).add("sparse",false).get());
_sessions.ensureIndex(
BasicDBObjectBuilder.start().add("id",1).add("version",1).get(),
BasicDBObjectBuilder.start().add("unique",true).add("sparse",false).get());
// index our accessed and valid fields so that purges are faster, note that the "valid" field is first
// so that we can take advantage of index prefixes
// http://docs.mongodb.org/manual/core/index-compound/#compound-index-prefix
_sessions.ensureIndex(
BasicDBObjectBuilder.start().add(MongoSessionDataStore.__VALID, 1).add(MongoSessionDataStore.__ACCESSED, 1).get(),
BasicDBObjectBuilder.start().add("sparse", false).add("background", true).get());
}
/* ------------------------------------------------------------ */
public DBCollection getSessions()
{
return _sessions;
}
/* ------------------------------------------------------------ */
@Override
protected void doStart() throws Exception
{
if (LOG.isDebugEnabled()) LOG.debug("MongoSessionIdManager:starting");
super.doStart();
}
/* ------------------------------------------------------------ */
@Override
protected void doStop() throws Exception
{
if (LOG.isDebugEnabled()) LOG.debug("MongoSessionIdManager:stopping");
super.doStop();
}
/* ------------------------------------------------------------ */
/**
* Searches database to find if the session id known to mongo, and is it valid
*/
@Override
public boolean isIdInUse(String sessionId)
{
/*
* optimize this query to only return the valid and expiry
*/
DBObject fields = new BasicDBObject();
fields.put(MongoSessionDataStore.__VALID, new Long(1));
fields.put(MongoSessionDataStore.__EXPIRY, new Long(1));
DBObject o = _sessions.findOne(new BasicDBObject(MongoSessionDataStore.__ID,sessionId), fields);
if ( o != null )
{
Boolean valid = (Boolean)o.get(MongoSessionDataStore.__VALID);
if ( valid == null )
return false;
Long expiry = (Long)o.get(MongoSessionDataStore.__EXPIRY);
if (expiry < System.currentTimeMillis())
return false;
return valid;
}
return false;
}
/* ------------------------------------------------------------ */
@Override
public void useId(Session session)
{
if (session == null)
return;
/*
* already a part of the index in mongo...
*/
LOG.debug("MongoSessionIdManager:addSession {}", session.getId());
}
/* ------------------------------------------------------------ */
@Override
public boolean removeId(String id)
{
//The corresponding session document will be marked as expired or invalid?
return true; //can't distinguish first remove vs subsequent removes
}
}

View File

@ -110,22 +110,10 @@ public class MongoSessionManager extends SessionManager
public void doStart() throws Exception
{
((AbstractSessionStore)_sessionStore).setSessionDataStore(_sessionDataStore);
_sessionDataStore.setDBCollection(_dbSessions);
super.doStart();
}
/* ------------------------------------------------------------ */
@Override
public void setSessionIdManager(SessionIdManager metaManager)
{
MongoSessionIdManager msim = (MongoSessionIdManager)metaManager;
_dbSessions=msim.getSessions();
super.setSessionIdManager(metaManager);
}
{
}
public MongoSessionDataStore getSessionDataStore()
{

View File

@ -34,8 +34,7 @@ import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.session.AbstractSessionIdManager;
import org.eclipse.jetty.server.session.HashSessionIdManager;
import org.eclipse.jetty.server.session.DefaultSessionIdManager;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.junit.After;
@ -99,7 +98,7 @@ public class BalancerServletTest
if (nodeName != null)
{
AbstractSessionIdManager sessionIdManager = new HashSessionIdManager(server);
DefaultSessionIdManager sessionIdManager = new DefaultSessionIdManager(server);
sessionIdManager.setWorkerName(nodeName);
server.setSessionIdManager(sessionIdManager);
}

View File

@ -1,38 +0,0 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<!-- ===================================================================== -->
<!-- Configure a SessionIdManager -->
<!-- ===================================================================== -->
<Set name="sessionIdManager">
<New id="idMgr" class="org.eclipse.jetty.server.session.JDBCSessionIdManager">
<Arg>
<Ref refid="Server"/>
</Arg>
<Set name="workerName"><Property name="jetty.jdbcSession.workerName" default="node1"/></Set>
<Set name="sessionScavenger">
<New class="org.eclipse.jetty.server.session.SessionScavenger">
<Set name="scavengeIntervalSec"><Property name="jetty.jdbcSession.scavenge" default="1800"/></Set>
</New>
</Set>
<!-- ===================================================================== -->
<!-- Uncomment either the datasource or driver setup and configure -->
<!-- ===================================================================== -->
<Get name="databaseAdaptor">
<!--
<Set name="DatasourceName"><Property name="jetty.jdbcSession.datasource" default="javax.sql.DataSource/default"/></Set>
-->
<!--
<Call name="setDriverInfo">
<Arg><Property name="jetty.jdbcSession.driverClass"/></Arg>
<Arg><Property name="jetty.jdbcSession.connectionURL"/></Arg>
</Call>
-->
</Get>
</New>
</Set>
</Configure>

View File

@ -0,0 +1,27 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<!-- ===================================================================== -->
<!-- Configure a SessionIdManager -->
<!-- ===================================================================== -->
<Set name="sessionIdManager">
<New id="idMgr" class="org.eclipse.jetty.server.session.DefaultSessionIdManager">
<Arg>
<Ref refid="Server"/>
</Arg>
<Set name="workerName"><Property name="jetty.sessionIdManager.workerName" default="node1"/></Set>
<!-- ===================================================================== -->
<!-- Configure a session inspector to help with scavenging -->
<!-- ===================================================================== -->
<Set name="sessionInspector">
<New id="idMgr" class="org.eclipse.jetty.server.session.PeriodicSessionInspector">
<Set name="intervalSec"><Property name="jetty.sessionInspectionInterval.seconds" default="60"/></Set>
</New>
</Set>
</New>
</Set>
</Configure>

View File

@ -1,25 +0,0 @@
[description]
Enables JDBC Session management.
[depend]
annotations
webapp
[xml]
etc/jetty-jdbc-sessions.xml
[ini-template]
## JDBC Session config
## Unique identifier for this node in the cluster
# jetty.jdbcSession.workerName=node1
## The interval in seconds between sweeps of the scavenger
# jetty.jdbcSession.scavenge=600
## Uncomment either the datasource name or driverClass and connectionURL
# jetty.jdbcSession.datasource=sessions
# jetty.jdbcSession.driverClass=changeme
# jetty.jdbcSession.connectionURL=changeme

View File

@ -76,3 +76,8 @@ etc/jetty.xml
## Dump the state of the Jetty server, components, and webapps before shutdown
# jetty.server.dumpBeforeStop=false
## The name to uniquely identify this server instance
#jetty.defaultSessionIdManager.workerName=node1
## How frequently sessions are inspected
#jetty.sessionInspectionInterval.seconds=60

View File

@ -0,0 +1,13 @@
[description]
Enables basic sessions.
[xml]
etc/jetty-sessions.xml
[ini-template]
## The name to uniquely identify this server instance
#jetty.sssionIdManager.workerName=node1
## How frequently sessions are inspected
#jetty.sessionInspectionInterval.seconds=60

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Get name="sessionHandler">
<Set name="sessionManager">
<New class="org.eclipse.jetty.server.session.FileSessionManager">
<Set name="maxInactiveInterval">seconds</Set>
<Get name="sessionDataStore">
<Set name="storeDir">filename</Set>
<Set name="deleteUnrestorableFiles">boolean</Set>
</Get>
<Get name="sessionStore">
<Set name="idlePassivationTimeoutSec">seconds</Set>
<Set name="expiryTimeoutSec">seconds</Set>
</Get>
</New>
</Set>
</Get>
</Configure>

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Get name="sessionHandler">
<Set name="sessionManager">
<New class="org.eclipse.jetty.server.session.JDBCSessionManager">
<Set name="maxInactiveInterval">seconds</Set>
<Get name="sessionDataStore">
<Set name="gracePeriod">seconds</Set>
<Set name="loadAttempts">integer</Set>
<Set name="deleteUnloadableSessions">boolean</Set>
<Set name="databaseAdaptor">
<New class="org.eclipse.jetty.server.session.DatabaseAdaptor">
<!-- or alternative -->
<Call name="setDriverInfo">
<Arg>driver class</Arg>
<Arg>URL</Arg>
</Call>
</New>
</Set>
<Set name="sessionTableSchema">
<New class="org.eclipse.jetty.server.session.JDBCSessionDataStore.SessionTableSchema">
<Set name="tableName">JettySessions</Set>
<Set name="idColumn">sessionId</Set>
<Set name="accessTimeColumn">accessTime</Set>
<Set name="contextPathColumn">contextPath</Set>
<Set nmae="cookieTimeColumn">cookieTime</Set>
<Set name="createTimeColumn">createTime</Set>
<Set name="expiryTimeColumn">expiryTime</Set>
<Set name="lastAccessTimeColumn">lastAccessTime</Set>
<Set name="lastNodeColumn">lastNode</Set>
<Set name="lastSavedTimeColumn">lastSavedTime</Set>
<Set name="mapColumn">map</Set>
<Set name="maxIntervalColumn">maxInterval</Set>
<Set name="virtualHostColumn">virtualHost</Set>
</New>
</Get>
<Get name="sessionStore">
<Set name="idlePassivationTimeoutSec">seconds</Set>
<Set name="expiryTimeoutSec">seconds</Set>
</Get>
</New>
</Set>
</Get>
</Configure>

View File

@ -35,29 +35,24 @@ public interface SessionIdManager extends LifeCycle
*/
public boolean isIdInUse(String id);
/* ------------------------------------------------------------ */
/**
* Notify the sessionid manager that a particular session id is in use
* @param session the session whose id is being used
*/
public void useId (Session session);
/* ------------------------------------------------------------ */
/**
* Remove id
* @param id the plain session id (no workername extension) of the session to remove
* @return true if the id was removed, false otherwise
* Expire all sessions on all contexts that share the same id.
*
* @param id The session ID without any cluster node extension
*/
public boolean removeId (String id);
public void expireAll(String id);
/* ------------------------------------------------------------ */
/**
* Invalidate all sessions on all contexts that share the same id.
*
* @param id The session ID without any cluster node extension
* @param id
*/
public void expireAll(String id);
public void invalidateAll (String id);
/* ------------------------------------------------------------ */
/**

View File

@ -312,4 +312,14 @@ public interface SessionManager extends LifeCycle
public SessionStore getSessionStore();
/**
* Check if id is in use by this manager
*
* @param id identity of session to check
*
* @return true if this manager knows about this id
*/
public boolean isIdInUse (String id) throws Exception;
}

View File

@ -146,4 +146,5 @@ public abstract class AbstractSessionDataStore extends AbstractLifeCycle impleme
{
_gracePeriodSec = sec;
}
}

View File

@ -92,15 +92,6 @@ public abstract class AbstractSessionStore extends AbstractLifeCycle implements
/**
* Check to see if the session exists in the store
* @param id the id
* @return true if the Session object exists in the session store
*/
public abstract boolean doExists (String id);
/**
* Remove the session with this identity from the store
* @param id the id
@ -348,7 +339,6 @@ public abstract class AbstractSessionStore extends AbstractLifeCycle implements
catch (Exception e)
{
ex = e; //remember a problem happened loading the session
LOG.warn(e);
doDelete(id); //remove the placeholder
phsLock.close();
session = null;
@ -412,14 +402,23 @@ public abstract class AbstractSessionStore extends AbstractLifeCycle implements
if (_sessionDataStore == null)
return null; //can't load it
data =_sessionDataStore.load(id);
try
{
data =_sessionDataStore.load(id);
if (data == null) //session doesn't exist
return null;
if (data == null) //session doesn't exist
return null;
session = newSession(data);
session.setSessionManager(_manager);
return session;
session = newSession(data);
session.setSessionManager(_manager);
return session;
}
catch (UnreadableSessionDataException e)
{
//can't load the session, delete it
_sessionDataStore.delete(id);
throw e;
}
}
/**
@ -512,14 +511,31 @@ public abstract class AbstractSessionStore extends AbstractLifeCycle implements
}
/**
* Check to see if the session object exists in this store.
* Check to see if a session corresponding to the id exists.
*
* This method will first check with the object store. If it
* doesn't exist in the object store (might be passivated etc),
* it will check with the data store.
* @throws Exception
*
* @see org.eclipse.jetty.server.session.SessionStore#exists(java.lang.String)
*/
@Override
public boolean exists(String id)
public boolean exists(String id) throws Exception
{
return doExists(id);
//try the object store first
Session s = doGet(id);
if (s != null)
{
try (Lock lock = s.lock())
{
//wait for the lock and check the validity of the session
return s.isValid();
}
}
//not there, so find out if session data exists for it
return _sessionDataStore.exists (id);
}

View File

@ -167,6 +167,13 @@ public class CachingSessionDataStore extends AbstractSessionDataStore
return true;
}
/**
* @see org.eclipse.jetty.server.session.SessionDataStore#exists(java.lang.String)
*/
@Override
public boolean exists(String id) throws Exception
{
// TODO Auto-generated method stub
return false;
}
}

View File

@ -22,6 +22,7 @@ import java.security.SecureRandom;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
import javax.servlet.http.HttpServletRequest;
@ -43,12 +44,14 @@ import org.eclipse.jetty.util.log.Logger;
*
* There is only 1 session id manager per Server instance.
*/
public abstract class AbstractSessionIdManager extends AbstractLifeCycle implements SessionIdManager
public class DefaultSessionIdManager extends AbstractLifeCycle implements SessionIdManager
{
private final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session");
private final static String __NEW_SESSION_ID="org.eclipse.jetty.server.newSessionId";
protected static final AtomicLong COUNTER = new AtomicLong();
protected Random _random;
protected boolean _weakRandom;
protected String _workerName;
@ -57,11 +60,12 @@ public abstract class AbstractSessionIdManager extends AbstractLifeCycle impleme
protected Server _server;
protected PeriodicSessionInspector _inspector;
/* ------------------------------------------------------------ */
/**
* @param server the server associated with the id manager
*/
public AbstractSessionIdManager(Server server)
public DefaultSessionIdManager(Server server)
{
_server = server;
}
@ -71,7 +75,7 @@ public abstract class AbstractSessionIdManager extends AbstractLifeCycle impleme
* @param server the server associated with the id manager
* @param random a random number generator to use for ids
*/
public AbstractSessionIdManager(Server server, Random random)
public DefaultSessionIdManager(Server server, Random random)
{
this(server);
_random=random;
@ -226,7 +230,7 @@ public abstract class AbstractSessionIdManager extends AbstractLifeCycle impleme
{
// pick a new unique ID!
String id=null;
while (id==null||id.length()==0||isIdInUse(id))
while (id==null||id.length()==0)
{
long r0=_weakRandom
?(hashCode()^Runtime.getRuntime().freeMemory()^_random.nextInt()^((seedTerm)<<32))
@ -263,12 +267,53 @@ public abstract class AbstractSessionIdManager extends AbstractLifeCycle impleme
if (_workerName!=null)
id=_workerName + id;
id = id+Long.toString(COUNTER.getAndIncrement());
}
return id;
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.server.SessionIdManager#isIdInUse(java.lang.String)
*/
@Override
public boolean isIdInUse(String id)
{
if (id == null)
return false;
boolean inUse = false;
if (LOG.isDebugEnabled())
LOG.debug("Checking {} is in use by at least one context",id);
try
{
for (SessionManager manager:getSessionManagers())
{
if (manager.isIdInUse(id))
{
if (LOG.isDebugEnabled())
LOG.debug("Context {} reports id in use", manager.getContext());
inUse = true;
break;
}
}
if (LOG.isDebugEnabled())
LOG.debug("Checked {}, in use:", id, inUse);
return inUse;
}
catch (Exception e)
{
LOG.warn("Problem checking if id {} is in use", e);
return false;
}
}
/* ------------------------------------------------------------ */
/**
@ -379,19 +424,6 @@ public abstract class AbstractSessionIdManager extends AbstractLifeCycle impleme
if (LOG.isDebugEnabled())
LOG.debug("Expiring {}",id);
//TODO handle cases:
//1. infinispan session id manager may not be able to remove id because it has timed out in infinispan but yet
//we want to remove a session object from the session store (session data store probably ok because it has same timeout as session id mgr entries)
//2. a session id manager may not know all session ids (ie subset in memory only) and therefore won't remove
//it, but it should be removed from the session data store (could it be in session store?)
//3. old sessions that no node is handling, eg after all restarted, but need to be removed from
//session data store, AND have listeners called on them.
//BUT want to avoid loading into memory sessions that this node is not managing (eg have 3 nodes all running session mgrs,
//all 3 find the expired session and load it into memory and expire it
removeId(id);
//tell all contexts that may have a session object with this id to
//get rid of them
for (SessionManager manager:getSessionManagers())
{
manager.invalidate(id);
@ -399,11 +431,11 @@ public abstract class AbstractSessionIdManager extends AbstractLifeCycle impleme
}
/* ------------------------------------------------------------ */
/**
* @param id
*/
public void invalidateAll (String id)
{
//take the id out of the list of known sessionids for this node
removeId(id);
//tell all contexts that may have a session object with this id to
//get rid of them
for (SessionManager manager:getSessionManagers())
@ -425,7 +457,7 @@ public abstract class AbstractSessionIdManager extends AbstractLifeCycle impleme
//generate a new id
String newClusterId = newSessionId(request.hashCode());
removeId(oldClusterId);//remove the old one from the list
//TODO how to handle request for old id whilst id change is happening?
//tell all contexts to update the id
for (SessionManager manager:getSessionManagers())

View File

@ -117,9 +117,6 @@ public class FileSessionDataStore extends AbstractSessionDataStore
@Override
public Set<String> doGetExpired(final Set<String> candidates, final int expiryTimeoutSec)
{
//we don't want to open up each file and check, so just leave it up to the SessionStore
//TODO as the session manager is likely to be a lazy loader, if a session is never requested, its
//file will stay forever after a restart
final long now = System.currentTimeMillis();
HashSet<String> expired = new HashSet<String>();
@ -273,6 +270,27 @@ public class FileSessionDataStore extends AbstractSessionDataStore
return true;
}
/**
* @see org.eclipse.jetty.server.session.SessionDataStore#exists(java.lang.String)
*/
@Override
public boolean exists(String id) throws Exception
{
File sessionFile = getFile(_storeDir, id);
if (sessionFile == null || !sessionFile.exists())
return false;
//check the expiry
long expiry = getExpiryFromFile(sessionFile);
if (expiry <= 0)
return true; //never expires
else
return (expiry > System.currentTimeMillis()); //hasn't yet expired
}
/* ------------------------------------------------------------ */
/**
* @param os the output stream to save to
@ -318,6 +336,10 @@ public class FileSessionDataStore extends AbstractSessionDataStore
return ""+data.getExpiry()+"_"+getFileName(data.getId());
}
/**
* @param file
* @return
*/
private String getIdFromFile (File file)
{
if (file == null)
@ -327,6 +349,20 @@ public class FileSessionDataStore extends AbstractSessionDataStore
return name.substring(name.lastIndexOf('_')+1);
}
/**
* @param file
* @return
*/
private long getExpiryFromFile (File file)
{
if (file == null)
return 0;
String name = file.getName();
String s = name.substring(0, name.indexOf('_'));
return (s==null?0:Long.parseLong(s));
}
/**
* Find a File for the session id for the current context.

View File

@ -1,77 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2016 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.util.Set;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.ConcurrentHashSet;
/**
* HashSessionIdManager
*
*
*/
public class HashSessionIdManager extends AbstractSessionIdManager
{
/**
* @param server the server
*/
public HashSessionIdManager(Server server)
{
super(server);
}
private final Set<String> _ids = new ConcurrentHashSet<String>();
/**
* @see org.eclipse.jetty.server.SessionIdManager#isIdInUse(java.lang.String)
*/
@Override
public boolean isIdInUse(String id)
{
return _ids.contains(id);
}
/**
* @see org.eclipse.jetty.server.SessionIdManager#useId(org.eclipse.jetty.server.session.Session)
*/
@Override
public void useId(Session session)
{
if (session == null)
return;
_ids.add(session.getId());
}
/**
* @see org.eclipse.jetty.server.SessionIdManager#removeId(java.lang.String)
*/
@Override
public boolean removeId(String id)
{
return _ids.remove(id);
}
}

View File

@ -1090,6 +1090,44 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
{
return true;
}
/**
* @see org.eclipse.jetty.server.session.SessionDataStore#exists(java.lang.String)
*/
@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.getCanonicalContextPath()))
{
_sessionTableSchema.fillCheckSessionExistsStatement (checkSessionExists, id, _context);
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
}
}
}
}
}
}

View File

@ -1,391 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2016 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.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.Random;
import javax.servlet.http.HttpServletRequest;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/**
* JDBCSessionIdManager
*
* SessionIdManager implementation that uses a database to store in-use session ids,
* to support distributed sessions.
*
*/
public class JDBCSessionIdManager extends org.eclipse.jetty.server.session.AbstractSessionIdManager
{
private final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session");
public final static int MAX_INTERVAL_NOT_SET = -999;
protected final HashSet<String> _sessionIds = new HashSet<String>();
protected Server _server;
protected PeriodicSessionInspector _scavenger;
private DatabaseAdaptor _dbAdaptor = new DatabaseAdaptor();
protected SessionIdTableSchema _sessionIdTableSchema = new SessionIdTableSchema();
/**
* SessionIdTableSchema
*
*/
public static class SessionIdTableSchema
{
protected String _tableName = "JettySessionIds";
protected String _idColumn = "id";
protected DatabaseAdaptor _jdbc;
public String getIdColumn()
{
return _idColumn;
}
public void setIdColumn(String idColumn)
{
checkNotNull(idColumn);
_idColumn = idColumn;
}
public String getTableName()
{
return _tableName;
}
public void setTableName(String tableName)
{
checkNotNull(tableName);
_tableName = tableName;
}
public String getInsertStatementAsString ()
{
return "insert into "+_tableName+" ("+_idColumn+") values (?)";
}
public String getDeleteStatementAsString ()
{
return "delete from "+_tableName+" where "+_idColumn+" = ?";
}
public String getSelectStatementAsString ()
{
return "select * from "+_tableName+" where "+_idColumn+" = ?";
}
public String getCreateStatementAsString ()
{
return "create table "+_tableName+" ("+_idColumn+" varchar(120), primary key("+_idColumn+"))";
}
protected void prepareTables (DatabaseAdaptor jdbc)
throws Exception
{
_jdbc = jdbc;
try (Connection connection = _jdbc.getConnection();
Statement statement = connection.createStatement())
{
//make the id table
connection.setAutoCommit(true);
DatabaseMetaData metaData = connection.getMetaData();
_jdbc.adaptTo(metaData);
//checking for table existence is case-sensitive, but table creation is not
String tableName = _jdbc.convertIdentifier(getTableName());
try (ResultSet result = metaData.getTables(null, null, tableName, null))
{
if (!result.next())
{
//table does not exist, so create it
statement.executeUpdate(getCreateStatementAsString());
}
}
}
}
private void checkNotNull(String s)
{
if (s == null)
throw new IllegalArgumentException(s);
}
}
public JDBCSessionIdManager(Server server)
{
super(server);
}
public JDBCSessionIdManager(Server server, Random random)
{
super(server,random);
}
public SessionIdTableSchema getSessionIdTableSchema()
{
return _sessionIdTableSchema;
}
/**
* @see org.eclipse.jetty.server.SessionIdManager#useId(org.eclipse.jetty.server.session.Session)
*/
@Override
public void useId (Session session)
{
if (session == null)
return;
synchronized (_sessionIds)
{
String id = session.getId();
try
{
insert(id);
_sessionIds.add(id);
}
catch (Exception e)
{
LOG.warn("Problem storing session id="+id, e);
}
}
}
/**
* Remove the id from in-use set
*
* Prevents another context from using this id
*
* @see org.eclipse.jetty.server.SessionIdManager#removeId(java.lang.String)
*/
@Override
public boolean removeId (String id)
{
if (id == null)
return false;
synchronized (_sessionIds)
{
if (LOG.isDebugEnabled())
LOG.debug("Removing sessionid="+id);
try
{
boolean remove = _sessionIds.remove(id);
boolean dbremove = delete(id);
return remove || dbremove;
}
catch (Exception e)
{
LOG.warn("Problem removing session id="+id, e);
return false;
}
}
}
/**
* Insert a new used session id into the table.
*
* @param id the id to put into the table
* @throws SQLException
*/
private void insert (String id)
throws SQLException
{
try (Connection connection = _dbAdaptor.getConnection();
PreparedStatement query = connection.prepareStatement(_sessionIdTableSchema.getSelectStatementAsString()))
{
connection.setAutoCommit(true);
query.setString(1, id);
try (ResultSet result = query.executeQuery())
{
//only insert the id if it isn't in the db already
if (!result.next())
{
try (PreparedStatement statement = connection.prepareStatement(_sessionIdTableSchema.getInsertStatementAsString()))
{
statement.setString(1, id);
statement.executeUpdate();
}
}
}
}
}
/**
* Remove a session id from the table.
*
* @param id the id to remove from the table
* @throws SQLException
*/
private boolean delete (String id)
throws SQLException
{
try (Connection connection = _dbAdaptor.getConnection();
PreparedStatement statement = connection.prepareStatement(_sessionIdTableSchema.getDeleteStatementAsString()))
{
connection.setAutoCommit(true);
statement.setString(1, id);
return (statement.executeUpdate() > 0);
}
}
/**
* Check if a session id exists.
*
* @param id the id to check
* @return true if the id exists in the table, false otherwise
* @throws SQLException
*/
private boolean exists (String id)
throws SQLException
{
try (Connection connection = _dbAdaptor.getConnection();
PreparedStatement statement = connection.prepareStatement(_sessionIdTableSchema.getSelectStatementAsString()))
{
connection.setAutoCommit(true);
statement.setString(1, id);
try (ResultSet result = statement.executeQuery())
{
return result.next();
}
}
}
@Override
public boolean isIdInUse(String id)
{
if (id == null)
return false;
String sessionId = getId(id);
boolean inUse = false;
synchronized (_sessionIds)
{
inUse = _sessionIds.contains(sessionId);
}
if (inUse)
return true; //optimisation - if this session is one we've been managing, we can check locally
//otherwise, we need to go to the database to check
try
{
return exists(sessionId);
}
catch (Exception e)
{
LOG.warn("Problem checking inUse for id="+sessionId, e);
return false;
}
}
/**
* Invalidate the session matching the id on all contexts.
*
* @see org.eclipse.jetty.server.SessionIdManager#expireAll(java.lang.String)
*/
@Override
public void expireAll(String id)
{
synchronized (_sessionIds)
{
super.expireAll(id);
}
}
@Override
public void renewSessionId(String oldClusterId, String oldNodeId, HttpServletRequest request)
{
synchronized (_sessionIds)
{
super.renewSessionId(oldClusterId, oldNodeId, request);
}
}
/**
* Get the database adaptor in order to configure it
* @return the database adpator
*/
public DatabaseAdaptor getDatabaseAdaptor ()
{
return _dbAdaptor;
}
/**
* Start up the id manager.
*
* Makes necessary database tables and starts a Session
* scavenger thread.
*/
@Override
public void doStart()
throws Exception
{
_dbAdaptor.initialize();
_sessionIdTableSchema.prepareTables(_dbAdaptor);
super.doStart();
}
/**
* Stop
*/
@Override
public void doStop ()
throws Exception
{
_sessionIds.clear();
super.doStop();
}
}

View File

@ -26,13 +26,11 @@ package org.eclipse.jetty.server.session;
public class JDBCSessionManager extends SessionManager
{
protected DatabaseAdaptor _db;
protected JDBCSessionDataStore _sessionDataStore;
public JDBCSessionManager()
{
_db = new DatabaseAdaptor();
_sessionStore = new MemorySessionStore();
_sessionDataStore = new JDBCSessionDataStore();
}
@ -40,7 +38,6 @@ public class JDBCSessionManager extends SessionManager
@Override
public void doStart() throws Exception
{
_sessionDataStore.setDatabaseAdaptor(_db);
((AbstractSessionStore)_sessionStore).setSessionDataStore(_sessionDataStore);
super.doStart();
@ -53,14 +50,7 @@ public class JDBCSessionManager extends SessionManager
}
/**
* Get the db adaptor to configure jdbc settings
* @return the database adaptor
*/
public DatabaseAdaptor getDatabaseAdaptor()
{
return _db;
}
/**
* Get the SessionDataStore to configure it

View File

@ -129,14 +129,7 @@ public class MemorySessionStore extends AbstractSessionStore
return s;
}
/**
* @see org.eclipse.jetty.server.session.AbstractSessionStore#doExists(java.lang.String)
*/
@Override
public boolean doExists(String id)
{
return _sessions.containsKey(id);
}
/**
* @see org.eclipse.jetty.server.session.AbstractSessionStore#doDelete(java.lang.String)

View File

@ -87,4 +87,14 @@ public class NullSessionDataStore extends AbstractSessionDataStore
return false;
}
/**
* @see org.eclipse.jetty.server.session.SessionDataStore#exists(java.lang.String)
*/
@Override
public boolean exists(String id)
{
return false;
}
}

View File

@ -93,12 +93,12 @@ public class PeriodicSessionInspector extends AbstractLifeCycle
if (_sessionIdManager == null)
throw new IllegalStateException ("No SessionIdManager for Scavenger");
if (!(_sessionIdManager instanceof AbstractSessionIdManager))
if (!(_sessionIdManager instanceof DefaultSessionIdManager))
throw new IllegalStateException ("SessionIdManager is not an AbstractSessionIdManager");
//try and use a common scheduler, fallback to own
_scheduler = ((AbstractSessionIdManager)_sessionIdManager).getServer().getBean(Scheduler.class);
_scheduler = ((DefaultSessionIdManager)_sessionIdManager).getServer().getBean(Scheduler.class);
if (_scheduler == null)
{
@ -199,7 +199,7 @@ public class PeriodicSessionInspector extends AbstractLifeCycle
LOG.debug("Inspecting sessions");
//find the session managers
for (SessionManager manager:((AbstractSessionIdManager)_sessionIdManager).getSessionManagers())
for (SessionManager manager:((DefaultSessionIdManager)_sessionIdManager).getSessionManagers())
{
if (manager != null)
{

View File

@ -452,10 +452,10 @@ public class Session implements SessionManager.SessionIf
checkLocked();
if (_state != State.VALID)
throw new IllegalStateException();
throw new IllegalStateException("Not valid for write: id="+_sessionData.getId()+" created="+_sessionData.getCreated()+" accessed="+_sessionData.getAccessed()+" lastaccessed="+_sessionData.getLastAccessed()+" maxInactiveMs="+_sessionData.getMaxInactiveMs()+" expiry="+_sessionData.getExpiry());
if (_passivationState == PassivationState.PASSIVATED)
throw new IllegalStateException("Passivated");
throw new IllegalStateException("Not valid for write: id="+_sessionData.getId()+" passivated");
}
@ -469,10 +469,10 @@ public class Session implements SessionManager.SessionIf
checkLocked();
if (_state == State.INVALID)
throw new IllegalStateException("Invalid");
throw new IllegalStateException("Invalid for read: id="+_sessionData.getId()+" created="+_sessionData.getCreated()+" accessed="+_sessionData.getAccessed()+" lastaccessed="+_sessionData.getLastAccessed()+" maxInactiveMs="+_sessionData.getMaxInactiveMs()+" expiry="+_sessionData.getExpiry());
if (_passivationState == PassivationState.PASSIVATED)
throw new IllegalStateException("Passivated");
throw new IllegalStateException("Invalid for read: id="+_sessionData.getId()+" passivated");
}
@ -723,7 +723,7 @@ public class Session implements SessionManager.SessionIf
if (result)
{
//tell id mgr to remove session from all other contexts
((AbstractSessionIdManager)_manager.getSessionIdManager()).invalidateAll(_sessionData.getId());
((DefaultSessionIdManager)_manager.getSessionIdManager()).invalidateAll(_sessionData.getId());
}
}
catch (Exception e)

View File

@ -106,4 +106,15 @@ public interface SessionDataStore extends LifeCycle
*/
public boolean isPassivating ();
/**
* Test if data exists for a given session id.
*
* @param id Identity of session whose existance should be checked
*
* @return true if valid, non-expired session exists
* @throws Exception if problem checking existance with persistence layer
*/
public boolean exists (String id) throws Exception;
}

View File

@ -267,7 +267,7 @@ public class SessionManager extends ContainerLifeCycle implements org.eclipse.je
try
{
Thread.currentThread().setContextClassLoader(serverLoader);
_sessionIdManager=new HashSessionIdManager(server);
_sessionIdManager=new DefaultSessionIdManager(server);
server.setSessionIdManager(_sessionIdManager);
server.manage(_sessionIdManager);
_sessionIdManager.start();
@ -595,7 +595,6 @@ public class SessionManager extends ContainerLifeCycle implements org.eclipse.je
{
_sessionStore.put(id, session);
_sessionsCreatedStats.increment();
_sessionIdManager.useId(session);
if (_sessionListeners!=null)
{
@ -749,9 +748,15 @@ public class SessionManager extends ContainerLifeCycle implements org.eclipse.je
catch (UnreadableSessionDataException e)
{
LOG.warn(e);
//Could not retrieve the session with the given id
//Tell the session id manager that the session id is not to be used by any other threads/contexts
_sessionIdManager.removeId(id);
try
{
//tell id mgr to remove session from all other contexts
getSessionIdManager().invalidateAll(id);
}
catch (Exception x)
{
LOG.warn("Error cross-context invalidating unreadable session {}", id, x);
}
return null;
}
catch (Exception other)
@ -967,7 +972,6 @@ public class SessionManager extends ContainerLifeCycle implements org.eclipse.je
}
session.setExtendedId(newExtendedId); //remember the extended id
_sessionIdManager.useId(session); //tell id manager new id is in use
//inform the listeners
if (!_sessionIdListeners.isEmpty())
@ -978,36 +982,6 @@ public class SessionManager extends ContainerLifeCycle implements org.eclipse.je
l.sessionIdChanged(event, oldId);
}
}
/* Session session =_sessionStore.get(oldId);
if (session == null)
{
LOG.warn("Unable to renew id to "+newId+" for non-existant session "+oldId);
return;
}
try (Lock lock = session.lock())
{
//swap the ids
session.renewId(oldId, oldExtendedId, newId, newExtendedId);
_sessionStore.put(newId, session);
//tell session id manager the id is in use
_sessionIdManager.useId(session);
//inform the listeners
if (!_sessionIdListeners.isEmpty())
{
HttpSessionEvent event = new HttpSessionEvent(session);
for (HttpSessionIdListener l:_sessionIdListeners)
{
l.sessionIdChanged(event, oldId);
}
}
}*/
}
catch (Exception e)
{
@ -1048,6 +1022,9 @@ public class SessionManager extends ContainerLifeCycle implements org.eclipse.je
/* ------------------------------------------------------------ */
/**
*
*/
public void inspect ()
{
//don't attempt to scavenge if we are shutting down
@ -1058,6 +1035,25 @@ public class SessionManager extends ContainerLifeCycle implements org.eclipse.je
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.server.SessionManager#isIdInUse(java.lang.String)
*/
@Override
public boolean isIdInUse(String id) throws Exception
{
//Ask the session store
return _sessionStore.exists(id);
}
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */

View File

@ -52,4 +52,5 @@ public interface SessionStore extends LifeCycle
int getExpiryTimeoutSec();
void setExpiryTimeoutSec(int sec);
Stream<Session> getStream();
SessionDataStore getSessionDataStore();
}

View File

@ -54,7 +54,7 @@ import org.eclipse.jetty.io.RuntimeIOException;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ErrorHandler;
import org.eclipse.jetty.server.session.HashSessionIdManager;
import org.eclipse.jetty.server.session.DefaultSessionIdManager;
import org.eclipse.jetty.server.session.HashSessionManager;
import org.eclipse.jetty.server.session.Session;
import org.eclipse.jetty.server.session.SessionData;
@ -511,7 +511,7 @@ public class ResponseTest
request.setRequestedSessionId("12345");
request.setRequestedSessionIdFromCookie(false);
HashSessionManager manager = new HashSessionManager();
manager.setSessionIdManager(new HashSessionIdManager(_server));
manager.setSessionIdManager(new DefaultSessionIdManager(_server));
request.setSessionManager(manager);
TestSession tsession = new TestSession(manager, "12345");
tsession.setExtendedId(manager.getSessionIdManager().getExtendedId("12345", null));
@ -588,7 +588,7 @@ public class ResponseTest
request.setRequestedSessionId("12345");
request.setRequestedSessionIdFromCookie(i>2);
HashSessionManager manager = new HashSessionManager();
manager.setSessionIdManager(new HashSessionIdManager(_server));
manager.setSessionIdManager(new DefaultSessionIdManager(_server));
request.setSessionManager(manager);
request.setSession(new TestSession(manager, "12345"));
manager.setCheckingRemoteSessionIdEncoding(false);

View File

@ -61,7 +61,7 @@ public class FileSessionManagerTest
Server server = new Server();
SessionHandler handler = new SessionHandler();
handler.setServer(server);
final HashSessionIdManager idmgr = new HashSessionIdManager(server);
final DefaultSessionIdManager idmgr = new DefaultSessionIdManager(server);
idmgr.setServer(server);
server.setSessionIdManager(idmgr);
@ -94,7 +94,7 @@ public class FileSessionManagerTest
Server server = new Server();
SessionHandler handler = new SessionHandler();
handler.setServer(server);
final HashSessionIdManager idmgr = new HashSessionIdManager(server);
final DefaultSessionIdManager idmgr = new DefaultSessionIdManager(server);
idmgr.setServer(server);
server.setSessionIdManager(idmgr);
final FileSessionManager manager = new FileSessionManager();
@ -135,7 +135,7 @@ public class FileSessionManagerTest
Assert.assertTrue(testDir.canWrite());
handler.setSessionManager(manager);
AbstractSessionIdManager idManager = new HashSessionIdManager(server);
DefaultSessionIdManager idManager = new DefaultSessionIdManager(server);
idManager.setServer(server);
idManager.setWorkerName("foo");
manager.setSessionIdManager(idManager);

View File

@ -90,15 +90,7 @@ public class SessionCookieTest
return null;
}
/**
* @see org.eclipse.jetty.server.session.AbstractSessionStore#doExists(String)
*/
@Override
public boolean doExists(String key)
{
// TODO Auto-generated method stub
return false;
}
/**
* @see org.eclipse.jetty.server.session.AbstractSessionStore#doDelete(String)
@ -134,7 +126,7 @@ public class SessionCookieTest
public class MockSessionIdManager extends AbstractSessionIdManager
public class MockSessionIdManager extends DefaultSessionIdManager
{
public MockSessionIdManager(Server server)
{
@ -165,25 +157,6 @@ public class SessionCookieTest
// TODO Auto-generated method stub
}
/**
* @see org.eclipse.jetty.server.SessionIdManager#useId(Session)
*/
@Override
public void useId(Session session)
{
// TODO Auto-generated method stub
}
/**
* @see org.eclipse.jetty.server.SessionIdManager#removeId(java.lang.String)
*/
@Override
public boolean removeId(String id)
{
return true;
}
}
public class MockSessionManager extends SessionManager

View File

@ -133,7 +133,7 @@ public class FileTestServer extends AbstractTestServer
public SessionIdManager newSessionIdManager(Object config)
{
HashSessionIdManager mgr = new HashSessionIdManager(_server);
DefaultSessionIdManager mgr = new DefaultSessionIdManager(_server);
mgr.setWorkerName("worker"+(__workers++));
return mgr;
}

View File

@ -22,6 +22,7 @@ import java.io.File;
import org.eclipse.jetty.server.SessionManager;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.webapp.WebAppContext;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@ -58,7 +59,7 @@ public class SessionRenewTest extends AbstractSessionRenewTest
* @see org.eclipse.jetty.server.session.AbstractSessionRenewTest#verifyChange(java.lang.String, java.lang.String)
*/
@Override
public boolean verifyChange(String oldSessionId, String newSessionId)
public boolean verifyChange(WebAppContext context, String oldSessionId, String newSessionId)
{
((FileTestServer)_server).assertFileExists(oldSessionId, false);
((FileTestServer)_server).assertFileExists(newSessionId, true);

View File

@ -23,6 +23,7 @@ import org.eclipse.jetty.server.SessionIdManager;
import org.eclipse.jetty.server.SessionManager;
import org.eclipse.jetty.server.session.AbstractSessionStore;
import org.eclipse.jetty.server.session.AbstractTestServer;
import org.eclipse.jetty.server.session.DefaultSessionIdManager;
import org.eclipse.jetty.server.session.SessionHandler;
import org.eclipse.jetty.server.session.StalePeriodStrategy;
@ -36,8 +37,6 @@ import com.google.gcloud.datastore.DatastoreFactory;
*/
public class GCloudTestServer extends AbstractTestServer
{
static int __workers=0;
static protected int __maxInactivePeriod = 30;
static protected int __scavengePeriod = 10;
static protected int __inspectPeriod = 1;
@ -65,17 +64,7 @@ public class GCloudTestServer extends AbstractTestServer
super(port, 30,10, __inspectPeriod, __idlePeriod, configuration);
}
/**
* @see org.eclipse.jetty.server.session.AbstractTestServer#newSessionIdManager(java.lang.Object)
*/
@Override
public SessionIdManager newSessionIdManager(Object config)
{
GCloudSessionIdManager idManager = new GCloudSessionIdManager(getServer());
idManager.setWorkerName("w"+(__workers++));
idManager.setConfig((GCloudConfiguration)config);
return idManager;
}
/**
* @see org.eclipse.jetty.server.session.AbstractTestServer#newSessionManager()
@ -84,8 +73,8 @@ public class GCloudTestServer extends AbstractTestServer
public SessionManager newSessionManager()
{
GCloudSessionManager sessionManager = new GCloudSessionManager();
sessionManager.setSessionIdManager((GCloudSessionIdManager)_sessionIdManager);
sessionManager.getSessionDataStore().setGCloudConfiguration(((GCloudSessionIdManager)_sessionIdManager).getConfig());
sessionManager.setSessionIdManager(_sessionIdManager);
sessionManager.getSessionDataStore().setGCloudConfiguration((GCloudConfiguration)_config);
return sessionManager;
}

View File

@ -23,6 +23,8 @@ import java.util.Set;
import org.eclipse.jetty.server.session.AbstractSessionRenewTest;
import org.eclipse.jetty.server.session.AbstractTestServer;
import org.eclipse.jetty.webapp.WebAppContext;
import static org.junit.Assert.fail;
import org.junit.AfterClass;
import org.junit.BeforeClass;
@ -70,7 +72,7 @@ public class SessionRenewTest extends AbstractSessionRenewTest
* @see org.eclipse.jetty.server.session.AbstractSessionRenewTest#verifyChange(java.lang.String, java.lang.String)
*/
@Override
public boolean verifyChange(String oldSessionId, String newSessionId)
public boolean verifyChange(WebAppContext context, String oldSessionId, String newSessionId)
{
try
{

View File

@ -39,13 +39,6 @@ public class HashTestServer extends AbstractTestServer
}
public SessionIdManager newSessionIdManager(Object config)
{
HashSessionIdManager mgr = new HashSessionIdManager(_server);
mgr.setWorkerName("worker"+(__workers++));
return mgr;
}
public SessionManager newSessionManager()
{
HashSessionManager manager = new HashSessionManager();

View File

@ -22,6 +22,7 @@ import java.io.File;
import org.eclipse.jetty.server.SessionManager;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.webapp.WebAppContext;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@ -45,7 +46,7 @@ public class SessionRenewTest extends AbstractSessionRenewTest
* @see org.eclipse.jetty.server.session.AbstractSessionRenewTest#verifyChange(java.lang.String, java.lang.String)
*/
@Override
public boolean verifyChange(String oldSessionId, String newSessionId)
public boolean verifyChange(WebAppContext context ,String oldSessionId, String newSessionId)
{
return true; //no other tests possible, sessions only in memory
}

View File

@ -21,18 +21,15 @@ package org.eclipse.jetty.server.session;
import org.eclipse.jetty.server.SessionIdManager;
import org.eclipse.jetty.server.SessionManager;
import org.eclipse.jetty.session.infinispan.InfinispanSessionIdManager;
import org.eclipse.jetty.session.infinispan.InfinispanSessionDataStore;
import org.eclipse.jetty.session.infinispan.InfinispanSessionManager;
import org.eclipse.jetty.webapp.WebAppContext;
import org.infinispan.Cache;
import org.infinispan.commons.api.BasicCache;
import org.infinispan.commons.util.CloseableIteratorSet;
public class InfinispanTestSessionServer extends AbstractTestServer
{
static int __workers=0;
public InfinispanTestSessionServer(int port, BasicCache config)
@ -49,22 +46,11 @@ public class InfinispanTestSessionServer extends AbstractTestServer
@Override
public SessionIdManager newSessionIdManager(Object config)
{
InfinispanSessionIdManager idManager = new InfinispanSessionIdManager(getServer());
idManager.setWorkerName("w"+(__workers++));
idManager.setCache((BasicCache)config);
idManager.setInfinispanIdleTimeoutSec(0);
return idManager;
}
@Override
public SessionManager newSessionManager()
{
InfinispanSessionManager sessionManager = new InfinispanSessionManager();
sessionManager.setSessionIdManager((InfinispanSessionIdManager)_sessionIdManager);
sessionManager.getSessionDataStore().setCache(((InfinispanSessionIdManager)_sessionIdManager).getCache());
sessionManager.getSessionDataStore().setCache((BasicCache)_config);
return sessionManager;
}
@ -74,23 +60,23 @@ public class InfinispanTestSessionServer extends AbstractTestServer
return new SessionHandler(sessionManager);
}
public boolean exists (String id)
public boolean exists (WebAppContext context, String id)
{
BasicCache cache = ((InfinispanSessionIdManager)_sessionIdManager).getCache();
BasicCache cache = (BasicCache)_config;
if (cache != null)
{
return cache.containsKey(((InfinispanSessionIdManager)_sessionIdManager).makeKey(id));
return cache.containsKey(((InfinispanSessionDataStore)(context.getSessionHandler().getSessionManager().getSessionStore().getSessionDataStore())).getCacheKey(id));
}
return false;
}
public Object get (String id)
public Object get (WebAppContext context, String id)
{
BasicCache cache = ((InfinispanSessionIdManager)_sessionIdManager).getCache();
BasicCache cache = (BasicCache)_config;
if (cache != null)
{
return cache.get(((InfinispanSessionIdManager)_sessionIdManager).makeKey(id));
return cache.get(((InfinispanSessionDataStore)(context.getSessionHandler().getSessionManager().getSessionStore().getSessionDataStore())).getCacheKey(id));
}
return null;
@ -98,7 +84,7 @@ public class InfinispanTestSessionServer extends AbstractTestServer
public void dumpCache ()
{
BasicCache cache = ((InfinispanSessionIdManager)_sessionIdManager).getCache();
BasicCache cache = (BasicCache)_config;
if (cache != null)
{
System.err.println(cache.getName()+" contains "+cache.size()+" entries");
@ -107,7 +93,8 @@ public class InfinispanTestSessionServer extends AbstractTestServer
public void clearCache ()
{
BasicCache cache = ((InfinispanSessionIdManager)_sessionIdManager).getCache();
BasicCache cache = (BasicCache)_config;
if (cache != null)
cache.clear();
}

View File

@ -20,6 +20,9 @@
package org.eclipse.jetty.server.session;
import static org.junit.Assert.assertTrue;
import org.eclipse.jetty.webapp.WebAppContext;
import static org.junit.Assert.assertFalse;
import org.junit.AfterClass;
import org.junit.BeforeClass;
@ -69,11 +72,11 @@ public class SessionRenewTest extends AbstractSessionRenewTest
* @see org.eclipse.jetty.server.session.AbstractSessionRenewTest#verifyChange(java.lang.String, java.lang.String)
*/
@Override
public boolean verifyChange(String oldSessionId, String newSessionId)
public boolean verifyChange(WebAppContext context, String oldSessionId, String newSessionId)
{
assertTrue(((InfinispanTestSessionServer)_server).exists(newSessionId));
assertFalse(((InfinispanTestSessionServer)_server).exists(oldSessionId));
return (!((InfinispanTestSessionServer)_server).exists(oldSessionId)) && ((InfinispanTestSessionServer)_server).exists(newSessionId);
assertTrue(((InfinispanTestSessionServer)_server).exists(context, newSessionId));
assertFalse(((InfinispanTestSessionServer)_server).exists(context, oldSessionId));
return (!((InfinispanTestSessionServer)_server).exists(context, oldSessionId)) && ((InfinispanTestSessionServer)_server).exists(context, newSessionId);
}

View File

@ -22,6 +22,7 @@ package org.eclipse.jetty.server.session.remote;
import org.eclipse.jetty.server.session.AbstractSessionRenewTest;
import org.eclipse.jetty.server.session.AbstractTestServer;
import org.eclipse.jetty.server.session.InfinispanTestSessionServer;
import org.eclipse.jetty.webapp.WebAppContext;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
@ -70,8 +71,8 @@ public class RemoteSessionRenewTest extends AbstractSessionRenewTest
* @see org.eclipse.jetty.server.session.AbstractSessionRenewTest#verifyChange(java.lang.String, java.lang.String)
*/
@Override
public boolean verifyChange(String oldSessionId, String newSessionId)
public boolean verifyChange(WebAppContext context, String oldSessionId, String newSessionId)
{
return !((InfinispanTestSessionServer)_server).exists(oldSessionId) && ((InfinispanTestSessionServer)_server).exists(newSessionId);
return !((InfinispanTestSessionServer)_server).exists(context, oldSessionId) && ((InfinispanTestSessionServer)_server).exists(context, newSessionId);
}
}

View File

@ -105,25 +105,6 @@ public class JdbcTestServer extends AbstractTestServer
return new SessionHandler(sessionManager);
}
static int __workers=0;
/**
* @see org.eclipse.jetty.server.session.AbstractTestServer#newSessionIdManager(String)
*/
@Override
public SessionIdManager newSessionIdManager(Object config)
{
synchronized(JdbcTestServer.class)
{
JDBCSessionIdManager idManager = new JDBCSessionIdManager(_server);
idManager.setWorkerName("w"+(__workers++));
idManager.getDatabaseAdaptor().setDriverInfo(DRIVER_CLASS, (config==null?DEFAULT_CONNECTION_URL:(String)config));
JDBCSessionIdManager.SessionIdTableSchema idTableSchema = idManager.getSessionIdTableSchema();
idTableSchema.setTableName("mysessionids");
idTableSchema.setIdColumn("myid");
return idManager;
}
}
/**
* @see org.eclipse.jetty.server.session.AbstractTestServer#newSessionManager()
@ -135,10 +116,11 @@ public class JdbcTestServer extends AbstractTestServer
public SessionManager newSessionManager()
{
JDBCSessionManager manager = new JDBCSessionManager();
manager.setSessionIdManager((JDBCSessionIdManager)_sessionIdManager);
JDBCSessionDataStore ds = manager.getSessionDataStore();
ds.setGracePeriodSec(_inspectionPeriod);
manager.getDatabaseAdaptor().setDriverInfo(DRIVER_CLASS, DEFAULT_CONNECTION_URL);
DatabaseAdaptor da = new DatabaseAdaptor();
da.setDriverInfo(DRIVER_CLASS, (_config==null?DEFAULT_CONNECTION_URL:(String)_config));
ds.setDatabaseAdaptor(da);
JDBCSessionDataStore.SessionTableSchema sessionTableSchema = new JDBCSessionDataStore.SessionTableSchema();
sessionTableSchema.setTableName(TABLE);
sessionTableSchema.setIdColumn(ID_COL);
@ -157,27 +139,6 @@ public class JdbcTestServer extends AbstractTestServer
}
public boolean existsInSessionIdTable(String id)
throws Exception
{
Class.forName(DRIVER_CLASS);
Connection con = null;
try
{
con = DriverManager.getConnection(DEFAULT_CONNECTION_URL);
PreparedStatement statement = con.prepareStatement("select * from "+
((JDBCSessionIdManager)_sessionIdManager)._sessionIdTableSchema.getTableName()+
" where "+((JDBCSessionIdManager)_sessionIdManager)._sessionIdTableSchema.getIdColumn()+" = ?");
statement.setString(1, id);
ResultSet result = statement.executeQuery();
return result.next();
}
finally
{
if (con != null)
con.close();
}
}
public boolean existsInSessionTable(String id, boolean verbose)
@ -223,8 +184,7 @@ public class JdbcTestServer extends AbstractTestServer
try
{
con = DriverManager.getConnection(DEFAULT_CONNECTION_URL);
PreparedStatement statement = con.prepareStatement("select * from "+((JDBCSessionIdManager)_sessionIdManager)._sessionIdTableSchema.getTableName());
PreparedStatement statement = con.prepareStatement("select "+ID_COL+" from "+TABLE);
ResultSet result = statement.executeQuery();
while (result.next())
{

View File

@ -123,11 +123,11 @@ public class ReloadedSessionMissingClassTest
request.header("Cookie", sessionCookie);
response = request.send();
assertEquals(HttpServletResponse.SC_OK,response.getStatus());
String afterStopSessionId = (String)webApp.getServletContext().getAttribute("foo.session");
Boolean fooPresent = (Boolean)webApp.getServletContext().getAttribute("foo.present");
assertFalse(fooPresent);
assertNotNull(afterStopSessionId);
assertFalse(fooPresent);
assertTrue(!afterStopSessionId.equals(sessionId));
}

View File

@ -21,6 +21,8 @@ package org.eclipse.jetty.server.session;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.fail;
import org.eclipse.jetty.webapp.WebAppContext;
import org.junit.After;
import org.junit.Test;
@ -39,7 +41,7 @@ public class SessionRenewTest extends AbstractSessionRenewTest
* @see org.eclipse.jetty.server.session.AbstractSessionRenewTest#verifyChange(java.lang.String, java.lang.String)
*/
@Override
public boolean verifyChange(String oldSessionId, String newSessionId)
public boolean verifyChange(WebAppContext context, String oldSessionId, String newSessionId)
{
try
{

View File

@ -79,20 +79,6 @@ public class MongoTestServer extends AbstractTestServer
super(port, maxInactivePeriod, scavengePeriod, inspectionPeriod, idlePassivatePeriod);
}
public SessionIdManager newSessionIdManager(Object config)
{
try
{
MongoSessionIdManager idManager = new MongoSessionIdManager(_server, getCollection());
idManager.setWorkerName("w"+(__workers++));
return idManager;
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
public SessionManager newSessionManager()
{
@ -100,6 +86,7 @@ public class MongoTestServer extends AbstractTestServer
try
{
manager = new MongoSessionManager();
((MongoSessionManager)manager).getSessionDataStore().setDBCollection(getCollection());
manager.getSessionDataStore().setGracePeriodSec(_inspectionPeriod);
}
catch (Exception e)

View File

@ -1,260 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2016 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.nosql.mongodb;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.net.UnknownHostException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.junit.Ignore;
import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.Mongo;
import com.mongodb.MongoException;
/**
* PurgeInvalidSessionTest
*
*
*
*/
public class PurgeInvalidSessionTest
{
public MongoTestServer createServer(int port, int max, int scavenge)
{
MongoTestServer server = new MongoTestServer(port,max,scavenge);
return server;
}
@Ignore
public void testPurgeInvalidSession() throws Exception
{
String contextPath = "";
String servletMapping = "/server";
long purgeDelay = 1000; //1 sec
long purgeInvalidAge = 1000; //1 sec
long purgeValidAge = 1000;
//ensure scavenging is turned off so the purger gets a chance to find the session
MongoTestServer server = createServer(0, 1, 0);
ServletContextHandler context = server.addContext(contextPath);
context.addServlet(TestServlet.class, servletMapping);
MongoSessionManager sessionManager = (MongoSessionManager)context.getSessionHandler().getSessionManager();
MongoSessionIdManager idManager = (MongoSessionIdManager)server.getServer().getSessionIdManager();
/* idManager.setPurge(true);
idManager.setPurgeDelay(purgeDelay);
idManager.setPurgeInvalidAge(purgeInvalidAge); //purge invalid sessions older than
idManager.setPurgeValidAge(purgeValidAge); //purge valid sessions older than
*/
server.start();
int port=server.getPort();
try
{
HttpClient client = new HttpClient();
client.start();
try
{
//Create a session
ContentResponse response = client.GET("http://localhost:" + port + contextPath + servletMapping + "?action=create");
assertEquals(HttpServletResponse.SC_OK,response.getStatus());
String sessionCookie = response.getHeaders().get("Set-Cookie");
assertTrue(sessionCookie != null);
// Mangle the cookie, replacing Path with $Path, etc.
sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
//make a request to invalidate the session
Request request = client.newRequest("http://localhost:" + port + contextPath + servletMapping + "?action=invalidate");
request.header("Cookie", sessionCookie);
response = request.send();
assertEquals(HttpServletResponse.SC_OK,response.getStatus());
Thread.currentThread().sleep(3*purgeDelay); //sleep long enough for purger to have run
//make a request using previous session to test if its still there
request = client.newRequest("http://localhost:" + port + contextPath + servletMapping + "?action=test");
request.header("Cookie", sessionCookie);
response = request.send();
assertEquals(HttpServletResponse.SC_OK,response.getStatus());
}
finally
{
client.stop();
}
}
finally
{
server.stop();
}
}
@Ignore
public void testPurgeInvalidSessionsWithLimit() throws Exception
{
String contextPath = "";
String servletMapping = "/server";
long purgeInvalidAge = 1000; //1 sec
int purgeLimit = 5; // only purge 5 sessions for each purge run
//ensure scavenging is turned off so the purger gets a chance to find the session
MongoTestServer server = createServer(0, 1, 0);
ServletContextHandler context = server.addContext(contextPath);
context.addServlet(TestServlet.class, servletMapping);
// disable purging so we can call it manually below
MongoSessionManager sessionManager = (MongoSessionManager)context.getSessionHandler().getSessionManager();
MongoSessionIdManager idManager = (MongoSessionIdManager)server.getServer().getSessionIdManager();
/* idManager.setPurge(false);
idManager.setPurgeLimit(purgeLimit);
idManager.setPurgeInvalidAge(purgeInvalidAge);
// don't purge valid sessions
idManager.setPurgeValidAge(0);*/
server.start();
int port=server.getPort();
try
{
// cleanup any previous sessions that are invalid so that we are starting fresh
/* idManager.purgeFully();*/
long sessionCountAtTestStart = sessionManager.getSessionStoreCount();
HttpClient client = new HttpClient();
client.start();
try
{
// create double the purge limit of sessions, and make them all invalid
for (int i = 0; i < purgeLimit * 2; i++)
{
ContentResponse response = client.GET("http://localhost:" + port + contextPath + servletMapping + "?action=create");
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
String sessionCookie = response.getHeaders().get("Set-Cookie");
assertTrue(sessionCookie != null);
// Mangle the cookie, replacing Path with $Path, etc.
sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
Request request = client.newRequest("http://localhost:" + port + contextPath + servletMapping + "?action=invalidate");
request.header("Cookie", sessionCookie);
response = request.send();
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
}
// sleep for our invalid age period so that the purge below does something
Thread.sleep(purgeInvalidAge * 2);
// validate that we have the right number of sessions before we purge
assertEquals("Expected to find right number of sessions before purge", sessionCountAtTestStart + (purgeLimit * 2), sessionManager.getSessionStoreCount());
// run our purge we should still have items in the DB
/* idManager.purge();*/
assertEquals("Expected to find sessions remaining in db after purge run with limit set",
sessionCountAtTestStart + purgeLimit, sessionManager.getSessionStoreCount());
}
finally
{
client.stop();
}
}
finally
{
server.stop();
}
}
public static class TestServlet extends HttpServlet
{
DBCollection _sessions;
public TestServlet() throws UnknownHostException, MongoException
{
super();
_sessions = new Mongo().getDB("HttpSessions").getCollection("sessions");
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
String action = request.getParameter("action");
if ("create".equals(action))
{
HttpSession session = request.getSession(true);
session.setAttribute("foo", "bar");
assertTrue(session.isNew());
}
else if ("invalidate".equals(action))
{
HttpSession existingSession = request.getSession(false);
assertNotNull(existingSession);
String id = existingSession.getId();
id = (id.indexOf(".") > 0?id.substring(0, id.indexOf(".")):id);
DBObject dbSession = _sessions.findOne(new BasicDBObject("id",id));
assertNotNull(dbSession);
existingSession.invalidate();
//still in db, just marked as invalid
dbSession = _sessions.findOne(new BasicDBObject("id", id));
assertNotNull(dbSession);
/* assertTrue(dbSession.containsField(MongoSessionManager.__INVALIDATED));*/
assertTrue(dbSession.containsField(MongoSessionDataStore.__VALID));
assertTrue(dbSession.get(MongoSessionDataStore.__VALID).equals(false));
}
else if ("test".equals(action))
{
String id = request.getRequestedSessionId();
assertNotNull(id);
id = (id.indexOf(".") > 0?id.substring(0, id.indexOf(".")):id);
HttpSession existingSession = request.getSession(false);
assertTrue(existingSession == null);
//not in db any more
DBObject dbSession = _sessions.findOne(new BasicDBObject("id", id));
assertTrue(dbSession == null);
}
}
}
}

View File

@ -1,232 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2016 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.nosql.mongodb;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.net.UnknownHostException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.junit.Ignore;
import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.Mongo;
import com.mongodb.MongoException;
/**
* PurgeValidSessionTest
*
*
*
*/
public class PurgeValidSessionTest
{
public MongoTestServer createServer(int port, int max, int scavenge)
{
MongoTestServer server = new MongoTestServer(port,max,scavenge);
return server;
}
@Ignore
public void testPurgeValidSession() throws Exception
{
String contextPath = "";
String servletMapping = "/server";
long purgeDelay = 1000; //1 sec
long purgeValidAge = 1000;
//ensure scavenging is turned off so the purger gets a chance to find the session
MongoTestServer server = createServer(0, 1, 0);
ServletContextHandler context = server.addContext(contextPath);
context.addServlet(TestServlet.class, servletMapping);
MongoSessionManager sessionManager = (MongoSessionManager)context.getSessionHandler().getSessionManager();
MongoSessionIdManager idManager = (MongoSessionIdManager)server.getServer().getSessionIdManager();
/* idManager.setPurge(true);
idManager.setPurgeDelay(purgeDelay);
idManager.setPurgeValidAge(purgeValidAge); //purge valid sessions older than
*/
server.start();
int port=server.getPort();
try
{
HttpClient client = new HttpClient();
client.start();
try
{
//Create a session
ContentResponse response = client.GET("http://localhost:" + port + contextPath + servletMapping + "?action=create");
assertEquals(HttpServletResponse.SC_OK,response.getStatus());
String sessionCookie = response.getHeaders().get("Set-Cookie");
assertTrue(sessionCookie != null);
// Mangle the cookie, replacing Path with $Path, etc.
sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
Thread.currentThread().sleep(3*purgeDelay); //sleep long enough for purger to have run
//make a request using previous session to test if its still there
Request request = client.newRequest("http://localhost:" + port + contextPath + servletMapping + "?action=test");
request.header("Cookie", sessionCookie);
ContentResponse response2 = request.send();
assertEquals(HttpServletResponse.SC_OK,response2.getStatus());
}
finally
{
client.stop();
}
}
finally
{
server.stop();
}
}
@Ignore
public void testPurgeValidSessionWithPurgeLimitSet() throws Exception
{
String contextPath = "";
String servletMapping = "/server";
long purgeDelay = 1000; //1 sec
long purgeValidAge = 1000; // 1 sec
int purgeLimit = 5; // only purge 5 items in each purge run
//ensure scavenging is turned off so the purger gets a chance to find the session
MongoTestServer server = createServer(0, 1, 0);
ServletContextHandler context = server.addContext(contextPath);
context.addServlet(TestServlet.class, servletMapping);
MongoSessionManager sessionManager = (MongoSessionManager)context.getSessionHandler().getSessionManager();
MongoSessionIdManager idManager = (MongoSessionIdManager)server.getServer().getSessionIdManager();
// disable purging we will run it manually below
/* idManager.setPurge(false);
idManager.setPurgeLimit(purgeLimit);
idManager.setPurgeDelay(purgeDelay);
idManager.setPurgeValidAge(purgeValidAge); //purge valid sessions older than
*/
server.start();
int port=server.getPort();
try
{
// start with no sessions
//((TestMongoSessionIdManager)idManager).deleteAll();
HttpClient client = new HttpClient();
client.start();
try
{
// create double our purgeLmit number of sessions
for (int i = 0; i < purgeLimit * 2; i++)
{
ContentResponse response = client.GET("http://localhost:" + port + contextPath + servletMapping + "?action=create");
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
String sessionCookie = response.getHeaders().get("Set-Cookie");
assertTrue(sessionCookie != null);
// don't remember our cookies from call to call
client.getCookieStore().removeAll();
}
// delay long enough for purgeValidAge to apply
Thread.sleep(2* purgeValidAge);
// validate that we have the right number of sessions before we purge
assertEquals("Expected to find right number of sessions before purge", purgeLimit * 2, sessionManager.getSessionStoreCount());
// run our purge
/* idManager.purge();*/
assertEquals("Expected to find sessions remaining in db after purge run with limit set",
purgeLimit, sessionManager.getSessionStoreCount());
}
finally
{
client.stop();
}
}
finally
{
server.stop();
}
}
public static class TestServlet extends HttpServlet
{
DBCollection _sessions;
public TestServlet() throws UnknownHostException, MongoException
{
super();
_sessions = new Mongo().getDB("HttpSessions").getCollection("sessions");
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
String action = request.getParameter("action");
if ("create".equals(action))
{
HttpSession session = request.getSession(true);
assertTrue(session.isNew());
}
else if ("test".equals(action))
{
String id = request.getRequestedSessionId();
assertNotNull(id);
id = id.substring(0, id.indexOf("."));
HttpSession existingSession = request.getSession(false);
assertTrue(existingSession == null);
//not in db any more
DBObject dbSession = _sessions.findOne(new BasicDBObject("id", id));
assertTrue(dbSession == null);
}
}
}
}

View File

@ -123,7 +123,7 @@ public class SessionExpiryTest extends AbstractSessionExpiryTest
String sessionId = AbstractTestServer.extractSessionId(sessionCookie);
DBCollection sessions = ((MongoSessionIdManager)((MongoTestServer)server1).getServer().getSessionIdManager()).getSessions();
DBCollection sessions = MongoTestServer.getCollection();
verifySessionCreated(listener,sessionId);
//verify that the session timeout is set in mongo
verifySessionTimeout(sessions, sessionId, -1); //SessionManager sets -1 if maxInactive < 0
@ -176,7 +176,7 @@ public class SessionExpiryTest extends AbstractSessionExpiryTest
String sessionId = AbstractTestServer.extractSessionId(sessionCookie);
DBCollection sessions = ((MongoSessionIdManager)((MongoTestServer)server1).getServer().getSessionIdManager()).getSessions();
DBCollection sessions = MongoTestServer.getCollection();
verifySessionCreated(listener,sessionId);
//verify that the session timeout is set in mongo
verifySessionTimeout(sessions, sessionId, inactivePeriod);
@ -254,7 +254,7 @@ public class SessionExpiryTest extends AbstractSessionExpiryTest
String sessionId = AbstractTestServer.extractSessionId(sessionCookie);
DBCollection sessions = ((MongoSessionIdManager)((MongoTestServer)server1).getServer().getSessionIdManager()).getSessions();
DBCollection sessions = MongoTestServer.getCollection();
verifySessionCreated(listener,sessionId);
//verify that the session timeout is the new value and not the default
verifySessionTimeout(sessions, sessionId, inactivePeriod);

View File

@ -20,6 +20,7 @@ package org.eclipse.jetty.nosql.mongodb;
import org.eclipse.jetty.server.session.AbstractSessionRenewTest;
import org.eclipse.jetty.server.session.AbstractTestServer;
import org.eclipse.jetty.webapp.WebAppContext;
import static org.junit.Assert.assertNotNull;
import org.junit.AfterClass;
@ -63,7 +64,7 @@ public class SessionRenewTest extends AbstractSessionRenewTest
* @see org.eclipse.jetty.server.session.AbstractSessionRenewTest#verifyChange(java.lang.String, java.lang.String)
*/
@Override
public boolean verifyChange(String oldSessionId, String newSessionId)
public boolean verifyChange(WebAppContext context, String oldSessionId, String newSessionId)
{
try
{

View File

@ -52,7 +52,7 @@ public abstract class AbstractSessionRenewTest
public abstract AbstractTestServer createServer(int port, int max, int scavenge, int inspectionPeriod, int idlePassivationPeriod);
public abstract boolean verifyChange (String oldSessionId, String newSessionId);
public abstract boolean verifyChange (WebAppContext context, String oldSessionId, String newSessionId);
/**
* @throws Exception
@ -101,7 +101,7 @@ public abstract class AbstractSessionRenewTest
assertNotSame(sessionCookie, renewSessionCookie);
assertTrue(testListener.isCalled());
assertTrue(verifyChange(AbstractTestServer.extractSessionId(sessionCookie), AbstractTestServer.extractSessionId(renewSessionCookie)));
assertTrue(verifyChange(context, AbstractTestServer.extractSessionId(sessionCookie), AbstractTestServer.extractSessionId(renewSessionCookie)));
}
finally
{
@ -160,7 +160,7 @@ public abstract class AbstractSessionRenewTest
assertFalse(beforeSessionId.equals(afterSessionId)); //different id
SessionManager sessionManager = ((Session)afterSession).getSessionManager();
AbstractSessionIdManager sessionIdManager = (AbstractSessionIdManager)sessionManager.getSessionIdManager();
DefaultSessionIdManager sessionIdManager = (DefaultSessionIdManager)sessionManager.getSessionIdManager();
assertTrue(sessionIdManager.isIdInUse(afterSessionId)); //new session id should be in use
assertFalse(sessionIdManager.isIdInUse(beforeSessionId));

View File

@ -39,6 +39,8 @@ public abstract class AbstractTestServer
public static int DEFAULT_SCAVENGE_SEC = 10;
public static int DEFAULT_IDLE_PASSIVATE_SEC = 2;
protected static int __workers=0;
protected final Server _server;
protected final int _maxInactivePeriod;
protected final int _inspectionPeriod;
@ -47,6 +49,7 @@ public abstract class AbstractTestServer
protected final ContextHandlerCollection _contexts;
protected SessionIdManager _sessionIdManager;
private PeriodicSessionInspector _inspector;
protected Object _config;
@ -78,7 +81,7 @@ public abstract class AbstractTestServer
this (port, maxInactivePeriod, scavengePeriod, inspectionPeriod, idlePassivatePeriod, null);
}
public AbstractTestServer(int port, int maxInactivePeriod, int scavengePeriod, int inspectionPeriod, int idlePassivatePeriod, Object sessionIdMgrConfig)
public AbstractTestServer(int port, int maxInactivePeriod, int scavengePeriod, int inspectionPeriod, int idlePassivatePeriod, Object cfg)
{
_server = new Server(port);
_maxInactivePeriod = maxInactivePeriod;
@ -86,17 +89,28 @@ public abstract class AbstractTestServer
_inspectionPeriod = inspectionPeriod;
_idlePassivatePeriod = idlePassivatePeriod;
_contexts = new ContextHandlerCollection();
_sessionIdManager = newSessionIdManager(sessionIdMgrConfig);
_config = cfg;
_sessionIdManager = newSessionIdManager();
_server.setSessionIdManager(_sessionIdManager);
((AbstractSessionIdManager) _sessionIdManager).setServer(_server);
((DefaultSessionIdManager) _sessionIdManager).setServer(_server);
_inspector = new PeriodicSessionInspector();
_inspector.setIntervalSec(_inspectionPeriod);
((AbstractSessionIdManager)_sessionIdManager).setSessionInspector(_inspector);
((DefaultSessionIdManager)_sessionIdManager).setSessionInspector(_inspector);
}
public abstract SessionIdManager newSessionIdManager(Object config);
/**
* @return
*/
public SessionIdManager newSessionIdManager()
{
DefaultSessionIdManager idManager = new DefaultSessionIdManager(getServer());
idManager.setWorkerName("w"+(__workers++));
return idManager;
}
public abstract SessionManager newSessionManager();
public abstract SessionHandler newSessionHandler(SessionManager sessionManager);