Merge branch 'master' of ssh://git.eclipse.org/gitroot/jetty/org.eclipse.jetty.project
This commit is contained in:
commit
1a832ef21e
|
@ -0,0 +1,94 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>7.5.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-nosql</artifactId>
|
||||
<name>Jetty :: NoSQL Session Managers</name>
|
||||
<properties>
|
||||
<jetty-version>${project.version}</jetty-version>
|
||||
<junit4-version>${junit-version}</junit4-version>
|
||||
<bundle-symbolic-name>${project.groupId}.mongodb</bundle-symbolic-name> </properties>
|
||||
<build>
|
||||
<defaultGoal>install</defaultGoal>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
<verbose>false</verbose>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Import-Package>javax.servlet.*;version="[2.5,3.0)",org.eclipse.jetty.server.session.jmx;version="[7.5,8)";resolution:=optional,,org.eclipse.jetty.*;version="[7.5,8)",*</Import-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
<extensions>true</extensions>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>manifest</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>artifact-jar</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>${junit4-version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-jmx</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mongodb</groupId>
|
||||
<artifactId>mongo-java-driver</artifactId>
|
||||
<version>2.6.1</version>
|
||||
<type>jar</type>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.tests</groupId>
|
||||
<artifactId>test-sessions-common</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -0,0 +1,175 @@
|
|||
package org.eclipse.jetty.nosql;
|
||||
//========================================================================
|
||||
//Copyright (c) 2011 Intalio, Inc.
|
||||
//------------------------------------------------------------------------
|
||||
//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.
|
||||
//========================================================================
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.eclipse.jetty.server.session.AbstractSession;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public class NoSqlSession extends AbstractSession
|
||||
{
|
||||
private final static Logger __log = Log.getLogger("org.eclipse.jetty.server.session");
|
||||
|
||||
private final NoSqlSessionManager _manager;
|
||||
private Set<String> _dirty;
|
||||
private final AtomicInteger _active = new AtomicInteger();
|
||||
private Object _version;
|
||||
private long _lastSync;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public NoSqlSession(NoSqlSessionManager manager, long created, long accessed, String clusterId)
|
||||
{
|
||||
super(manager, created,accessed,clusterId);
|
||||
_manager=manager;
|
||||
save(true);
|
||||
_active.incrementAndGet();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public NoSqlSession(NoSqlSessionManager manager, long created, long accessed, String clusterId, Object version)
|
||||
{
|
||||
super(manager, created,accessed,clusterId);
|
||||
_manager=manager;
|
||||
_version=version;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public Object doPutOrRemove(String name, Object value)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
if (_dirty==null)
|
||||
_dirty=new HashSet<String>();
|
||||
_dirty.add(name);
|
||||
Object old = super.doPutOrRemove(name,value);
|
||||
if (_manager.getSavePeriod()==-2)
|
||||
save(true);
|
||||
return old;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void checkValid() throws IllegalStateException
|
||||
{
|
||||
super.checkValid();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected boolean access(long time)
|
||||
{
|
||||
__log.debug("NoSqlSession:access:active "+_active);
|
||||
if (_active.incrementAndGet()==1)
|
||||
{
|
||||
int period=_manager.getStalePeriod()*1000;
|
||||
if (period==0)
|
||||
refresh();
|
||||
else if (period>0)
|
||||
{
|
||||
long stale=time-_lastSync;
|
||||
__log.debug("NoSqlSession:access:stale "+stale);
|
||||
if (stale>period)
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
||||
return super.access(time);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void complete()
|
||||
{
|
||||
super.complete();
|
||||
if(_active.decrementAndGet()==0)
|
||||
{
|
||||
switch(_manager.getSavePeriod())
|
||||
{
|
||||
case 0:
|
||||
save(isValid());
|
||||
break;
|
||||
case 1:
|
||||
if (isDirty())
|
||||
save(isValid());
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void doInvalidate() throws IllegalStateException
|
||||
{
|
||||
super.doInvalidate();
|
||||
save(false);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void save(boolean activateAfterSave)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
_version=_manager.save(this,_version,activateAfterSave);
|
||||
_lastSync=getAccessed();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void refresh()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
_version=_manager.refresh(this,_version);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isDirty()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
return _dirty!=null && !_dirty.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public Set<String> takeDirty()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
Set<String> dirty=_dirty;
|
||||
if (dirty==null)
|
||||
dirty= new HashSet<String>();
|
||||
else
|
||||
_dirty=null;
|
||||
return dirty;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public Object getVersion()
|
||||
{
|
||||
return _version;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,317 @@
|
|||
package org.eclipse.jetty.nosql;
|
||||
//========================================================================
|
||||
//Copyright (c) 2011 Intalio, Inc.
|
||||
//------------------------------------------------------------------------
|
||||
//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.
|
||||
//========================================================================
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.eclipse.jetty.server.SessionManager;
|
||||
import org.eclipse.jetty.server.session.AbstractSession;
|
||||
import org.eclipse.jetty.server.session.AbstractSessionManager;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
public abstract class NoSqlSessionManager extends AbstractSessionManager implements SessionManager
|
||||
{
|
||||
private final static Logger __log = Log.getLogger("org.eclipse.jetty.server.session");
|
||||
|
||||
protected final ConcurrentMap<String,NoSqlSession> _sessions=new ConcurrentHashMap<String,NoSqlSession>();
|
||||
|
||||
private int _stalePeriod=0;
|
||||
private int _savePeriod=0;
|
||||
private int _idlePeriod=-1;
|
||||
private boolean _invalidateOnStop;
|
||||
private boolean _saveAllAttributes;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.jetty.server.session.AbstractSessionManager#doStart()
|
||||
*/
|
||||
@Override
|
||||
public void doStart() throws Exception
|
||||
{
|
||||
super.doStart();
|
||||
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void addSession(AbstractSession session)
|
||||
{
|
||||
if (isRunning())
|
||||
_sessions.put(session.getClusterId(),(NoSqlSession)session);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public AbstractSession getSession(String idInCluster)
|
||||
{
|
||||
NoSqlSession session = _sessions.get(idInCluster);
|
||||
|
||||
__log.debug("getSession: " + session );
|
||||
|
||||
if (session==null)
|
||||
{
|
||||
session=loadSession(idInCluster);
|
||||
|
||||
if (session!=null)
|
||||
{
|
||||
NoSqlSession race=_sessions.putIfAbsent(idInCluster,session);
|
||||
if (race!=null)
|
||||
{
|
||||
session.willPassivate();
|
||||
session.clearAttributes();
|
||||
session=race;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void invalidateSessions() throws Exception
|
||||
{
|
||||
// Invalidate all sessions to cause unbind events
|
||||
ArrayList<NoSqlSession> sessions=new ArrayList<NoSqlSession>(_sessions.values());
|
||||
int loop=100;
|
||||
while (sessions.size()>0 && loop-->0)
|
||||
{
|
||||
// If we are called from doStop
|
||||
if (isStopping())
|
||||
{
|
||||
// Then we only save and remove the session - it is not invalidated.
|
||||
for (NoSqlSession session : sessions)
|
||||
{
|
||||
session.save(false);
|
||||
removeSession(session,false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (NoSqlSession session : sessions)
|
||||
session.invalidate();
|
||||
}
|
||||
|
||||
// check that no new sessions were created while we were iterating
|
||||
sessions=new ArrayList<NoSqlSession>(_sessions.values());
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected AbstractSession newSession(HttpServletRequest request)
|
||||
{
|
||||
long created=System.currentTimeMillis();
|
||||
String clusterId=getSessionIdManager().newSessionId(request,created);
|
||||
return new NoSqlSession(this,created,created,clusterId);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected boolean removeSession(String idInCluster)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
NoSqlSession session = _sessions.remove(idInCluster);
|
||||
|
||||
try
|
||||
{
|
||||
if (session != null)
|
||||
{
|
||||
return remove(session);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
__log.warn("Problem deleting session id=" + idInCluster,e);
|
||||
}
|
||||
|
||||
return session != null;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void invalidateSession( String idInCluster )
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
NoSqlSession session = _sessions.remove(idInCluster);
|
||||
|
||||
try
|
||||
{
|
||||
if (session != null)
|
||||
{
|
||||
remove(session);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
__log.warn("Problem deleting session id=" + idInCluster,e);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ought we not go to cluster and mark it invalid?
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* The State Period is the maximum time in seconds that an in memory session is allows to be stale:
|
||||
* <ul>
|
||||
* <li>If this period is exceeded, the DB will be checked to see if a more recent version is available.</li>
|
||||
* <li>If the state period is set to a value < 0, then no staleness check will be made.</li>
|
||||
* <li>If the state period is set to 0, then a staleness check is made whenever the active request count goes from 0 to 1.</li>
|
||||
* </ul>
|
||||
* @return the stalePeriod in seconds
|
||||
*/
|
||||
public int getStalePeriod()
|
||||
{
|
||||
return _stalePeriod;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* The State Period is the maximum time in seconds that an in memory session is allows to be stale:
|
||||
* <ul>
|
||||
* <li>If this period is exceeded, the DB will be checked to see if a more recent version is available.</li>
|
||||
* <li>If the state period is set to a value < 0, then no staleness check will be made.</li>
|
||||
* <li>If the state period is set to 0, then a staleness check is made whenever the active request count goes from 0 to 1.</li>
|
||||
* </ul>
|
||||
* @param stalePeriod the stalePeriod in seconds
|
||||
*/
|
||||
public void setStalePeriod(int stalePeriod)
|
||||
{
|
||||
_stalePeriod = stalePeriod;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* The Save Period is the time in seconds between saves of a dirty session to the DB.
|
||||
* When this period is exceeded, the a dirty session will be written to the DB: <ul>
|
||||
* <li>a save period of -2 means the session is written to the DB whenever setAttribute is called.</li>
|
||||
* <li>a save period of -1 means the session is never saved to the DB other than on a shutdown</li>
|
||||
* <li>a save period of 0 means the session is written to the DB whenever the active request count goes from 1 to 0.</li>
|
||||
* <li>a save period of 1 means the session is written to the DB whenever the active request count goes from 1 to 0 and the session is dirty.</li>
|
||||
* <li>a save period of > 1 means the session is written after that period in seconds of being dirty.</li>
|
||||
* </ul>
|
||||
* @return the savePeriod -2,-1,0,1 or the period in seconds >=2
|
||||
*/
|
||||
public int getSavePeriod()
|
||||
{
|
||||
return _savePeriod;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* The Save Period is the time in seconds between saves of a dirty session to the DB.
|
||||
* When this period is exceeded, the a dirty session will be written to the DB: <ul>
|
||||
* <li>a save period of -2 means the session is written to the DB whenever setAttribute is called.</li>
|
||||
* <li>a save period of -1 means the session is never saved to the DB other than on a shutdown</li>
|
||||
* <li>a save period of 0 means the session is written to the DB whenever the active request count goes from 1 to 0.</li>
|
||||
* <li>a save period of 1 means the session is written to the DB whenever the active request count goes from 1 to 0 and the session is dirty.</li>
|
||||
* <li>a save period of > 1 means the session is written after that period in seconds of being dirty.</li>
|
||||
* </ul>
|
||||
* @param savePeriod the savePeriod -2,-1,0,1 or the period in seconds >=2
|
||||
*/
|
||||
public void setSavePeriod(int savePeriod)
|
||||
{
|
||||
_savePeriod = savePeriod;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* The Idle Period is the time in seconds before an in memory session is passivated.
|
||||
* When this period is exceeded, the session will be passivated and removed from memory. If the session was dirty, it will be written to the DB.
|
||||
* If the idle period is set to a value < 0, then the session is never idled.
|
||||
* If the save period is set to 0, then the session is idled whenever the active request count goes from 1 to 0.
|
||||
* @return the idlePeriod
|
||||
*/
|
||||
public int getIdlePeriod()
|
||||
{
|
||||
return _idlePeriod;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* The Idle Period is the time in seconds before an in memory session is passivated.
|
||||
* When this period is exceeded, the session will be passivated and removed from memory. If the session was dirty, it will be written to the DB.
|
||||
* If the idle period is set to a value < 0, then the session is never idled.
|
||||
* If the save period is set to 0, then the session is idled whenever the active request count goes from 1 to 0.
|
||||
* @param idlePeriod the idlePeriod in seconds
|
||||
*/
|
||||
public void setIdlePeriod(int idlePeriod)
|
||||
{
|
||||
_idlePeriod = idlePeriod;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Invalidate sessions when the session manager is stopped otherwise save them to the DB.
|
||||
* @return the invalidateOnStop
|
||||
*/
|
||||
public boolean isInvalidateOnStop()
|
||||
{
|
||||
return _invalidateOnStop;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Invalidate sessions when the session manager is stopped otherwise save them to the DB.
|
||||
* @param invalidateOnStop the invalidateOnStop to set
|
||||
*/
|
||||
public void setInvalidateOnStop(boolean invalidateOnStop)
|
||||
{
|
||||
_invalidateOnStop = invalidateOnStop;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Save all attributes of a session or only update the dirty attributes.
|
||||
* @return the saveAllAttributes
|
||||
*/
|
||||
public boolean isSaveAllAttributes()
|
||||
{
|
||||
return _saveAllAttributes;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Save all attributes of a session or only update the dirty attributes.
|
||||
* @param saveAllAttributes the saveAllAttributes to set
|
||||
*/
|
||||
public void setSaveAllAttributes(boolean saveAllAttributes)
|
||||
{
|
||||
_saveAllAttributes = saveAllAttributes;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
abstract protected NoSqlSession loadSession(String clusterId);
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
abstract protected Object save(NoSqlSession session,Object version, boolean activateAfterSave);
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
abstract protected Object refresh(NoSqlSession session, Object version);
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
abstract protected boolean remove(NoSqlSession session);
|
||||
|
||||
}
|
|
@ -0,0 +1,540 @@
|
|||
package org.eclipse.jetty.nosql.mongodb;
|
||||
//========================================================================
|
||||
//Copyright (c) 2011 Intalio, Inc.
|
||||
//------------------------------------------------------------------------
|
||||
//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.
|
||||
//========================================================================
|
||||
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.SessionManager;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.session.AbstractSessionIdManager;
|
||||
import org.eclipse.jetty.server.session.SessionHandler;
|
||||
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.DBCursor;
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.Mongo;
|
||||
import com.mongodb.MongoException;
|
||||
|
||||
/**
|
||||
* Based partially on the jdbc session id manager...
|
||||
*
|
||||
* Theory is that we really only need the session id manager for the local
|
||||
* instance so we have something to scavenge on, namely the list of known ids
|
||||
*
|
||||
* this class has a timer that runs at the scavenge delay that runs a query
|
||||
* for all id's known to this node and that have and old accessed value greater
|
||||
* then the scavengeDelay.
|
||||
*
|
||||
* these found sessions are then run through the invalidateAll(id) method that
|
||||
* is a bit hinky but is supposed to notify all handlers this id is now DOA and
|
||||
* ought to be cleaned up. this ought to result in a save operation on the session
|
||||
* that will change the valid field to false (this conjecture is unvalidated atm)
|
||||
*/
|
||||
public class MongoSessionIdManager extends AbstractSessionIdManager
|
||||
{
|
||||
private final static Logger __log = Log.getLogger("org.eclipse.jetty.server.session");
|
||||
|
||||
final static DBObject __version_1 = new BasicDBObject(MongoSessionManager.__VERSION,1);
|
||||
final static DBObject __valid_false = new BasicDBObject(MongoSessionManager.__VALID,false);
|
||||
|
||||
final DBCollection _sessions;
|
||||
protected Server _server;
|
||||
private Timer _scavengeTimer;
|
||||
private Timer _purgeTimer;
|
||||
private TimerTask _scavengerTask;
|
||||
private TimerTask _purgeTask;
|
||||
|
||||
|
||||
|
||||
private long _scavengeDelay = 30 * 60 * 1000; // every 30 minutes
|
||||
private long _scavengePeriod = 10 * 6 * 1000; // wait at least 10 minutes
|
||||
|
||||
|
||||
/**
|
||||
* purge process is enabled by default
|
||||
*/
|
||||
private boolean _purge = true;
|
||||
|
||||
/**
|
||||
* purge process would run daily by default
|
||||
*/
|
||||
private long _purgeDelay = 24 * 60 * 60 * 1000; // every day
|
||||
|
||||
/**
|
||||
* how long do you want to persist sessions that are no longer
|
||||
* valid before removing them completely
|
||||
*/
|
||||
private long _purgeInvalidAge = 24 * 60 * 60 * 1000; // default 1 day
|
||||
|
||||
/**
|
||||
* how long do you want to leave sessions that are still valid before
|
||||
* assuming they are dead and removing them
|
||||
*/
|
||||
private long _purgeValidAge = 7 * 24 * 60 * 60 * 1000; // default 1 week
|
||||
|
||||
|
||||
/**
|
||||
* the collection of session ids known to this manager
|
||||
*
|
||||
* TODO consider if this ought to be concurrent or not
|
||||
*/
|
||||
protected final Set<String> _sessionsIds = new HashSet<String>();
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public MongoSessionIdManager(Server server) throws UnknownHostException, MongoException
|
||||
{
|
||||
this(server, new Mongo().getDB("HttpSessions").getCollection("sessions"));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public MongoSessionIdManager(Server server, DBCollection sessions)
|
||||
{
|
||||
super(new Random());
|
||||
|
||||
_server = server;
|
||||
_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());
|
||||
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Scavenge is a process that periodically checks the tracked session
|
||||
* ids of this given instance of the session id manager to see if they
|
||||
* are past the point of expiration.
|
||||
*/
|
||||
protected void scavenge()
|
||||
{
|
||||
__log.debug("SessionIdManager:scavenge:called with delay" + _scavengeDelay);
|
||||
|
||||
synchronized (_sessionsIds)
|
||||
{
|
||||
/*
|
||||
* run a query returning results that:
|
||||
* - are in the known list of sessionIds
|
||||
* - have an accessed time less then current time - the scavenger period
|
||||
*
|
||||
* we limit the query to return just the __ID so we are not sucking back full sessions
|
||||
*/
|
||||
BasicDBObject query = new BasicDBObject();
|
||||
query.put(MongoSessionManager.__ID,new BasicDBObject("$in", _sessionsIds ));
|
||||
query.put(MongoSessionManager.__ACCESSED, new BasicDBObject("$lt",System.currentTimeMillis() - _scavengeDelay));
|
||||
|
||||
DBCursor checkSessions = _sessions.find(query, new BasicDBObject(MongoSessionManager.__ID, 1));
|
||||
|
||||
for ( DBObject session : checkSessions )
|
||||
{
|
||||
invalidateAll((String)session.get(MongoSessionManager.__ID));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* ScavengeFully is a process that periodically checks the tracked session
|
||||
* ids of this given instance of the session id manager to see if they
|
||||
* are past the point of expiration.
|
||||
*
|
||||
* NOTE: this is potentially devastating and may lead to serious session
|
||||
* coherence issues, not to be used in a running cluster
|
||||
*/
|
||||
protected void scavengeFully()
|
||||
{
|
||||
__log.debug("SessionIdManager:scavengeFully");
|
||||
|
||||
DBCursor checkSessions = _sessions.find();
|
||||
|
||||
for (DBObject session : checkSessions)
|
||||
{
|
||||
invalidateAll((String)session.get(MongoSessionManager.__ID));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Purge is a process that cleans the mongodb cluster of old sessions that are no
|
||||
* longer valid.
|
||||
*
|
||||
* There are two checks being done here:
|
||||
*
|
||||
* - if the accessed time is older then the current time minus the purge invalid age
|
||||
* and it is no longer valid then remove that session
|
||||
* - if the accessed time is older then the current time minus the purge valid age
|
||||
* then we consider this a lost record and remove it
|
||||
*
|
||||
* NOTE: if your system supports long lived sessions then the purge valid age should be
|
||||
* set to zero so the check is skipped.
|
||||
*
|
||||
* The second check was added to catch sessions that were being managed on machines
|
||||
* that might have crashed without marking their sessions as 'valid=false'
|
||||
*/
|
||||
protected void purge()
|
||||
{
|
||||
BasicDBObject invalidQuery = new BasicDBObject();
|
||||
|
||||
invalidQuery.put(MongoSessionManager.__ACCESSED, new BasicDBObject("$lt",System.currentTimeMillis() - _purgeInvalidAge));
|
||||
invalidQuery.put(MongoSessionManager.__VALID, __valid_false);
|
||||
|
||||
DBCursor oldSessions = _sessions.find(invalidQuery, new BasicDBObject(MongoSessionManager.__ID, 1));
|
||||
|
||||
for (DBObject session : oldSessions)
|
||||
{
|
||||
String id = (String)session.get("id");
|
||||
|
||||
__log.debug("MongoSessionIdManager:purging invalid " + id);
|
||||
|
||||
_sessions.remove(session);
|
||||
}
|
||||
|
||||
if (_purgeValidAge != 0)
|
||||
{
|
||||
BasicDBObject validQuery = new BasicDBObject();
|
||||
|
||||
validQuery.put(MongoSessionManager.__ACCESSED,new BasicDBObject("$lt",System.currentTimeMillis() - _purgeValidAge));
|
||||
validQuery.put(MongoSessionManager.__VALID, __valid_false);
|
||||
|
||||
oldSessions = _sessions.find(invalidQuery,new BasicDBObject(MongoSessionManager.__ID,1));
|
||||
|
||||
for (DBObject session : oldSessions)
|
||||
{
|
||||
String id = (String)session.get(MongoSessionManager.__ID);
|
||||
|
||||
__log.debug("MongoSessionIdManager:purging valid " + id);
|
||||
|
||||
_sessions.remove(session);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Purge is a process that cleans the mongodb cluster of old sessions that are no
|
||||
* longer valid.
|
||||
*
|
||||
*/
|
||||
protected void purgeFully()
|
||||
{
|
||||
BasicDBObject invalidQuery = new BasicDBObject();
|
||||
|
||||
invalidQuery.put(MongoSessionManager.__VALID, false);
|
||||
|
||||
DBCursor oldSessions = _sessions.find(invalidQuery, new BasicDBObject(MongoSessionManager.__ID, 1));
|
||||
|
||||
for (DBObject session : oldSessions)
|
||||
{
|
||||
String id = (String)session.get(MongoSessionManager.__ID);
|
||||
|
||||
__log.debug("MongoSessionIdManager:purging invalid " + id);
|
||||
|
||||
_sessions.remove(session);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public DBCollection getSessions()
|
||||
{
|
||||
return _sessions;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isPurgeEnabled()
|
||||
{
|
||||
return _purge;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setPurge(boolean purge)
|
||||
{
|
||||
this._purge = purge;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* sets the scavengeDelay
|
||||
*/
|
||||
public void setScavengeDelay(long scavengeDelay)
|
||||
{
|
||||
this._scavengeDelay = scavengeDelay;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setScavengePeriod(long scavengePeriod)
|
||||
{
|
||||
this._scavengePeriod = scavengePeriod;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setPurgeDelay(long purgeDelay)
|
||||
{
|
||||
if ( isRunning() )
|
||||
{
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
this._purgeDelay = purgeDelay;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public long getPurgeInvalidAge()
|
||||
{
|
||||
return _purgeInvalidAge;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* sets how old a session is to be persisted past the point it is
|
||||
* no longer valid
|
||||
*/
|
||||
public void setPurgeInvalidAge(long purgeValidAge)
|
||||
{
|
||||
this._purgeInvalidAge = purgeValidAge;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public long getPurgeValidAge()
|
||||
{
|
||||
return _purgeValidAge;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* sets how old a session is to be persist past the point it is
|
||||
* considered no longer viable and should be removed
|
||||
*
|
||||
* NOTE: set this value to 0 to disable purging of valid sessions
|
||||
*/
|
||||
public void setPurgeValidAge(long purgeValidAge)
|
||||
{
|
||||
this._purgeValidAge = purgeValidAge;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
__log.debug("MongoSessionIdManager:starting");
|
||||
|
||||
/*
|
||||
* setup the scavenger thread
|
||||
*/
|
||||
if (_scavengeDelay > 0)
|
||||
{
|
||||
_scavengeTimer = new Timer("MongoSessionIdScavenger",true);
|
||||
|
||||
synchronized (this)
|
||||
{
|
||||
if (_scavengerTask != null)
|
||||
{
|
||||
_scavengerTask.cancel();
|
||||
}
|
||||
|
||||
_scavengerTask = new TimerTask()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
scavenge();
|
||||
}
|
||||
};
|
||||
|
||||
_scavengeTimer.schedule(_scavengerTask,_scavengeDelay,_scavengePeriod);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* if purging is enabled, setup the purge thread
|
||||
*/
|
||||
if ( _purge )
|
||||
{
|
||||
_purgeTimer = new Timer("MongoSessionPurger", true);
|
||||
|
||||
synchronized (this)
|
||||
{
|
||||
if (_purgeTask != null)
|
||||
{
|
||||
_purgeTask.cancel();
|
||||
}
|
||||
_purgeTask = new TimerTask()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
purge();
|
||||
}
|
||||
};
|
||||
_purgeTimer.schedule(_purgeTask,_purgeDelay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
if (_scavengeTimer != null)
|
||||
{
|
||||
_scavengeTimer.cancel();
|
||||
_scavengeTimer = null;
|
||||
}
|
||||
|
||||
if (_purgeTimer != null)
|
||||
{
|
||||
_purgeTimer.cancel();
|
||||
_purgeTimer = null;
|
||||
}
|
||||
|
||||
super.doStop();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* is the session id known to mongo, and is it valid
|
||||
*/
|
||||
@Override
|
||||
public boolean idInUse(String sessionId)
|
||||
{
|
||||
/*
|
||||
* optimize this query to only return the valid variable
|
||||
*/
|
||||
DBObject o = _sessions.findOne(new BasicDBObject("id",sessionId), __valid_false);
|
||||
|
||||
if ( o != null )
|
||||
{
|
||||
Boolean valid = (Boolean)o.get(MongoSessionManager.__VALID);
|
||||
|
||||
if ( valid == null )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void addSession(HttpSession session)
|
||||
{
|
||||
if (session == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* already a part of the index in mongo...
|
||||
*/
|
||||
|
||||
__log.debug("MongoSessionIdManager:addSession:" + session.getId());
|
||||
|
||||
synchronized (_sessionsIds)
|
||||
{
|
||||
_sessionsIds.add(session.getId());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void removeSession(HttpSession session)
|
||||
{
|
||||
if (session == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (_sessionsIds)
|
||||
{
|
||||
_sessionsIds.remove(session.getId());
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void invalidateAll(String sessionId)
|
||||
{
|
||||
synchronized (_sessionsIds)
|
||||
{
|
||||
_sessionsIds.remove(sessionId);
|
||||
|
||||
|
||||
//tell all contexts that may have a session object with this id to
|
||||
//get rid of them
|
||||
Handler[] contexts = _server.getChildHandlersByClass(ContextHandler.class);
|
||||
for (int i=0; contexts!=null && i<contexts.length; i++)
|
||||
{
|
||||
SessionHandler sessionHandler = (SessionHandler)((ContextHandler)contexts[i]).getChildHandlerByClass(SessionHandler.class);
|
||||
if (sessionHandler != null)
|
||||
{
|
||||
SessionManager manager = sessionHandler.getSessionManager();
|
||||
|
||||
if (manager != null && manager instanceof MongoSessionManager)
|
||||
{
|
||||
((MongoSessionManager)manager).invalidateSession(sessionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
// TODO not sure if this is correct
|
||||
@Override
|
||||
public String getClusterId(String nodeId)
|
||||
{
|
||||
int dot=nodeId.lastIndexOf('.');
|
||||
return (dot>0)?nodeId.substring(0,dot):nodeId;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
// TODO not sure if this is correct
|
||||
@Override
|
||||
public String getNodeId(String clusterId, HttpServletRequest request)
|
||||
{
|
||||
if (_workerName!=null)
|
||||
return clusterId+'.'+_workerName;
|
||||
|
||||
return clusterId;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,549 @@
|
|||
package org.eclipse.jetty.nosql.mongodb;
|
||||
//========================================================================
|
||||
//Copyright (c) 2011 Intalio, Inc.
|
||||
//------------------------------------------------------------------------
|
||||
//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.
|
||||
//========================================================================
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.nosql.NoSqlSession;
|
||||
import org.eclipse.jetty.nosql.NoSqlSessionManager;
|
||||
import org.eclipse.jetty.server.SessionIdManager;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.omg.CORBA._IDLTypeStub;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBCollection;
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.MongoException;
|
||||
|
||||
public class MongoSessionManager extends NoSqlSessionManager
|
||||
{
|
||||
private final static Logger __log = Log.getLogger("org.eclipse.jetty.server.session");
|
||||
|
||||
/*
|
||||
* strings used as keys or parts of keys in mongo
|
||||
*/
|
||||
private final static String __METADATA = "__metadata__";
|
||||
|
||||
public final static String __ID = "id";
|
||||
private final static String __CREATED = "created";
|
||||
public final static String __VALID = "valid";
|
||||
public final static String __INVALIDATED = "invalidated";
|
||||
public final static String __ACCESSED = "accessed";
|
||||
private final static String __CONTEXT = "context";
|
||||
public final static String __VERSION = __METADATA + ".version";
|
||||
|
||||
/**
|
||||
* the context id is only set when this class has been started
|
||||
*/
|
||||
private String _contextId = null;
|
||||
|
||||
|
||||
private DBCollection _sessions;
|
||||
private DBObject __version_1;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public MongoSessionManager() throws UnknownHostException, MongoException
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*------------------------------------------------------------ */
|
||||
@Override
|
||||
public void doStart() throws Exception
|
||||
{
|
||||
super.doStart();
|
||||
String[] hosts = getContextHandler().getVirtualHosts();
|
||||
if (hosts == null || hosts.length == 0)
|
||||
hosts = getContextHandler().getConnectorNames();
|
||||
if (hosts == null || hosts.length == 0)
|
||||
hosts = new String[]
|
||||
{ "::" }; // IPv6 equiv of 0.0.0.0
|
||||
|
||||
String contextPath = getContext().getContextPath();
|
||||
if (contextPath == null || "".equals(contextPath))
|
||||
{
|
||||
contextPath = "*";
|
||||
}
|
||||
|
||||
_contextId = createContextId(hosts,contextPath);
|
||||
|
||||
__version_1 = new BasicDBObject(getContextKey(__VERSION),1);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.jetty.server.session.AbstractSessionManager#setSessionIdManager(org.eclipse.jetty.server.SessionIdManager)
|
||||
*/
|
||||
@Override
|
||||
public void setSessionIdManager(SessionIdManager metaManager)
|
||||
{
|
||||
MongoSessionIdManager msim = (MongoSessionIdManager)metaManager;
|
||||
_sessions=msim.getSessions();
|
||||
super.setSessionIdManager(metaManager);
|
||||
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected synchronized Object save(NoSqlSession session, Object version, boolean activateAfterSave)
|
||||
{
|
||||
try
|
||||
{
|
||||
__log.debug("MongoSessionManager:save:" + session);
|
||||
session.willPassivate();
|
||||
ByteArrayOutputStream bout = new ByteArrayOutputStream();
|
||||
ObjectOutputStream out = new ObjectOutputStream(bout);
|
||||
|
||||
// Form query for upsert
|
||||
BasicDBObject key = new BasicDBObject(__ID,session.getClusterId());
|
||||
key.put(__VALID,true);
|
||||
|
||||
// Form updates
|
||||
BasicDBObject update = new BasicDBObject();
|
||||
boolean upsert = false;
|
||||
BasicDBObject sets = new BasicDBObject();
|
||||
BasicDBObject unsets = new BasicDBObject();
|
||||
|
||||
// handle new or existing
|
||||
if (version == null)
|
||||
{
|
||||
// New session
|
||||
upsert = true;
|
||||
version = new Long(1);
|
||||
sets.put(__CREATED,session.getCreationTime());
|
||||
sets.put(getContextKey(__VERSION),version);
|
||||
}
|
||||
else
|
||||
{
|
||||
version = new Long(((Long)version).intValue() + 1);
|
||||
update.put("$inc",__version_1);
|
||||
}
|
||||
|
||||
// handle valid or invalid
|
||||
if (session.isValid())
|
||||
{
|
||||
sets.put(__ACCESSED,session.getAccessed());
|
||||
Set<String> names = session.takeDirty();
|
||||
if (isSaveAllAttributes() || upsert)
|
||||
{
|
||||
names.addAll(session.getNames()); // note dirty may include removed names
|
||||
}
|
||||
|
||||
for (String name : names)
|
||||
{
|
||||
Object value = session.getAttribute(name);
|
||||
if (value == null)
|
||||
unsets.put(getContextKey() + "." + encodeName(name),1);
|
||||
else
|
||||
sets.put(getContextKey() + "." + encodeName(name),encodeName(out,bout,value));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sets.put(__VALID,false);
|
||||
sets.put(__INVALIDATED, System.currentTimeMillis());
|
||||
unsets.put(getContextKey(),1);
|
||||
}
|
||||
|
||||
// Do the upsert
|
||||
if (!sets.isEmpty())
|
||||
update.put("$set",sets);
|
||||
if (!unsets.isEmpty())
|
||||
update.put("$unset",unsets);
|
||||
|
||||
_sessions.update(key,update,upsert,false);
|
||||
__log.debug("MongoSessionManager:save:db.sessions.update(" + key + "," + update + ",true)");
|
||||
|
||||
if (activateAfterSave)
|
||||
session.didActivate();
|
||||
|
||||
return version;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.warn(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------ */
|
||||
@Override
|
||||
protected Object refresh(NoSqlSession session, Object version)
|
||||
{
|
||||
__log.debug("MongoSessionManager:refresh " + session);
|
||||
|
||||
// check if our in memory version is the same as what is on the disk
|
||||
if (version != null)
|
||||
{
|
||||
DBObject o = _sessions.findOne(new BasicDBObject(__ID,session.getClusterId()),__version_1);
|
||||
|
||||
if (o != null)
|
||||
{
|
||||
Object saved = getNestedValue(o, getContextKey(__VERSION));
|
||||
|
||||
if (saved != null && saved.equals(version))
|
||||
{
|
||||
__log.debug("MongoSessionManager:refresh not needed");
|
||||
return version;
|
||||
}
|
||||
version = saved;
|
||||
}
|
||||
}
|
||||
|
||||
// If we are here, we have to load the object
|
||||
DBObject o = _sessions.findOne(new BasicDBObject(__ID,session.getClusterId()));
|
||||
|
||||
// If it doesn't exist, invalidate
|
||||
if (o == null)
|
||||
{
|
||||
__log.debug("MongoSessionManager:refresh:marking invalid, no object");
|
||||
session.invalidate();
|
||||
return null;
|
||||
}
|
||||
|
||||
// If it has been flagged invalid, invalidate
|
||||
Boolean valid = (Boolean)o.get(__VALID);
|
||||
if (valid == null || !valid)
|
||||
{
|
||||
__log.debug("MongoSessionManager:refresh:marking invalid, valid flag " + valid);
|
||||
session.invalidate();
|
||||
return null;
|
||||
}
|
||||
|
||||
// We need to update the attributes. We will model this as a passivate,
|
||||
// followed by bindings and then activation.
|
||||
session.willPassivate();
|
||||
try
|
||||
{
|
||||
session.clearAttributes();
|
||||
|
||||
DBObject attrs = (DBObject)getNestedValue(o,getContextKey());
|
||||
|
||||
if (attrs != null)
|
||||
{
|
||||
for (String name : attrs.keySet())
|
||||
{
|
||||
if ( __METADATA.equals(name) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
String attr = decodeName(name);
|
||||
Object value = decodeValue(attrs.get(name));
|
||||
session.doPutOrRemove(attr,value);
|
||||
session.bindValue(attr,value);
|
||||
}
|
||||
}
|
||||
|
||||
session.didActivate();
|
||||
|
||||
|
||||
return version;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.warn(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------ */
|
||||
@Override
|
||||
protected synchronized NoSqlSession loadSession(String clusterId)
|
||||
{
|
||||
DBObject o = _sessions.findOne(new BasicDBObject(__ID,clusterId));
|
||||
|
||||
__log.debug("MongoSessionManager:loaded " + o);
|
||||
|
||||
if (o == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Boolean valid = (Boolean)o.get(__VALID);
|
||||
if (valid == null || !valid)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Object version = o.get(getContextKey(__VERSION));
|
||||
Long created = (Long)o.get(__CREATED);
|
||||
Long accessed = (Long)o.get(__ACCESSED);
|
||||
|
||||
NoSqlSession session = new NoSqlSession(this,created,accessed,clusterId,version);
|
||||
|
||||
// get the attributes for the context
|
||||
DBObject attrs = (DBObject)getNestedValue(o,getContextKey());
|
||||
|
||||
__log.debug("MongoSessionManager:attrs: " + attrs);
|
||||
if (attrs != null)
|
||||
{
|
||||
for (String name : attrs.keySet())
|
||||
{
|
||||
if ( __METADATA.equals(name) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
String attr = decodeName(name);
|
||||
Object value = decodeValue(attrs.get(name));
|
||||
|
||||
session.doPutOrRemove(attr,value);
|
||||
session.bindValue(attr,value);
|
||||
|
||||
}
|
||||
}
|
||||
session.didActivate();
|
||||
|
||||
return session;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.warn(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------ */
|
||||
@Override
|
||||
protected boolean remove(NoSqlSession session)
|
||||
{
|
||||
__log.debug("MongoSessionManager:remove:session " + session.getClusterId());
|
||||
|
||||
/*
|
||||
* Check if the session exists and if it does remove the context
|
||||
* associated with this session
|
||||
*/
|
||||
BasicDBObject key = new BasicDBObject(__ID,session.getClusterId());
|
||||
|
||||
DBObject o = _sessions.findOne(key,__version_1);
|
||||
|
||||
if (o != null)
|
||||
{
|
||||
BasicDBObject remove = new BasicDBObject();
|
||||
BasicDBObject unsets = new BasicDBObject();
|
||||
unsets.put(getContextKey(),1);
|
||||
remove.put("$unsets",unsets);
|
||||
_sessions.update(key,remove);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void invalidateSession(String idInCluster)
|
||||
{
|
||||
__log.debug("MongoSessionManager:invalidateSession:invalidating " + idInCluster);
|
||||
|
||||
super.invalidateSession(idInCluster);
|
||||
|
||||
/*
|
||||
* pull back the 'valid' value, we can check if its false, if is we don't need to
|
||||
* reset it to false
|
||||
*/
|
||||
DBObject validKey = new BasicDBObject(__VALID, true);
|
||||
DBObject o = _sessions.findOne(new BasicDBObject(__ID,idInCluster), validKey);
|
||||
|
||||
if (o != null && (Boolean)o.get(__VALID))
|
||||
{
|
||||
BasicDBObject update = new BasicDBObject();
|
||||
BasicDBObject sets = new BasicDBObject();
|
||||
sets.put(__VALID,false);
|
||||
sets.put(__INVALIDATED, System.currentTimeMillis());
|
||||
update.put("$set",sets);
|
||||
|
||||
BasicDBObject key = new BasicDBObject(__ID,idInCluster);
|
||||
|
||||
_sessions.update(key,update);
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------ */
|
||||
protected String encodeName(String name)
|
||||
{
|
||||
return name.replace("%","%25").replace(".","%2E");
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------ */
|
||||
protected String decodeName(String name)
|
||||
{
|
||||
return name.replace("%2E",".").replace("%25","%");
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------ */
|
||||
protected Object encodeName(ObjectOutputStream out, ByteArrayOutputStream bout, Object value) throws IOException
|
||||
{
|
||||
if (value instanceof Number || value instanceof String || value instanceof Boolean || value instanceof Date)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
else if (value.getClass().equals(HashMap.class))
|
||||
{
|
||||
BasicDBObject o = new BasicDBObject();
|
||||
for (Map.Entry<?, ?> entry : ((Map<?, ?>)value).entrySet())
|
||||
{
|
||||
if (!(entry.getKey() instanceof String))
|
||||
{
|
||||
o = null;
|
||||
break;
|
||||
}
|
||||
o.append(encodeName(entry.getKey().toString()),encodeName(out,bout,value));
|
||||
}
|
||||
|
||||
if (o != null)
|
||||
return o;
|
||||
}
|
||||
|
||||
bout.reset();
|
||||
out.reset();
|
||||
out.writeUnshared(value);
|
||||
out.flush();
|
||||
return bout.toByteArray();
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------ */
|
||||
protected Object decodeValue(Object value) throws IOException, ClassNotFoundException
|
||||
{
|
||||
if (value == null || value instanceof Number || value instanceof String || value instanceof Boolean || value instanceof Date)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
else if (value instanceof byte[])
|
||||
{
|
||||
ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream((byte[])value));
|
||||
return in.readObject();
|
||||
}
|
||||
else if (value instanceof DBObject)
|
||||
{
|
||||
Map<String, Object> map = new HashMap<String, Object>();
|
||||
for (String name : ((DBObject)value).keySet())
|
||||
{
|
||||
String attr = decodeName(name);
|
||||
map.put(attr,decodeValue(((DBObject)value).get(name)));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalStateException(value.getClass().toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------ */
|
||||
private String getContextKey()
|
||||
{
|
||||
return __CONTEXT + "." + _contextId;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------ */
|
||||
private String getContextKey(String keybit)
|
||||
{
|
||||
return __CONTEXT + "." + _contextId + "." + keybit;
|
||||
}
|
||||
|
||||
public void purge()
|
||||
{
|
||||
((MongoSessionIdManager)_sessionIdManager).purge();
|
||||
}
|
||||
|
||||
public void purgeFully()
|
||||
{
|
||||
((MongoSessionIdManager)_sessionIdManager).purgeFully();
|
||||
}
|
||||
|
||||
public void scavenge()
|
||||
{
|
||||
((MongoSessionIdManager)_sessionIdManager).scavenge();
|
||||
}
|
||||
|
||||
public void scavengeFully()
|
||||
{
|
||||
((MongoSessionIdManager)_sessionIdManager).scavengeFully();
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------ */
|
||||
/**
|
||||
* returns the total number of session objects in the session store
|
||||
*
|
||||
* the count() operation itself is optimized to perform on the server side
|
||||
* and avoid loading to client side.
|
||||
*/
|
||||
public long getSessionStoreCount()
|
||||
{
|
||||
return _sessions.find().count();
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------ */
|
||||
/**
|
||||
* MongoDB keys are . delimited for nesting so .'s are protected characters
|
||||
*
|
||||
* @param virtualHosts
|
||||
* @param contextPath
|
||||
* @return
|
||||
*/
|
||||
private String createContextId(String[] virtualHosts, String contextPath)
|
||||
{
|
||||
String contextId = virtualHosts[0] + contextPath;
|
||||
|
||||
contextId.replace('/', '_');
|
||||
contextId.replace('.','_');
|
||||
contextId.replace('\\','_');
|
||||
|
||||
return contextId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dig through a given dbObject for the nested value
|
||||
*/
|
||||
private Object getNestedValue(DBObject dbObject, String nestedKey)
|
||||
{
|
||||
String[] keyChain = nestedKey.split("\\.");
|
||||
|
||||
DBObject temp = dbObject;
|
||||
|
||||
for (int i = 0; i < keyChain.length - 1; ++i)
|
||||
{
|
||||
temp = (DBObject)temp.get(keyChain[i]);
|
||||
|
||||
if ( temp == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return temp.get(keyChain[keyChain.length - 1]);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package org.eclipse.jetty.nosql.mongodb.jmx;
|
||||
|
||||
import org.eclipse.jetty.nosql.mongodb.MongoSessionManager;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandlerContainer;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.session.AbstractSessionManager;
|
||||
import org.eclipse.jetty.server.session.SessionHandler;
|
||||
import org.eclipse.jetty.server.session.jmx.AbstractSessionManagerMBean;
|
||||
|
||||
public class MongoSessionManagerMBean extends AbstractSessionManagerMBean
|
||||
{
|
||||
|
||||
public MongoSessionManagerMBean(Object managedObject)
|
||||
{
|
||||
super(managedObject);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public String getObjectContextBasis()
|
||||
{
|
||||
if (_managed != null && _managed instanceof MongoSessionManager)
|
||||
{
|
||||
MongoSessionManager manager = (MongoSessionManager)_managed;
|
||||
|
||||
String basis = null;
|
||||
SessionHandler handler = manager.getSessionHandler();
|
||||
if (handler != null)
|
||||
{
|
||||
ContextHandler context =
|
||||
AbstractHandlerContainer.findContainerOf(handler.getServer(),
|
||||
ContextHandler.class,
|
||||
handler);
|
||||
if (context != null)
|
||||
basis = getContextName(context);
|
||||
}
|
||||
|
||||
if (basis != null)
|
||||
return basis;
|
||||
}
|
||||
return super.getObjectContextBasis();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
MongoSessionManager: Mongo Session Manager
|
||||
sessionStoreCount: total number of known sessions in the store
|
||||
purge(): force a purge() of invalid sessions in the session store based on normal criteria
|
||||
purgeFully(): force a full purge of invalid sessions in the session store
|
||||
scavenge(): force a scavenge() of sessions known to this manager in the session store
|
||||
scavengeFully(): force a scavenge of all sessions in the session store
|
|
@ -0,0 +1,35 @@
|
|||
package org.eclipse.jetty.nosql.mongodb;
|
||||
|
||||
// ========================================================================
|
||||
// Copyright (c) 1996-2009 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.
|
||||
// ========================================================================
|
||||
|
||||
import org.eclipse.jetty.server.session.AbstractClientCrossContextSessionTest;
|
||||
import org.eclipse.jetty.server.session.AbstractTestServer;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ClientCrossContextSessionTest extends AbstractClientCrossContextSessionTest
|
||||
{
|
||||
public AbstractTestServer createServer(int port)
|
||||
{
|
||||
return new MongoTestServer(port);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore ("requires mongodb server")
|
||||
public void testCrossContextDispatch() throws Exception
|
||||
{
|
||||
super.testCrossContextDispatch();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package org.eclipse.jetty.nosql.mongodb;
|
||||
//========================================================================
|
||||
//Copyright (c) 2011 Intalio, Inc.
|
||||
//------------------------------------------------------------------------
|
||||
//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.
|
||||
//========================================================================
|
||||
|
||||
import org.eclipse.jetty.server.session.AbstractLastAccessTimeTest;
|
||||
import org.eclipse.jetty.server.session.AbstractTestServer;
|
||||
import org.junit.Ignore;
|
||||
|
||||
public class LastAccessTimeTest extends AbstractLastAccessTimeTest
|
||||
{
|
||||
|
||||
public AbstractTestServer createServer(int port, int max, int scavenge)
|
||||
{
|
||||
return new MongoTestServer(port,max,scavenge);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Ignore ("requires mongodb server")
|
||||
public void testLastAccessTime() throws Exception
|
||||
{
|
||||
super.testLastAccessTime();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package org.eclipse.jetty.nosql.mongodb;
|
||||
|
||||
// ========================================================================
|
||||
// Copyright (c) 1996-2009 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.
|
||||
// ========================================================================
|
||||
|
||||
import org.eclipse.jetty.server.session.AbstractLightLoadTest;
|
||||
import org.eclipse.jetty.server.session.AbstractTestServer;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* LightLoadTest
|
||||
*/
|
||||
public class LightLoadTest extends AbstractLightLoadTest
|
||||
{
|
||||
|
||||
public AbstractTestServer createServer(int port)
|
||||
{
|
||||
return new MongoTestServer(port);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore ("requires mongodb server")
|
||||
public void testLightLoad() throws Exception
|
||||
{
|
||||
super.testLightLoad();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package org.eclipse.jetty.nosql.mongodb;
|
||||
|
||||
//========================================================================
|
||||
//Copyright (c) 2011 Intalio, Inc.
|
||||
//------------------------------------------------------------------------
|
||||
//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.
|
||||
//========================================================================
|
||||
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.DBCollection;
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.Mongo;
|
||||
import com.mongodb.WriteResult;
|
||||
|
||||
public class MongoTest
|
||||
{
|
||||
public static void main(String... args) throws Exception
|
||||
{
|
||||
Mongo m = new Mongo( "127.0.0.1" , 27017 );
|
||||
|
||||
DB db = m.getDB( "mydb" );
|
||||
|
||||
Set<String> colls = db.getCollectionNames();
|
||||
|
||||
System.err.println("Colls="+colls);
|
||||
|
||||
DBCollection coll = db.getCollection("testCollection");
|
||||
|
||||
|
||||
BasicDBObject key = new BasicDBObject("id","1234");
|
||||
BasicDBObject sets = new BasicDBObject("name","value");
|
||||
BasicDBObject upsert=new BasicDBObject("$set",sets);
|
||||
|
||||
WriteResult result =coll.update(key,upsert,true,false);
|
||||
|
||||
System.err.println(result.getLastError());
|
||||
|
||||
|
||||
while (coll.count()>0)
|
||||
{
|
||||
DBObject docZ = coll.findOne();
|
||||
System.err.println("removing "+ docZ);
|
||||
if (docZ!=null)
|
||||
coll.remove(docZ);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
package org.eclipse.jetty.nosql.mongodb;
|
||||
|
||||
// ========================================================================
|
||||
// Copyright (c) 1996-2009 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.
|
||||
// ========================================================================
|
||||
|
||||
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.nosql.mongodb.MongoSessionIdManager;
|
||||
import org.eclipse.jetty.nosql.mongodb.MongoSessionManager;
|
||||
import org.eclipse.jetty.server.SessionIdManager;
|
||||
import org.eclipse.jetty.server.SessionManager;
|
||||
import org.eclipse.jetty.server.session.AbstractTestServer;
|
||||
import org.eclipse.jetty.server.session.SessionHandler;
|
||||
|
||||
|
||||
/**
|
||||
* @version $Revision$ $Date$
|
||||
*/
|
||||
public class MongoTestServer extends AbstractTestServer
|
||||
{
|
||||
|
||||
static MongoSessionIdManager _idManager;
|
||||
private boolean _saveAllAttributes = false; // false save dirty, true save all
|
||||
|
||||
public MongoTestServer(int port)
|
||||
{
|
||||
super(port, 30, 10);
|
||||
}
|
||||
|
||||
public MongoTestServer(int port, int maxInactivePeriod, int scavengePeriod)
|
||||
{
|
||||
super(port, maxInactivePeriod, scavengePeriod);
|
||||
}
|
||||
|
||||
|
||||
public MongoTestServer(int port, int maxInactivePeriod, int scavengePeriod, boolean saveAllAttributes)
|
||||
{
|
||||
super(port, maxInactivePeriod, scavengePeriod);
|
||||
|
||||
_saveAllAttributes = saveAllAttributes;
|
||||
}
|
||||
|
||||
public SessionIdManager newSessionIdManager()
|
||||
{
|
||||
if ( _idManager != null )
|
||||
{
|
||||
try
|
||||
{
|
||||
_idManager.stop();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
_idManager.setScavengeDelay(_scavengePeriod + 1000);
|
||||
_idManager.setScavengePeriod(_maxInactivePeriod);
|
||||
|
||||
try
|
||||
{
|
||||
_idManager.start();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return _idManager;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
System.err.println("MongoTestServer:SessionIdManager:" + _maxInactivePeriod + "/" + _scavengePeriod);
|
||||
_idManager = new MongoSessionIdManager(_server);
|
||||
|
||||
_idManager.setScavengeDelay((int)TimeUnit.SECONDS.toMillis(_scavengePeriod));
|
||||
_idManager.setScavengePeriod(_maxInactivePeriod);
|
||||
|
||||
return _idManager;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
public SessionManager newSessionManager()
|
||||
{
|
||||
MongoSessionManager manager;
|
||||
try
|
||||
{
|
||||
manager = new MongoSessionManager();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
manager.setSavePeriod(1);
|
||||
manager.setStalePeriod(0);
|
||||
manager.setSaveAllAttributes(_saveAllAttributes);
|
||||
//manager.setScavengePeriod((int)TimeUnit.SECONDS.toMillis(_scavengePeriod));
|
||||
return manager;
|
||||
}
|
||||
|
||||
public SessionHandler newSessionHandler(SessionManager sessionManager)
|
||||
{
|
||||
return new SessionHandler(sessionManager);
|
||||
}
|
||||
|
||||
public static void main(String... args) throws Exception
|
||||
{
|
||||
MongoTestServer server8080 = new MongoTestServer(8080);
|
||||
server8080.addContext("/").addServlet(SessionDump.class,"/");
|
||||
server8080.start();
|
||||
|
||||
MongoTestServer server8081 = new MongoTestServer(8081);
|
||||
server8081.addContext("/").addServlet(SessionDump.class,"/");
|
||||
server8081.start();
|
||||
|
||||
server8080.join();
|
||||
server8081.join();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package org.eclipse.jetty.nosql.mongodb;
|
||||
|
||||
// ========================================================================
|
||||
// Copyright (c) 1996-2009 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.
|
||||
// ========================================================================
|
||||
|
||||
import org.eclipse.jetty.server.session.AbstractNewSessionTest;
|
||||
import org.eclipse.jetty.server.session.AbstractTestServer;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* NewSessionTest
|
||||
*/
|
||||
public class NewSessionTest extends AbstractNewSessionTest
|
||||
{
|
||||
|
||||
public AbstractTestServer createServer(int port, int max, int scavenge)
|
||||
{
|
||||
return new MongoTestServer(port,max,scavenge);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore ("requires mongodb server")
|
||||
public void testNewSession() throws Exception
|
||||
{
|
||||
super.testNewSession();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package org.eclipse.jetty.nosql.mongodb;
|
||||
|
||||
// ========================================================================
|
||||
// Copyright (c) 1996-2009 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.
|
||||
// ========================================================================
|
||||
|
||||
import org.eclipse.jetty.server.session.AbstractOrphanedSessionTest;
|
||||
import org.eclipse.jetty.server.session.AbstractTestServer;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* OrphanedSessionTest
|
||||
*/
|
||||
public class OrphanedSessionTest extends AbstractOrphanedSessionTest
|
||||
{
|
||||
public AbstractTestServer createServer(int port, int max, int scavenge)
|
||||
{
|
||||
return new MongoTestServer(port,max,scavenge);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore ("requires mongodb server")
|
||||
public void testOrphanedSession() throws Exception
|
||||
{
|
||||
super.testOrphanedSession();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package org.eclipse.jetty.nosql.mongodb;
|
||||
|
||||
// ========================================================================
|
||||
// Copyright (c) 1996-2009 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.
|
||||
// ========================================================================
|
||||
|
||||
import org.eclipse.jetty.server.session.AbstractReentrantRequestSessionTest;
|
||||
import org.eclipse.jetty.server.session.AbstractTestServer;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* ReentrantRequestSessionTest
|
||||
*/
|
||||
public class ReentrantRequestSessionTest extends AbstractReentrantRequestSessionTest
|
||||
{
|
||||
public AbstractTestServer createServer(int port)
|
||||
{
|
||||
return new MongoTestServer(port);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore ("requires mongodb server")
|
||||
public void testReentrantRequestSession() throws Exception
|
||||
{
|
||||
super.testReentrantRequestSession();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package org.eclipse.jetty.nosql.mongodb;
|
||||
//========================================================================
|
||||
//Copyright (c) 2011 Intalio, Inc.
|
||||
//------------------------------------------------------------------------
|
||||
//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.
|
||||
//========================================================================
|
||||
|
||||
import org.eclipse.jetty.server.session.AbstractRemoveSessionTest;
|
||||
import org.eclipse.jetty.server.session.AbstractTestServer;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
public class RemoveSessionTest extends AbstractRemoveSessionTest
|
||||
{
|
||||
|
||||
public AbstractTestServer createServer(int port, int max, int scavenge)
|
||||
{
|
||||
return new MongoTestServer(port,max,scavenge);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore ("requires mongodb server")
|
||||
public void testRemoveSession() throws Exception
|
||||
{
|
||||
super.testRemoveSession();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package org.eclipse.jetty.nosql.mongodb;
|
||||
|
||||
// ========================================================================
|
||||
// Copyright (c) 1996-2009 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.
|
||||
// ========================================================================
|
||||
|
||||
import org.eclipse.jetty.server.session.AbstractServerCrossContextSessionTest;
|
||||
import org.eclipse.jetty.server.session.AbstractTestServer;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ServerCrossContextSessionTest extends AbstractServerCrossContextSessionTest
|
||||
{
|
||||
public AbstractTestServer createServer(int port)
|
||||
{
|
||||
return new MongoTestServer(port);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore ("requires mongodb server")
|
||||
public void testCrossContextDispatch() throws Exception
|
||||
{
|
||||
super.testCrossContextDispatch();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,181 @@
|
|||
package org.eclipse.jetty.nosql.mongodb;
|
||||
|
||||
// ========================================================================
|
||||
// Copyright (c) 1996-2009 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.
|
||||
// ========================================================================
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Test Servlet Sessions.
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class SessionDump extends HttpServlet
|
||||
{
|
||||
|
||||
int redirectCount=0;
|
||||
/* ------------------------------------------------------------ */
|
||||
String pageType;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void init(ServletConfig config)
|
||||
throws ServletException
|
||||
{
|
||||
super.init(config);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void handleForm(HttpServletRequest request,
|
||||
HttpServletResponse response)
|
||||
{
|
||||
HttpSession session = request.getSession(false);
|
||||
String action = request.getParameter("Action");
|
||||
String name = request.getParameter("Name");
|
||||
String value = request.getParameter("Value");
|
||||
|
||||
if (action!=null)
|
||||
{
|
||||
if(action.equals("New Session"))
|
||||
{
|
||||
session = request.getSession(true);
|
||||
session.setAttribute("test","value");
|
||||
}
|
||||
else if (session!=null)
|
||||
{
|
||||
if (action.equals("Invalidate"))
|
||||
session.invalidate();
|
||||
else if (action.equals("Set") && name!=null && name.length()>0)
|
||||
session.setAttribute(name,value);
|
||||
else if (action.equals("Remove"))
|
||||
session.removeAttribute(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void doPost(HttpServletRequest request,
|
||||
HttpServletResponse response)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
handleForm(request,response);
|
||||
String nextUrl = getURI(request)+"?R="+redirectCount++;
|
||||
String encodedUrl=response.encodeRedirectURL(nextUrl);
|
||||
response.sendRedirect(encodedUrl);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void doGet(HttpServletRequest request,
|
||||
HttpServletResponse response)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
handleForm(request,response);
|
||||
|
||||
response.setContentType("text/html");
|
||||
|
||||
HttpSession session = request.getSession(getURI(request).indexOf("new")>0);
|
||||
try
|
||||
{
|
||||
if (session!=null)
|
||||
session.isNew();
|
||||
}
|
||||
catch(IllegalStateException e)
|
||||
{
|
||||
session=null;
|
||||
}
|
||||
|
||||
PrintWriter out = response.getWriter();
|
||||
out.println("<h1>Session Dump Servlet:</h1>");
|
||||
out.println("<form action=\""+response.encodeURL(getURI(request))+"\" method=\"post\">");
|
||||
|
||||
if (session==null)
|
||||
{
|
||||
out.println("<H3>No Session</H3>");
|
||||
out.println("<input type=\"submit\" name=\"Action\" value=\"New Session\"/>");
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
out.println("<b>ID:</b> "+session.getId()+"<br/>");
|
||||
out.println("<b>New:</b> "+session.isNew()+"<br/>");
|
||||
out.println("<b>Created:</b> "+new Date(session.getCreationTime())+"<br/>");
|
||||
out.println("<b>Last:</b> "+new Date(session.getLastAccessedTime())+"<br/>");
|
||||
out.println("<b>Max Inactive:</b> "+session.getMaxInactiveInterval()+"<br/>");
|
||||
out.println("<b>Context:</b> "+session.getServletContext()+"<br/>");
|
||||
|
||||
|
||||
Enumeration keys=session.getAttributeNames();
|
||||
while(keys.hasMoreElements())
|
||||
{
|
||||
String name=(String)keys.nextElement();
|
||||
String value=""+session.getAttribute(name);
|
||||
|
||||
out.println("<b>"+name+":</b> "+value+"<br/>");
|
||||
}
|
||||
|
||||
out.println("<b>Name:</b><input type=\"text\" name=\"Name\" /><br/>");
|
||||
out.println("<b>Value:</b><input type=\"text\" name=\"Value\" /><br/>");
|
||||
|
||||
out.println("<input type=\"submit\" name=\"Action\" value=\"Set\"/>");
|
||||
out.println("<input type=\"submit\" name=\"Action\" value=\"Remove\"/>");
|
||||
out.println("<input type=\"submit\" name=\"Action\" value=\"Refresh\"/>");
|
||||
out.println("<input type=\"submit\" name=\"Action\" value=\"Invalidate\"/><br/>");
|
||||
|
||||
out.println("</form><br/>");
|
||||
|
||||
if (request.isRequestedSessionIdFromCookie())
|
||||
out.println("<P>Turn off cookies in your browser to try url encoding<BR>");
|
||||
|
||||
if (request.isRequestedSessionIdFromURL())
|
||||
out.println("<P>Turn on cookies in your browser to try cookie encoding<BR>");
|
||||
out.println("<a href=\""+response.encodeURL(request.getRequestURI()+"?q=0")+"\">Encoded Link</a><BR>");
|
||||
|
||||
}
|
||||
catch (IllegalStateException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public String getServletInfo() {
|
||||
return "Session Dump Servlet";
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private String getURI(HttpServletRequest request)
|
||||
{
|
||||
String uri=(String)request.getAttribute("javax.servlet.forward.request_uri");
|
||||
if (uri==null)
|
||||
uri=request.getRequestURI();
|
||||
return uri;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,246 @@
|
|||
package org.eclipse.jetty.nosql.mongodb;
|
||||
|
||||
//========================================================================
|
||||
//Copyright (c) 2011 Intalio, Inc.
|
||||
//------------------------------------------------------------------------
|
||||
//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.
|
||||
//========================================================================
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Serializable;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.net.MalformedURLException;
|
||||
|
||||
import javax.management.remote.JMXServiceURL;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.client.ContentExchange;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.http.HttpMethods;
|
||||
import org.eclipse.jetty.jmx.ConnectorServer;
|
||||
import org.eclipse.jetty.jmx.MBeanContainer;
|
||||
import org.eclipse.jetty.nosql.NoSqlSession;
|
||||
import org.eclipse.jetty.server.session.AbstractSessionValueSavingTest;
|
||||
import org.eclipse.jetty.server.session.AbstractTestServer;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
public class SessionSavingValueTest extends AbstractSessionValueSavingTest
|
||||
{
|
||||
|
||||
|
||||
|
||||
public AbstractTestServer createServer(int port, int max, int scavenge)
|
||||
{
|
||||
// ConnectorServer srv = null;
|
||||
try
|
||||
{
|
||||
// srv = new ConnectorServer(
|
||||
// new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:0/jettytest"),
|
||||
// "org.eclipse.jetty:name=rmiconnectorserver");
|
||||
// srv.start();
|
||||
|
||||
MongoTestServer server = new MongoTestServer(port,max,scavenge,true);
|
||||
|
||||
// MBeanContainer mbean = new MBeanContainer(ManagementFactory.getPlatformMBeanServer());
|
||||
//
|
||||
// server.getServer().getContainer().addEventListener(mbean);
|
||||
// server.getServer().addBean(mbean);
|
||||
//
|
||||
// mbean.start();
|
||||
|
||||
return server;
|
||||
|
||||
}
|
||||
// catch (MalformedURLException e)
|
||||
// {
|
||||
// // TODO Auto-generated catch block
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
catch (Exception e)
|
||||
{
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore ("requires mongodb server")
|
||||
public void testSessionValueSaving() throws Exception
|
||||
{
|
||||
String contextPath = "";
|
||||
String servletMapping = "/server";
|
||||
int maxInactivePeriod = 10000;
|
||||
int scavengePeriod = 20000;
|
||||
AbstractTestServer server1 = createServer(0,maxInactivePeriod,scavengePeriod);
|
||||
server1.addContext(contextPath).addServlet(TestServlet.class,servletMapping);
|
||||
server1.start();
|
||||
int port1 = server1.getPort();
|
||||
try
|
||||
{
|
||||
|
||||
HttpClient client = new HttpClient();
|
||||
client.setConnectorType(HttpClient.CONNECTOR_SOCKET);
|
||||
client.start();
|
||||
try
|
||||
{
|
||||
String[] sessionTestValue = new String[]
|
||||
{ "0", "null" };
|
||||
|
||||
// Perform one request to server1 to create a session
|
||||
ContentExchange exchange1 = new ContentExchange(true);
|
||||
exchange1.setMethod(HttpMethods.GET);
|
||||
exchange1.setURL("http://localhost:" + port1 + contextPath + servletMapping + "?action=init");
|
||||
client.send(exchange1);
|
||||
exchange1.waitForDone();
|
||||
assertEquals(HttpServletResponse.SC_OK,exchange1.getResponseStatus());
|
||||
|
||||
String[] sessionTestResponse = exchange1.getResponseContent().split("/");
|
||||
assertTrue(Long.parseLong(sessionTestValue[0]) < Long.parseLong(sessionTestResponse[0]));
|
||||
|
||||
sessionTestValue = sessionTestResponse;
|
||||
|
||||
String sessionCookie = exchange1.getResponseFields().getStringField("Set-Cookie");
|
||||
assertTrue(sessionCookie != null);
|
||||
// Mangle the cookie, replacing Path with $Path, etc.
|
||||
sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=","$1\\$Path=");
|
||||
|
||||
// Perform some request to server2 using the session cookie from the previous request
|
||||
// This should migrate the session from server1 to server2, and leave server1's
|
||||
// session in a very stale state, while server2 has a very fresh session.
|
||||
// We want to test that optimizations done to the saving of the shared lastAccessTime
|
||||
// do not break the correct working
|
||||
int requestInterval = 500;
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{
|
||||
ContentExchange exchange2 = new ContentExchange(true);
|
||||
exchange2.setMethod(HttpMethods.GET);
|
||||
exchange2.setURL("http://localhost:" + port1 + contextPath + servletMapping);
|
||||
exchange2.getRequestFields().add("Cookie",sessionCookie);
|
||||
client.send(exchange2);
|
||||
exchange2.waitForDone();
|
||||
assertEquals(HttpServletResponse.SC_OK,exchange2.getResponseStatus());
|
||||
|
||||
sessionTestResponse = exchange2.getResponseContent().split("/");
|
||||
|
||||
assertTrue(Long.parseLong(sessionTestValue[0]) < Long.parseLong(sessionTestResponse[0]));
|
||||
assertTrue(Long.parseLong(sessionTestValue[1]) < Long.parseLong(sessionTestResponse[1]));
|
||||
|
||||
sessionTestValue = sessionTestResponse;
|
||||
|
||||
String setCookie = exchange1.getResponseFields().getStringField("Set-Cookie");
|
||||
if (setCookie != null)
|
||||
sessionCookie = setCookie.replaceFirst("(\\W)(P|p)ath=","$1\\$Path=");
|
||||
|
||||
Thread.sleep(requestInterval);
|
||||
}
|
||||
|
||||
// Thread.sleep(320000);
|
||||
}
|
||||
finally
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
server1.stop();
|
||||
}
|
||||
}
|
||||
|
||||
public static class TestServlet extends HttpServlet
|
||||
{
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse httpServletResponse) throws ServletException, IOException
|
||||
{
|
||||
String action = request.getParameter("action");
|
||||
if ("init".equals(action))
|
||||
{
|
||||
NoSqlSession session = (NoSqlSession)request.getSession(true);
|
||||
session.setAttribute("test",System.currentTimeMillis());
|
||||
session.setAttribute("objectTest", new Pojo("foo","bar"));
|
||||
|
||||
sendResult(session,httpServletResponse.getWriter());
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
NoSqlSession session = (NoSqlSession)request.getSession(false);
|
||||
if (session != null)
|
||||
{
|
||||
long value = System.currentTimeMillis();
|
||||
session.setAttribute("test",value);
|
||||
|
||||
}
|
||||
|
||||
sendResult(session,httpServletResponse.getWriter());
|
||||
|
||||
Pojo p = (Pojo)session.getAttribute("objectTest");
|
||||
|
||||
//System.out.println(p.getName() + " / " + p.getValue() );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void sendResult(NoSqlSession session, PrintWriter writer)
|
||||
{
|
||||
if (session != null)
|
||||
{
|
||||
if (session.getVersion() == null)
|
||||
{
|
||||
writer.print(session.getAttribute("test") + "/-1");
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.print(session.getAttribute("test") + "/" + session.getVersion());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.print("0/-1");
|
||||
}
|
||||
}
|
||||
|
||||
public class Pojo implements Serializable
|
||||
{
|
||||
private String _name;
|
||||
private String _value;
|
||||
|
||||
public Pojo( String name, String value )
|
||||
{
|
||||
_name = name;
|
||||
_value = value;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
public String getValue()
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue