Remove necessity for SessionIdManager specializations.
This commit is contained in:
parent
c1b03c6d8c
commit
add04e8fba
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
|
@ -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)
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -29,238 +29,16 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
/**
|
||||
* GCloudSessionManager
|
||||
*
|
||||
*
|
||||
* Convenience class to link up a MemorySessionStore with the GCloudSessionDataStore.
|
||||
*
|
||||
*/
|
||||
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
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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>
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -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>
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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>
|
|
@ -314,6 +314,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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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>
|
|
@ -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>
|
|
@ -34,30 +34,25 @@ public interface SessionIdManager extends LifeCycle
|
|||
* @return True if the session ID is in use by at least one context.
|
||||
*/
|
||||
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
|
||||
* Expire all sessions on all contexts that share the same id.
|
||||
*
|
||||
* @param id The session ID without any cluster node extension
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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);
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -146,4 +146,5 @@ public abstract class AbstractSessionDataStore extends AbstractLifeCycle impleme
|
|||
{
|
||||
_gracePeriodSec = sec;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -90,16 +90,7 @@ public abstract class AbstractSessionStore extends AbstractLifeCycle implements
|
|||
*/
|
||||
public abstract boolean doReplace (String id, Session oldValue, Session newValue);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -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;
|
||||
|
@ -411,15 +401,24 @@ public abstract class AbstractSessionStore extends AbstractLifeCycle implements
|
|||
|
||||
if (_sessionDataStore == null)
|
||||
return null; //can't load it
|
||||
|
||||
data =_sessionDataStore.load(id);
|
||||
|
||||
if (data == null) //session doesn't exist
|
||||
return null;
|
||||
try
|
||||
{
|
||||
data =_sessionDataStore.load(id);
|
||||
|
||||
session = newSession(data);
|
||||
session.setSessionManager(_manager);
|
||||
return session;
|
||||
if (data == null) //session doesn't exist
|
||||
return null;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,11 +44,13 @@ 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;
|
||||
|
@ -56,12 +59,13 @@ public abstract class AbstractSessionIdManager extends AbstractLifeCycle impleme
|
|||
protected long _reseed=100000L;
|
||||
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))
|
||||
|
@ -262,6 +266,8 @@ public abstract class AbstractSessionIdManager extends AbstractLifeCycle impleme
|
|||
//NOTE this is different to the node suffix which denotes which node the request was received on
|
||||
if (_workerName!=null)
|
||||
id=_workerName + id;
|
||||
|
||||
id = id+Long.toString(COUNTER.getAndIncrement());
|
||||
|
||||
}
|
||||
return id;
|
||||
|
@ -269,7 +275,46 @@ public abstract class AbstractSessionIdManager extends AbstractLifeCycle impleme
|
|||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
|
||||
|
@ -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,8 +457,8 @@ 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())
|
||||
{
|
|
@ -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)
|
||||
|
@ -326,6 +348,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));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
@ -1057,7 +1034,26 @@ public class SessionManager extends ContainerLifeCycle implements org.eclipse.je
|
|||
_sessionStore.inspect();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -52,4 +52,5 @@ public interface SessionStore extends LifeCycle
|
|||
int getExpiryTimeoutSec();
|
||||
void setExpiryTimeoutSec(int sec);
|
||||
Stream<Session> getStream();
|
||||
SessionDataStore getSessionDataStore();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,14 +37,12 @@ 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;
|
||||
static protected int __idlePeriod = 2;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param port
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
@ -106,8 +92,9 @@ public class InfinispanTestSessionServer extends AbstractTestServer
|
|||
}
|
||||
|
||||
public void clearCache ()
|
||||
{
|
||||
BasicCache cache = ((InfinispanSessionIdManager)_sessionIdManager).getCache();
|
||||
{
|
||||
BasicCache cache = (BasicCache)_config;
|
||||
|
||||
if (cache != null)
|
||||
cache.clear();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,26 +105,7 @@ 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);
|
||||
|
@ -156,28 +138,7 @@ public class JdbcTestServer extends AbstractTestServer
|
|||
return manager;
|
||||
}
|
||||
|
||||
|
||||
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())
|
||||
{
|
||||
|
|
|
@ -122,12 +122,12 @@ public class ReloadedSessionMissingClassTest
|
|||
Request request = client.newRequest("http://localhost:" + port1 + contextPath + "/bar?action=get");
|
||||
request.header("Cookie", sessionCookie);
|
||||
response = request.send();
|
||||
assertEquals(HttpServletResponse.SC_OK,response.getStatus());
|
||||
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));
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue