Add new test-sessions module to do testing of various session implementations. The test-session-common module was created based on the terracotta session test suite checked into jetty-codehaus. I've genericized these tests so that they may be applied to the various session clustering solutions.

Changes to JDBCSessionIdManager with this checkin were to increase the length of the varchar storing the session id from 60 to 120 char, and also to reduce the amount of time we held a lock over the session id map.

Changes to the JDBCSessionManager with this checkin were to decrease the amount of time we held locks, and when retrieving a session from the database, checking if the session had expired before loading it.

Changes to the AbstractSessionManager with this checkin were to ensure that the SessionListeners were only called if the session was removed (we were calling them anyway).


git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@1213 7e9141cc-0065-0410-87d8-b60c137991c4
This commit is contained in:
Jan Bartel 2010-01-26 01:37:03 +00:00
parent c706695eca
commit 28453e9c24
42 changed files with 3168 additions and 108 deletions

View File

@ -631,39 +631,36 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement
public void removeSession(Session session, boolean invalidate)
{
// Remove session from context and global maps
//noinspection SynchronizeOnNonFinalField
synchronized (_sessionIdManager)
boolean removed = false;
synchronized (this)
{
boolean removed = false;
synchronized (this)
//take this session out of the map of sessions for this context
if (getSession(session.getClusterId()) != null)
{
//take this session out of the map of sessions for this context
if (getSession(session.getClusterId()) != null)
{
removed = true;
removeSession(session.getClusterId());
}
}
if (removed)
{
// Remove session from all context and global id maps
_sessionIdManager.removeSession(session);
if (invalidate)
_sessionIdManager.invalidateAll(session.getClusterId());
removed = true;
removeSession(session.getClusterId());
}
}
if (invalidate && _sessionListeners!=null)
if (removed)
{
HttpSessionEvent event=new HttpSessionEvent(session);
for (int i=LazyList.size(_sessionListeners); i-->0;)
((HttpSessionListener)LazyList.get(_sessionListeners,i)).sessionDestroyed(event);
}
if (!invalidate)
{
session.willPassivate();
// Remove session from all context and global id maps
_sessionIdManager.removeSession(session);
if (invalidate)
_sessionIdManager.invalidateAll(session.getClusterId());
if (invalidate && _sessionListeners!=null)
{
HttpSessionEvent event=new HttpSessionEvent(session);
for (int i=LazyList.size(_sessionListeners); i-->0;)
((HttpSessionListener)LazyList.get(_sessionListeners,i)).sessionDestroyed(event);
}
if (!invalidate)
{
session.willPassivate();
}
}
}

View File

@ -318,22 +318,24 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
return false;
String clusterId = getClusterId(id);
boolean inUse = false;
synchronized (_sessionIds)
{
if (_sessionIds.contains(clusterId))
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(clusterId);
}
catch (Exception e)
{
Log.warn("Problem checking inUse for id="+clusterId, e);
return false;
}
inUse = _sessionIds.contains(clusterId);
}
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(clusterId);
}
catch (Exception e)
{
Log.warn("Problem checking inUse for id="+clusterId, e);
return false;
}
}
@ -452,7 +454,7 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
private void prepareTables()
throws SQLException
{
_createSessionIdTable = "create table "+_sessionIdTable+" (id varchar(60), primary key(id))";
_createSessionIdTable = "create table "+_sessionIdTable+" (id varchar(120), primary key(id))";
_selectExpiredSessions = "select * from "+_sessionTable+" where expiryTime >= ? and expiryTime <= ?";
_deleteOldExpiredSessions = "delete from "+_sessionTable+" where expiryTime >0 and expiryTime <= ?";
@ -485,7 +487,7 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
{
//table does not exist, so create it
String blobType = _dbAdaptor.getBlobType();
_createSessionTable = "create table "+_sessionTable+" (rowId varchar(60), sessionId varchar(60), "+
_createSessionTable = "create table "+_sessionTable+" (rowId varchar(120), sessionId varchar(120), "+
" contextPath varchar(60), virtualHost varchar(60), lastNode varchar(60), accessTime bigint, "+
" lastAccessTime bigint, createTime bigint, cookieTime bigint, "+
" lastSavedTime bigint, expiryTime bigint, map "+blobType+", primary key(rowId))";
@ -634,7 +636,8 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
PreparedStatement statement = connection.prepareStatement(_selectExpiredSessions);
long lowerBound = (_lastScavengeTime - _scavengeIntervalMs);
long upperBound = _lastScavengeTime;
if (Log.isDebugEnabled()) Log.debug("Searching for sessions expired between "+lowerBound + " and "+upperBound);
if (Log.isDebugEnabled()) Log.debug (" Searching for sessions expired between "+lowerBound + " and "+upperBound);
statement.setLong(1, lowerBound);
statement.setLong(2, upperBound);
ResultSet result = statement.executeQuery();
@ -642,10 +645,9 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
{
String sessionId = result.getString("sessionId");
expiredSessionIds.add(sessionId);
if (Log.isDebugEnabled()) Log.debug("Found expired sessionId="+sessionId);
if (Log.isDebugEnabled()) Log.debug (" Found expired sessionId="+sessionId);
}
//tell the SessionManagers to expire any sessions with a matching sessionId in memory
Handler[] contexts = _server.getChildHandlersByClass(ContextHandler.class);
for (int i=0; contexts!=null && i<contexts.length; i++)

View File

@ -213,7 +213,7 @@ public class JDBCSessionManager extends AbstractSessionManager
public synchronized void setExpiryTime (long time)
{
_expiryTime=time;
_expiryTime=time;
}
public synchronized long getExpiryTime ()
@ -278,6 +278,7 @@ public class JDBCSessionManager extends AbstractSessionManager
{
super(data.getCreated(), data.getId());
_data=data;
_data.setMaxIdleMs(_dftMaxIdleSecs*1000);
_values=data.getAttributeMap();
}
@ -466,6 +467,7 @@ public class JDBCSessionManager extends AbstractSessionManager
" lastSaved="+(session==null?0:session._data._lastSaved)+
" interval="+(_saveIntervalSec * 1000)+
" difference="+(now - (session==null?0:session._data._lastSaved)));
if (session==null || ((now - session._data._lastSaved) >= (_saveIntervalSec * 1000)))
{
data = loadSession(idInCluster, canonicalize(_context.getContextPath()), getVirtualHost(_context));
@ -477,13 +479,17 @@ public class JDBCSessionManager extends AbstractSessionManager
{
if (!data.getLastNode().equals(getIdManager().getWorkerName()) || session==null)
{
//session last used on a different node, or we don't have it in memory
session = new Session(data);
_sessions.put(idInCluster, session);
session.didActivate();
//TODO is this the best way to do this? Or do this on the way out using
//the _dirty flag?
updateSessionNode(data);
//if the session in the database has not already expired
if (data._expiryTime > System.currentTimeMillis())
{
//session last used on a different node, or we don't have it in memory
session = new Session(data);
_sessions.put(idInCluster, session);
session.didActivate();
//TODO is this the best way to do this? Or do this on the way out using
//the _dirty flag?
updateSessionNode(data);
}
}
else
if (Log.isDebugEnabled()) Log.debug("Session not stale "+session._data);
@ -587,13 +593,15 @@ public class JDBCSessionManager extends AbstractSessionManager
*/
protected void invalidateSession (String idInCluster)
{
Session session = null;
synchronized (this)
{
Session session = (Session)_sessions.get(idInCluster);
if (session != null)
{
session.invalidate();
}
session = (Session)_sessions.get(idInCluster);
}
if (session != null)
{
session.invalidate();
}
}
@ -606,17 +614,19 @@ public class JDBCSessionManager extends AbstractSessionManager
@Override
protected void removeSession(String idInCluster)
{
Session session = null;
synchronized (this)
{
try
{
Session session = (Session)_sessions.remove(idInCluster);
deleteSession(session._data);
}
catch (Exception e)
{
Log.warn("Problem deleting session id="+idInCluster, e);
}
session = (Session)_sessions.remove(idInCluster);
}
try
{
if (session != null)
deleteSession(session._data);
}
catch (Exception e)
{
Log.warn("Problem deleting session id="+idInCluster, e);
}
}
@ -631,22 +641,23 @@ public class JDBCSessionManager extends AbstractSessionManager
{
if (session==null)
return;
synchronized (this)
{
_sessions.put(session.getClusterId(), session);
//TODO or delay the store until exit out of session? If we crash before we store it
//then session data will be lost.
try
{
session.willPassivate();
storeSession(((JDBCSessionManager.Session)session)._data);
session.didActivate();
}
catch (Exception e)
{
Log.warn("Unable to store new session id="+session.getId() , e);
}
}
//TODO or delay the store until exit out of session? If we crash before we store it
//then session data will be lost.
try
{
session.willPassivate();
storeSession(((JDBCSessionManager.Session)session)._data);
session.didActivate();
}
catch (Exception e)
{
Log.warn("Unable to store new session id="+session.getId() , e);
}
}
@ -672,38 +683,36 @@ public class JDBCSessionManager extends AbstractSessionManager
public void removeSession(AbstractSessionManager.Session session, boolean invalidate)
{
// Remove session from context and global maps
synchronized (_sessionIdManager)
boolean removed = false;
synchronized (this)
{
boolean removed = false;
synchronized (this)
//take this session out of the map of sessions for this context
if (getSession(session.getClusterId()) != null)
{
//take this session out of the map of sessions for this context
if (_sessions.get(session.getClusterId()) != null)
{
removed = true;
removeSession(session.getClusterId());
}
}
if (removed)
{
// Remove session from all context and global id maps
_sessionIdManager.removeSession(session);
if (invalidate)
_sessionIdManager.invalidateAll(session.getClusterId());
removed = true;
removeSession(session.getClusterId());
}
}
if (invalidate && _sessionListeners!=null)
if (removed)
{
HttpSessionEvent event=new HttpSessionEvent(session);
for (int i=LazyList.size(_sessionListeners); i-->0;)
((HttpSessionListener)LazyList.get(_sessionListeners,i)).sessionDestroyed(event);
}
if (!invalidate)
{
session.willPassivate();
// Remove session from all context and global id maps
_sessionIdManager.removeSession(session);
if (invalidate)
_sessionIdManager.invalidateAll(session.getClusterId());
if (invalidate && _sessionListeners!=null)
{
HttpSessionEvent event=new HttpSessionEvent(session);
for (int i=LazyList.size(_sessionListeners); i-->0;)
((HttpSessionListener)LazyList.get(_sessionListeners,i)).sessionDestroyed(event);
}
if (!invalidate)
{
session.willPassivate();
}
}
}
@ -731,6 +740,7 @@ public class JDBCSessionManager extends AbstractSessionManager
{
String sessionId = (String)itor.next();
if (Log.isDebugEnabled()) Log.debug("Expiring session id "+sessionId);
Session session = (Session)_sessions.get(sessionId);
if (session != null)
{

View File

@ -32,5 +32,6 @@
<modules>
<module>test-integration</module>
<module>test-webapps</module>
<module>test-sessions</module>
</modules>
</project>

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
// ========================================================================
// Copyright (c) Webtide LLC
//
// 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.apache.org/licenses/LICENSE-2.0.txt
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
-->
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>tests-parent</artifactId>
<version>7.0.2-SNAPSHOT</version>
</parent>
<artifactId>test-sessions-parent</artifactId>
<name>Jetty Tests :: Sessions :: Parent</name>
<packaging>pom</packaging>
<build>
</build>
<modules>
<module>test-sessions-common</module>
<module>test-hash-sessions</module>
<module>test-jdbc-sessions</module>
</modules>
</project>

View File

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
// ========================================================================
// Copyright (c) Webtide LLC
//
// 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.apache.org/licenses/LICENSE-2.0.txt
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
-->
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>test-sessions-parent</artifactId>
<version>7.0.2-SNAPSHOT</version>
</parent>
<artifactId>test-hash-sessions</artifactId>
<name>Jetty Tests :: Sessions :: Hash</name>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<groups>hash-all</groups>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>test-sessions-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>5.8</version>
<classifier>jdk15</classifier>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,34 @@
// ========================================================================
// Copyright 2010 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 org.testng.annotations.Test;
public class ClientCrossContextSessionTest extends AbstractClientCrossContextSessionTest
{
public AbstractTestServer createServer(int port)
{
return new HashTestServer(port);
}
@Test(groups={"hash-all"})
public void testCrossContextDispatch() throws Exception
{
super.testCrossContextDispatch();
}
}

View File

@ -0,0 +1,56 @@
// ========================================================================
// Copyright 2004-2005 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========================================================================
package org.eclipse.jetty.server.session;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.server.SessionIdManager;
import org.eclipse.jetty.server.SessionManager;
/**
* @version $Revision$ $Date$
*/
public class HashTestServer extends AbstractTestServer
{
public HashTestServer(int port)
{
super(port, 30, 10);
}
public HashTestServer(int port, int maxInactivePeriod, int scavengePeriod)
{
super(port, maxInactivePeriod, scavengePeriod);
}
public SessionIdManager newSessionIdManager()
{
return new HashSessionIdManager();
}
public AbstractSessionManager newSessionManager()
{
HashSessionManager manager = new HashSessionManager();
manager.setScavengePeriod((int)TimeUnit.SECONDS.toMillis(_scavengePeriod));
return manager;
}
public SessionHandler newSessionHandler(SessionManager sessionManager)
{
return new SessionHandler(sessionManager);
}
}

View File

@ -0,0 +1,36 @@
//========================================================================
// Copyright 2010 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 org.testng.annotations.Test;
/**
* LightLoadTest
*
*
*/
public class LightLoadTest extends AbstractLightLoadTest
{
public AbstractTestServer createServer(int port)
{
return new HashTestServer(port);
}
@Test(groups={"hash-all"})
public void testLightLoad() throws Exception
{
super.testLightLoad();
}
}

View File

@ -0,0 +1,37 @@
//========================================================================
// Copyright 2010 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 org.testng.annotations.Test;
/**
* NewSessionTest
*
*
*/
public class NewSessionTest extends AbstractNewSessionTest
{
public AbstractTestServer createServer(int port, int max, int scavenge)
{
return new HashTestServer(port,max,scavenge);
}
@Test(groups={"hash-all"})
public void testNewSession() throws Exception
{
super.testNewSession();
}
}

View File

@ -0,0 +1,36 @@
//========================================================================
//Copyright 2010 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 org.testng.annotations.Test;
/**
* OrphanedSessionTest
*
*
*/
public class OrphanedSessionTest extends AbstractOrphanedSessionTest
{
public AbstractTestServer createServer(int port, int max, int scavenge)
{
return new HashTestServer(port,max,scavenge);
}
@Test(groups={"hash-all"})
public void testOrphanedSession() throws Exception
{
super.testOrphanedSession();
}
}

View File

@ -0,0 +1,35 @@
//========================================================================
//Copyright 2010 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 org.testng.annotations.Test;
/**
* ReentrantRequestSessionTest
*
*
*/
public class ReentrantRequestSessionTest extends AbstractReentrantRequestSessionTest
{
public AbstractTestServer createServer(int port)
{
return new HashTestServer(port);
}
@Test(groups={"hash-all"})
public void testReentrantRequestSession() throws Exception
{
super.testReentrantRequestSession();
}
}

View File

@ -0,0 +1,34 @@
// ========================================================================
// Copyright 2010 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 org.testng.annotations.Test;
public class ServerCrossContextSessionTest extends AbstractServerCrossContextSessionTest
{
public AbstractTestServer createServer(int port)
{
return new HashTestServer(port);
}
@Test(groups={"hash-all"})
public void testCrossContextDispatch() throws Exception
{
super.testCrossContextDispatch();
}
}

View File

@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
// ========================================================================
// Copyright (c) Webtide LLC
//
// 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.apache.org/licenses/LICENSE-2.0.txt
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
-->
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>test-sessions-parent</artifactId>
<version>7.0.2-SNAPSHOT</version>
</parent>
<artifactId>test-jdbc-sessions</artifactId>
<name>Jetty Tests :: Sessions :: JDBC</name>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<groups>jdbc-all</groups>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>test-sessions-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
<version>10.4.1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derbytools</artifactId>
<version>10.4.1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>5.8</version>
<classifier>jdk15</classifier>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,40 @@
//========================================================================
//Copyright 2010 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 org.testng.annotations.Test;
/**
* ClientCrossContextSessionTest
*
*
*/
public class ClientCrossContextSessionTest extends AbstractClientCrossContextSessionTest
{
public AbstractTestServer createServer(int port)
{
return new JdbcTestServer(port);
}
@Test(groups={"jdbc-all"})
public void testCrossContextDispatch() throws Exception
{
super.testCrossContextDispatch();
}
}

View File

@ -0,0 +1,39 @@
//========================================================================
//Copyright 2010 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 org.testng.annotations.Test;
/**
* ImmortalSessionTest
*
*
*/
public class ImmortalSessionTest extends AbstractImmortalSessionTest
{
public AbstractTestServer createServer(int port, int maxInactiveMs, int scavengeMs)
{
return new JdbcTestServer(port, maxInactiveMs, scavengeMs);
}
@Test(groups={"jdbc-all"})
public void testImmortalSession() throws Exception
{
super.testImmortalSession();
}
}

View File

@ -0,0 +1,52 @@
//========================================================================
//Copyright 2010 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 org.testng.annotations.Test;
/**
* InvalidationSessionTest
*
*
*/
public class InvalidationSessionTest extends AbstractInvalidationSessionTest
{
public AbstractTestServer createServer(int port)
{
return new JdbcTestServer(port);
}
public void pause()
{
//This test moves around a session between 2 nodes. Due to optimizations in the handling of
//the sessions for the JDBC SessionManager, this can mean that a session that may have been
//deleted on one node is then accessed again shortly afterwards, it can appear as if the
//session is still live in the memory of that node. By waiting a little time, we can ensure
//that the node will re-load the session from the database and discover that it has gone.
try
{
Thread.sleep(2 * JdbcTestServer.SAVE_INTERVAL * 1000);
}
catch (InterruptedException e)
{
}
}
@Test(groups={"jdbc-all"})
public void testInvalidation() throws Exception
{
super.testInvalidation();
}
}

View File

@ -0,0 +1,79 @@
//========================================================================
//Copyright 2010 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 org.eclipse.jetty.server.SessionIdManager;
import org.eclipse.jetty.server.SessionManager;
/**
* JdbcTestServer
*
*
*/
public class JdbcTestServer extends AbstractTestServer
{
public static final String DRIVER_CLASS = "org.apache.derby.jdbc.EmbeddedDriver";
public static final String CONNECTION_URL = "jdbc:derby:sessions;create=true";
public static final int SAVE_INTERVAL = 1;
static
{
System.setProperty("derby.system.home", System.getProperty("java.io.tmpdir"));
}
public JdbcTestServer(int port)
{
super(port);
}
public JdbcTestServer(int port, int maxInactivePeriod, int scavengePeriod)
{
super(port, maxInactivePeriod, scavengePeriod);
}
/**
* @see org.eclipse.jetty.server.session.AbstractTestServer#newSessionHandler(org.eclipse.jetty.server.SessionManager)
*/
@Override
public SessionHandler newSessionHandler(SessionManager sessionManager)
{
return new SessionHandler(sessionManager);
}
/**
* @see org.eclipse.jetty.server.session.AbstractTestServer#newSessionIdManager()
*/
@Override
public SessionIdManager newSessionIdManager()
{
JDBCSessionIdManager idManager = new JDBCSessionIdManager(_server);
idManager.setScavengeInterval(_scavengePeriod);
idManager.setWorkerName(String.valueOf(System.currentTimeMillis()));
idManager.setDriverInfo(DRIVER_CLASS, CONNECTION_URL);
return idManager;
}
/**
* @see org.eclipse.jetty.server.session.AbstractTestServer#newSessionManager()
*/
@Override
public AbstractSessionManager newSessionManager()
{
JDBCSessionManager manager = new JDBCSessionManager();
manager.setIdManager((JDBCSessionIdManager)_sessionIdManager);
manager.setSaveInterval(SAVE_INTERVAL); //ensure we save any changes to the session at least once per second
return manager;
}
}

View File

@ -0,0 +1,38 @@
//========================================================================
//Copyright 2010 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 org.testng.annotations.Test;
/**
* LastAccessTimeTest
*
*
*/
public class LastAccessTimeTest extends AbstractLastAccessTimeTest
{
public AbstractTestServer createServer(int port, int max, int scavenge)
{
return new JdbcTestServer(port,max,scavenge);
}
@Test(groups={"jdbc-all"})
public void testLastAccessTime() throws Exception
{
super.testLastAccessTime();
}
}

View File

@ -0,0 +1,39 @@
//========================================================================
//Copyright 2010 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 org.testng.annotations.Test;
/**
* LightLoadTest
*
*
*/
public class LightLoadTest extends AbstractLightLoadTest
{
public AbstractTestServer createServer(int port)
{
return new JdbcTestServer(port);
}
@Test(groups={"jdbc-all"})
public void testLightLoad() throws Exception
{
super.testLightLoad();
}
}

View File

@ -0,0 +1,52 @@
//========================================================================
//Copyright 2010 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 org.testng.annotations.Test;
/**
* LocalSessionScavengingTest
*
*
*/
public class LocalSessionScavengingTest extends AbstractLocalSessionScavengingTest
{
public void pause (int scavenge)
{
//Wait a little longer for the scavenging to happen with the JDBCSession handling.
//The scavenging happens at about +10% longer than the scavenge interval, so that
//not all nodes sync up and start trying to scavenge for the same sessions at the
//same time.
//So, we wait 3 times the scavenging interval.
try
{
Thread.sleep(scavenge * 3000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
public AbstractTestServer createServer(int port, int max, int scavenge)
{
return new JdbcTestServer(port,max,scavenge);
}
@Test(groups={"jdbc-all"})
public void testLocalSessionsScavenging() throws Exception
{
super.testLocalSessionsScavenging();
}
}

View File

@ -0,0 +1,38 @@
//========================================================================
//Copyright 2010 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 org.testng.annotations.Test;
/**
* NewSessionTest
*
*
*/
public class NewSessionTest extends AbstractNewSessionTest
{
/**
* @see org.eclipse.jetty.server.session.AbstractNewSessionTest#createServer(int, int, int)
*/
public AbstractTestServer createServer(int port, int max, int scavenge)
{
return new JdbcTestServer(port,max,scavenge);
}
@Test(groups={"jdbc-all"})
public void testNewSession() throws Exception
{
super.testNewSession();
}
}

View File

@ -0,0 +1,38 @@
//========================================================================
//Copyright 2010 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 org.testng.annotations.Test;
/**
* OrphanedSessionTest
*
*
*/
public class OrphanedSessionTest extends AbstractOrphanedSessionTest
{
public AbstractTestServer createServer(int port, int max, int scavenge)
{
return new JdbcTestServer(port,max,scavenge);
}
@Test(groups={"jdbc-all"})
public void testOrphanedSession() throws Exception
{
super.testOrphanedSession();
}
}

View File

@ -0,0 +1,37 @@
//========================================================================
//Copyright 2010 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 org.testng.annotations.Test;
/**
* ReentrantRequestSessionTest
*
*
*/
public class ReentrantRequestSessionTest extends AbstractReentrantRequestSessionTest
{
public AbstractTestServer createServer(int port)
{
return new JdbcTestServer(port);
}
@Test(groups={"jdbc-all"})
public void testReentrantRequestSession() throws Exception
{
super.testReentrantRequestSession();
}
}

View File

@ -0,0 +1,38 @@
//========================================================================
//Copyright 2010 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 org.testng.annotations.Test;
/**
* ServerCrossContextSessionTest
*
*
*/
public class ServerCrossContextSessionTest extends AbstractServerCrossContextSessionTest
{
public AbstractTestServer createServer(int port)
{
return new JdbcTestServer(port);
}
@Test(groups={"jdbc-all"})
public void testCrossContextDispatch() throws Exception
{
super.testCrossContextDispatch();
}
}

View File

@ -0,0 +1,38 @@
//========================================================================
//$Id$
//Copyright 2010 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 org.testng.annotations.Test;
/**
* SessionMigrationTest
*
*
*/
public class SessionMigrationTest extends AbstractSessionMigrationTest
{
public AbstractTestServer createServer(int port)
{
return new JdbcTestServer(port);
}
@Test(groups={"jdbc-all"})
public void testSessionMigration() throws Exception
{
super.testSessionMigration();
}
}

View File

@ -0,0 +1,36 @@
//========================================================================
//Copyright 2010 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 org.testng.annotations.Test;
/**
* WebAppObjectInSessionTest
*
*
*/
public class WebAppObjectInSessionTest extends AbstractWebAppObjectInSessionTest
{
public AbstractTestServer createServer(int port)
{
return new JdbcTestServer(port);
}
@Test(groups={"jdbc-all"})
public void testWebappObjectInSession() throws Exception
{
super.testWebappObjectInSession();
}
}

View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
// ========================================================================
// Copyright (c) Webtide LLC
//
// 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.apache.org/licenses/LICENSE-2.0.txt
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
-->
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>test-sessions-parent</artifactId>
<version>7.0.2-SNAPSHOT</version>
</parent>
<artifactId>test-sessions-common</artifactId>
<name>Jetty Tests :: Sessions :: Common</name>
<build>
</build>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>5.8</version>
<classifier>jdk15</classifier>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,132 @@
// ========================================================================
// Copyright 2004-2010 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.server.session;
import java.io.IOException;
import java.util.Collections;
import java.util.Random;
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.http.HttpMethods;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.client.ContentExchange;
import org.eclipse.jetty.client.HttpClient;
import org.testng.annotations.Test;
/**
* AbstractClientCrossContextSessionTest
*
*
*/
public abstract class AbstractClientCrossContextSessionTest
{
public abstract AbstractTestServer createServer(int port);
@Test
public void testCrossContextDispatch() throws Exception
{
Random random = new Random(System.nanoTime());
String contextA = "/contextA";
String contextB = "/contextB";
String servletMapping = "/server";
int port = random.nextInt(50000) + 10000;
AbstractTestServer server = createServer(port);
ServletContextHandler ctxA = server.addContext(contextA);
ctxA.addServlet(TestServletA.class, servletMapping);
ServletContextHandler ctxB = server.addContext(contextB);
ctxB.addServlet(TestServletB.class, servletMapping);
server.start();
try
{
HttpClient client = new HttpClient();
client.setConnectorType(HttpClient.CONNECTOR_SOCKET);
client.start();
try
{
// Perform a request to contextA
ContentExchange exchangeA = new ContentExchange(true);
exchangeA.setMethod(HttpMethods.GET);
exchangeA.setURL("http://localhost:" + port + contextA + servletMapping);
client.send(exchangeA);
exchangeA.waitForDone();
assert exchangeA.getResponseStatus() == HttpServletResponse.SC_OK;
String sessionCookie = exchangeA.getResponseFields().getStringField("Set-Cookie");
assert sessionCookie != null;
// Mangle the cookie, replacing Path with $Path, etc.
sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
// Perform a request to contextB with the same session cookie
ContentExchange exchangeB = new ContentExchange(true);
exchangeB.setMethod(HttpMethods.GET);
exchangeB.setURL("http://localhost:" + port + contextB + servletMapping);
exchangeB.getRequestFields().add("Cookie", sessionCookie);
client.send(exchangeB);
exchangeB.waitForDone();
assert exchangeB.getResponseStatus() == HttpServletResponse.SC_OK;
}
finally
{
client.stop();
}
}
finally
{
server.stop();
}
}
public static class TestServletA extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
HttpSession session = request.getSession(false);
if (session == null) session = request.getSession(true);
// Add something to the session
session.setAttribute("A", "A");
// Check that we don't see things put in session by contextB
Object objectB = session.getAttribute("B");
assert objectB == null;
System.out.println("A: session.getAttributeNames() = " + Collections.list(session.getAttributeNames()));
}
}
public static class TestServletB extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse httpServletResponse) throws ServletException, IOException
{
HttpSession session = request.getSession(false);
if (session == null) session = request.getSession(true);
// Add something to the session
session.setAttribute("B", "B");
// Check that we don't see things put in session by contextA
Object objectA = session.getAttribute("A");
assert objectA == null;
System.out.println("B: session.getAttributeNames() = " + Collections.list(session.getAttributeNames()));
}
}
}

View File

@ -0,0 +1,125 @@
// ========================================================================
// Copyright 2004-2010 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.server.session;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Random;
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.http.HttpMethods;
import org.eclipse.jetty.client.ContentExchange;
import org.eclipse.jetty.client.HttpClient;
import org.testng.annotations.Test;
/**
* AbstractImmortalSessionTest
*
*
*/
public abstract class AbstractImmortalSessionTest
{
public abstract AbstractTestServer createServer(int port, int maxInactiveMs, int scavengeMs);
@Test
public void testImmortalSession() throws Exception
{
Random random = new Random(System.nanoTime());
String contextPath = "";
String servletMapping = "/server";
int port = random.nextInt(50000) + 10000;
int scavengePeriod = 2;
AbstractTestServer server = createServer(port, -1, scavengePeriod);
server.addContext(contextPath).addServlet(TestServlet.class, servletMapping);
server.start();
try
{
HttpClient client = new HttpClient();
client.setConnectorType(HttpClient.CONNECTOR_SOCKET);
client.start();
try
{
int value = 42;
ContentExchange exchange = new ContentExchange(true);
exchange.setMethod(HttpMethods.GET);
exchange.setURL("http://localhost:" + port + contextPath + servletMapping + "?action=set&value=" + value);
client.send(exchange);
exchange.waitForDone();
assert exchange.getResponseStatus() == HttpServletResponse.SC_OK;
String sessionCookie = exchange.getResponseFields().getStringField("Set-Cookie");
assert sessionCookie != null;
// Mangle the cookie, replacing Path with $Path, etc.
sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
String response = exchange.getResponseContent();
assert response.trim().equals(String.valueOf(value));
// Let's wait for the scavenger to run, waiting 2.5 times the scavenger period
Thread.sleep(scavengePeriod * 2500L);
// Be sure the session is still there
exchange = new ContentExchange(true);
exchange.setMethod(HttpMethods.GET);
exchange.setURL("http://localhost:" + port + contextPath + servletMapping + "?action=get");
exchange.getRequestFields().add("Cookie", sessionCookie);
client.send(exchange);
exchange.waitForDone();
assert exchange.getResponseStatus() == HttpServletResponse.SC_OK;
response = exchange.getResponseContent();
assert response.trim().equals(String.valueOf(value));
}
finally
{
client.stop();
}
}
finally
{
server.stop();
}
}
public static class TestServlet extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
String result = null;
String action = request.getParameter("action");
if ("set".equals(action))
{
String value = request.getParameter("value");
HttpSession session = request.getSession(true);
session.setAttribute("value", value);
result = value;
}
else if ("get".equals(action))
{
HttpSession session = request.getSession(false);
result = (String)session.getAttribute("value");
}
PrintWriter writer = response.getWriter();
writer.println(result);
writer.flush();
}
}
}

View File

@ -0,0 +1,157 @@
// ========================================================================
// Copyright 2004-2010 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.server.session;
import java.io.IOException;
import java.util.Random;
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.http.HttpMethods;
import org.eclipse.jetty.client.ContentExchange;
import org.eclipse.jetty.client.HttpClient;
import org.testng.annotations.Test;
/**
* AbstractInvalidationSessionTest
* Goal of the test is to be sure that invalidating a session on one node
* result in the session being unavailable in the other node also.
*
*/
public abstract class AbstractInvalidationSessionTest
{
public abstract AbstractTestServer createServer(int port);
public abstract void pause();
@Test
public void testInvalidation() throws Exception
{
Random random = new Random(System.nanoTime());
String contextPath = "";
String servletMapping = "/server";
int port1 = random.nextInt(50000) + 10000;
AbstractTestServer server1 = createServer(port1);
server1.addContext(contextPath).addServlet(TestServlet.class, servletMapping);
server1.start();
try
{
int port2 = random.nextInt(50000) + 10000;
AbstractTestServer server2 = createServer(port2);
server2.addContext(contextPath).addServlet(TestServlet.class, servletMapping);
server2.start();
try
{
HttpClient client = new HttpClient();
client.setConnectorType(HttpClient.CONNECTOR_SOCKET);
client.start();
try
{
String[] urls = new String[2];
urls[0] = "http://localhost:" + port1 + contextPath + servletMapping;
urls[1] = "http://localhost:" + port2 + contextPath + servletMapping;
// Create the session on node1
ContentExchange exchange1 = new ContentExchange(true);
exchange1.setMethod(HttpMethods.GET);
exchange1.setURL(urls[0] + "?action=init");
client.send(exchange1);
exchange1.waitForDone();
assert exchange1.getResponseStatus() == HttpServletResponse.SC_OK;
String sessionCookie = exchange1.getResponseFields().getStringField("Set-Cookie");
assert sessionCookie != null;
// Mangle the cookie, replacing Path with $Path, etc.
sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
// Be sure the session is also present in node2
ContentExchange exchange2 = new ContentExchange(true);
exchange2.setMethod(HttpMethods.GET);
exchange2.setURL(urls[1] + "?action=increment");
exchange2.getRequestFields().add("Cookie", sessionCookie);
client.send(exchange2);
exchange2.waitForDone();
assert exchange2.getResponseStatus() == HttpServletResponse.SC_OK;
// Invalidate on node1
exchange1 = new ContentExchange(true);
exchange1.setMethod(HttpMethods.GET);
exchange1.setURL(urls[0] + "?action=invalidate");
exchange1.getRequestFields().add("Cookie", sessionCookie);
client.send(exchange1);
exchange1.waitForDone();
assert exchange1.getResponseStatus() == HttpServletResponse.SC_OK;
pause();
// Be sure on node2 we don't see the session anymore
exchange2 = new ContentExchange(true);
exchange2.setMethod(HttpMethods.GET);
exchange2.setURL(urls[1] + "?action=test");
exchange2.getRequestFields().add("Cookie", sessionCookie);
client.send(exchange2);
exchange2.waitForDone();
assert exchange2.getResponseStatus() == HttpServletResponse.SC_OK;
}
finally
{
client.stop();
}
}
finally
{
server2.stop();
}
}
finally
{
server1.stop();
}
}
public static class TestServlet extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
String action = request.getParameter("action");
if ("init".equals(action))
{
HttpSession session = request.getSession(true);
session.setAttribute("value", 0);
}
else if ("increment".equals(action))
{
HttpSession session = request.getSession(false);
int value = (Integer)session.getAttribute("value");
session.setAttribute("value", value + 1);
}
else if ("invalidate".equals(action))
{
HttpSession session = request.getSession(false);
session.invalidate();
}
else if ("test".equals(action))
{
HttpSession session = request.getSession(false);
assert session == null;
}
}
}
}

View File

@ -0,0 +1,145 @@
// ========================================================================
// Copyright 2004-2010 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.server.session;
import java.io.IOException;
import java.util.Random;
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.http.HttpMethods;
import org.eclipse.jetty.client.ContentExchange;
import org.eclipse.jetty.client.HttpClient;
import org.testng.annotations.Test;
/**
* AbstractLastAccessTimeTest
*
*
*/
public abstract class AbstractLastAccessTimeTest
{
public abstract AbstractTestServer createServer(int port, int max, int scavenge);
@Test
public void testLastAccessTime() throws Exception
{
Random random = new Random(System.nanoTime());
String contextPath = "";
String servletMapping = "/server";
int port1 = random.nextInt(50000) + 10000;
int maxInactivePeriod = 8;
int scavengePeriod = 2;
AbstractTestServer server1 = createServer(port1, maxInactivePeriod, scavengePeriod);
server1.addContext(contextPath).addServlet(TestServlet.class, servletMapping);
server1.start();
try
{
int port2 = random.nextInt(50000) + 10000;
AbstractTestServer server2 = createServer(port2, maxInactivePeriod, scavengePeriod);
server2.addContext(contextPath).addServlet(TestServlet.class, servletMapping);
server2.start();
try
{
HttpClient client = new HttpClient();
client.setConnectorType(HttpClient.CONNECTOR_SOCKET);
client.start();
try
{
// 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();
assert exchange1.getResponseStatus() == HttpServletResponse.SC_OK;
String sessionCookie = exchange1.getResponseFields().getStringField("Set-Cookie");
assert 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 < maxInactivePeriod * (1000 / requestInterval); ++i)
{
ContentExchange exchange2 = new ContentExchange(true);
exchange2.setMethod(HttpMethods.GET);
exchange2.setURL("http://localhost:" + port2 + contextPath + servletMapping);
exchange2.getRequestFields().add("Cookie", sessionCookie);
client.send(exchange2);
exchange2.waitForDone();
assert exchange2.getResponseStatus() == HttpServletResponse.SC_OK;
Thread.sleep(requestInterval);
}
System.out.println("Waiting for scavenging on node1...");
// At this point, session1 should be eligible for expiration.
// Let's wait for the scavenger to run, waiting 2.5 times the scavenger period
Thread.sleep(scavengePeriod * 2500L);
// Access again server1, and be sure we can
exchange1 = new ContentExchange(true);
exchange1.setMethod(HttpMethods.GET);
exchange1.setURL("http://localhost:" + port1 + contextPath + servletMapping);
exchange1.getRequestFields().add("Cookie", sessionCookie);
client.send(exchange1);
exchange1.waitForDone();
assert exchange1.getResponseStatus() == HttpServletResponse.SC_OK;
}
finally
{
client.stop();
}
}
finally
{
server2.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))
{
HttpSession session = request.getSession(true);
session.setAttribute("test", "test");
}
else
{
HttpSession session = request.getSession(false);
session.setAttribute("test", "test");
}
}
}
}

View File

@ -0,0 +1,241 @@
// ========================================================================
// Copyright 2004-2010 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.server.session;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Random;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
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.http.HttpMethods;
import org.eclipse.jetty.client.ContentExchange;
import org.eclipse.jetty.client.HttpClient;
import org.testng.annotations.Test;
/**
* AbstractLightLoadTest
*
*
*/
public abstract class AbstractLightLoadTest
{
protected boolean _stress = Boolean.getBoolean( "STRESS" );
public abstract AbstractTestServer createServer(int port);
@Test
public void testLightLoad()
throws Exception
{
if ( _stress )
{
Random random = new Random( System.nanoTime() );
String contextPath = "";
String servletMapping = "/server";
int port1 = random.nextInt( 50000 ) + 10000;
AbstractTestServer server1 = createServer( port1 );
server1.addContext( contextPath ).addServlet( TestServlet.class, servletMapping );
server1.start();
try
{
int port2 = random.nextInt( 50000 ) + 10000;
AbstractTestServer server2 = createServer( port2 );
server2.addContext( contextPath ).addServlet( TestServlet.class, servletMapping );
server2.start();
try
{
HttpClient client = new HttpClient();
client.setConnectorType( HttpClient.CONNECTOR_SOCKET );
client.start();
try
{
String[] urls = new String[2];
urls[0] = "http://localhost:" + port1 + contextPath + servletMapping;
urls[1] = "http://localhost:" + port2 + contextPath + servletMapping;
ContentExchange exchange1 = new ContentExchange( true );
exchange1.setMethod( HttpMethods.GET );
exchange1.setURL( urls[0] + "?action=init" );
client.send( exchange1 );
exchange1.waitForDone();
assert exchange1.getResponseStatus() == HttpServletResponse.SC_OK;
String sessionCookie = exchange1.getResponseFields().getStringField( "Set-Cookie" );
assert sessionCookie != null;
// Mangle the cookie, replacing Path with $Path, etc.
sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
ExecutorService executor = Executors.newCachedThreadPool();
int clientsCount = 50;
CyclicBarrier barrier = new CyclicBarrier( clientsCount + 1 );
int requestsCount = 100;
Worker[] workers = new Worker[clientsCount];
for ( int i = 0; i < clientsCount; ++i )
{
workers[i] = new Worker( barrier, requestsCount, sessionCookie, urls );
workers[i].start();
executor.execute( workers[i] );
}
// Wait for all workers to be ready
barrier.await();
long start = System.nanoTime();
// Wait for all workers to be done
barrier.await();
long end = System.nanoTime();
long elapsed = TimeUnit.NANOSECONDS.toMillis( end - start );
System.out.println( "elapsed ms: " + elapsed );
for ( Worker worker : workers )
worker.stop();
executor.shutdownNow();
// Perform one request to get the result
ContentExchange exchange2 = new ContentExchange( true );
exchange2.setMethod( HttpMethods.GET );
exchange2.setURL( urls[0] + "?action=result" );
exchange2.getRequestFields().add( "Cookie", sessionCookie );
client.send( exchange2 );
exchange2.waitForDone();
assert exchange2.getResponseStatus() == HttpServletResponse.SC_OK;
String response = exchange2.getResponseContent();
System.out.println( "get = " + response );
assert response.trim().equals( String.valueOf( clientsCount * requestsCount ) );
}
finally
{
client.stop();
}
}
finally
{
server2.stop();
}
}
finally
{
server1.stop();
}
}
}
public static class Worker
implements Runnable
{
private final HttpClient client;
private final CyclicBarrier barrier;
private final int requestsCount;
private final String sessionCookie;
private final String[] urls;
public Worker( CyclicBarrier barrier, int requestsCount, String sessionCookie, String[] urls )
{
this.client = new HttpClient();
this.client.setConnectorType( HttpClient.CONNECTOR_SOCKET );
this.barrier = barrier;
this.requestsCount = requestsCount;
this.sessionCookie = sessionCookie;
this.urls = urls;
}
public void start()
throws Exception
{
client.start();
}
public void stop()
throws Exception
{
client.stop();
}
public void run()
{
try
{
// Wait for all workers to be ready
barrier.await();
Random random = new Random( System.nanoTime() );
for ( int i = 0; i < requestsCount; ++i )
{
int urlIndex = random.nextInt( urls.length );
ContentExchange exchange = new ContentExchange( true );
exchange.setMethod( HttpMethods.GET );
exchange.setURL( urls[urlIndex] + "?action=increment" );
exchange.getRequestFields().add( "Cookie", sessionCookie );
client.send( exchange );
exchange.waitForDone();
assert exchange.getResponseStatus() == HttpServletResponse.SC_OK;
}
// Wait for all workers to be done
barrier.await();
}
catch ( Exception x )
{
throw new RuntimeException( x );
}
}
}
public static class TestServlet
extends HttpServlet
{
@Override
protected void doGet( HttpServletRequest request, HttpServletResponse response )
throws ServletException, IOException
{
String action = request.getParameter( "action" );
if ( "init".equals( action ) )
{
HttpSession session = request.getSession( true );
session.setAttribute( "value", 0 );
}
else if ( "increment".equals( action ) )
{
// Without synchronization, because it is taken care by Jetty/Terracotta
HttpSession session = request.getSession( false );
int value = (Integer) session.getAttribute( "value" );
session.setAttribute( "value", value + 1 );
}
else if ( "result".equals( action ) )
{
HttpSession session = request.getSession( false );
int value = (Integer) session.getAttribute( "value" );
PrintWriter writer = response.getWriter();
writer.println( value );
writer.flush();
}
}
}
}

View File

@ -0,0 +1,172 @@
// ========================================================================
// Copyright 2004-2010 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.server.session;
import java.io.IOException;
import java.util.Random;
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.http.HttpMethods;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.SessionManager;
import org.eclipse.jetty.client.ContentExchange;
import org.eclipse.jetty.client.HttpClient;
import org.testng.annotations.Test;
/**
* AbstractLocalSessionScavengingTest
*
*
*/
public abstract class AbstractLocalSessionScavengingTest
{
public abstract AbstractTestServer createServer(int port, int max, int scavenge);
public void pause(int scavengePeriod)
{
try
{
Thread.sleep(scavengePeriod * 2500L);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
@Test
public void testLocalSessionsScavenging() throws Exception
{
Random random = new Random(System.nanoTime());
String contextPath = "";
String servletMapping = "/server";
int port1 = random.nextInt(50000) + 10000;
int inactivePeriod = 1;
int scavengePeriod = 2;
AbstractTestServer server1 = createServer(port1, inactivePeriod, scavengePeriod);
server1.addContext(contextPath).addServlet(TestServlet.class, servletMapping);
server1.start();
try
{
int port2 = random.nextInt(50000) + 10000;
AbstractTestServer server2 = createServer(port2, inactivePeriod, scavengePeriod * 3);
server2.addContext(contextPath).addServlet(TestServlet.class, servletMapping);
server2.start();
try
{
HttpClient client = new HttpClient();
client.setConnectorType(HttpClient.CONNECTOR_SOCKET);
client.start();
try
{
String[] urls = new String[2];
urls[0] = "http://localhost:" + port1 + contextPath + servletMapping;
urls[1] = "http://localhost:" + port2 + contextPath + servletMapping;
// Create the session on node1
ContentExchange exchange1 = new ContentExchange(true);
exchange1.setMethod(HttpMethods.GET);
exchange1.setURL(urls[0] + "?action=init");
client.send(exchange1);
exchange1.waitForDone();
assert exchange1.getResponseStatus() == HttpServletResponse.SC_OK;
String sessionCookie = exchange1.getResponseFields().getStringField("Set-Cookie");
assert sessionCookie != null;
// Mangle the cookie, replacing Path with $Path, etc.
sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
// Be sure the session is also present in node2
ContentExchange exchange2 = new ContentExchange(true);
exchange2.setMethod(HttpMethods.GET);
exchange2.setURL(urls[1] + "?action=test");
exchange2.getRequestFields().add("Cookie", sessionCookie);
client.send(exchange2);
exchange2.waitForDone();
assert exchange2.getResponseStatus() == HttpServletResponse.SC_OK;
// Wait for the scavenger to run on node1, waiting 2.5 times the scavenger period
pause(scavengePeriod);
// Check that node1 does not have any local session cached
exchange1 = new ContentExchange(true);
exchange1.setMethod(HttpMethods.GET);
exchange1.setURL(urls[0] + "?action=check");
client.send(exchange1);
exchange1.waitForDone();
assert exchange1.getResponseStatus() == HttpServletResponse.SC_OK;
// Wait for the scavenger to run on node2, waiting 2 times the scavenger period
// This ensures that the scavenger on node2 runs at least once.
pause(scavengePeriod);
// Check that node2 does not have any local session cached
exchange2 = new ContentExchange(true);
exchange2.setMethod(HttpMethods.GET);
exchange2.setURL(urls[1] + "?action=check");
client.send(exchange2);
exchange2.waitForDone();
assert exchange2.getResponseStatus() == HttpServletResponse.SC_OK;
}
finally
{
client.stop();
}
}
finally
{
server2.stop();
}
}
finally
{
server1.stop();
}
}
public static class TestServlet extends HttpServlet
{
private SessionManager sessionManager;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse httpServletResponse) throws ServletException, IOException
{
String action = request.getParameter("action");
if ("init".equals(action))
{
HttpSession session = request.getSession(true);
session.setAttribute("test", "test");
this.sessionManager = ((Request)request).getSessionManager();
}
else if ("test".equals(action))
{
HttpSession session = request.getSession(false);
session.setAttribute("test", "test");
this.sessionManager = ((Request)request).getSessionManager();
}
else if ("check".equals(action))
{
HttpSession session = request.getSession(false);
assert session == null;
}
}
}
}

View File

@ -0,0 +1,126 @@
// ========================================================================
// Copyright 2004-2010 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.server.session;
import java.io.IOException;
import java.util.Random;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpMethods;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.client.ContentExchange;
import org.eclipse.jetty.client.HttpClient;
import org.testng.annotations.Test;
/**
* AbstractNewSessionTest
*
*
*/
public abstract class AbstractNewSessionTest
{
public abstract AbstractTestServer createServer(int port, int max, int scavenge);
public void pause(int scavenge)
{
try
{
Thread.sleep(scavenge * 2500L);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
@Test
public void testNewSession() throws Exception
{
Random random = new Random(System.nanoTime());
String contextPath = "";
String servletMapping = "/server";
int port = random.nextInt(50000) + 10000;
int scavengePeriod = 3;
AbstractTestServer server = createServer(port, 1, scavengePeriod);
ServletContextHandler context = server.addContext(contextPath);
context.addServlet(TestServlet.class, servletMapping);
server.start();
try
{
HttpClient client = new HttpClient();
client.setConnectorType(HttpClient.CONNECTOR_SOCKET);
client.start();
try
{
ContentExchange exchange = new ContentExchange(true);
exchange.setMethod(HttpMethods.GET);
exchange.setURL("http://localhost:" + port + contextPath + servletMapping + "?action=create");
client.send(exchange);
exchange.waitForDone();
assert exchange.getResponseStatus() == HttpServletResponse.SC_OK;
String sessionCookie = exchange.getResponseFields().getStringField("Set-Cookie");
assert sessionCookie != null;
// Mangle the cookie, replacing Path with $Path, etc.
sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
// Let's wait for the scavenger to run, waiting 2.5 times the scavenger period
pause(scavengePeriod);
// The session is not there anymore, but we present an old cookie
// The server creates a new session, we must ensure we released all locks
exchange = new ContentExchange(true);
exchange.setMethod(HttpMethods.GET);
exchange.setURL("http://localhost:" + port + contextPath + servletMapping + "?action=old-create");
exchange.getRequestFields().add("Cookie", sessionCookie);
client.send(exchange);
exchange.waitForDone();
assert exchange.getResponseStatus() == HttpServletResponse.SC_OK;
}
finally
{
client.stop();
}
}
finally
{
server.stop();
}
}
public static class TestServlet extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
String action = request.getParameter("action");
if ("create".equals(action))
{
request.getSession(true);
}
else if ("old-create".equals(action))
{
request.getSession(true);
}
else
{
assert false;
}
}
}
}

View File

@ -0,0 +1,136 @@
// ========================================================================
// Copyright 2004-2010 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.server.session;
import java.io.IOException;
import java.util.Random;
import java.util.concurrent.TimeUnit;
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.http.HttpMethods;
import org.eclipse.jetty.client.ContentExchange;
import org.eclipse.jetty.client.HttpClient;
import org.testng.annotations.Test;
/**
* AbstractOrphanedSessionTest
*
*
*/
public abstract class AbstractOrphanedSessionTest
{
public abstract AbstractTestServer createServer(int port, int max, int scavenge);
/**
* If nodeA creates a session, and just afterwards crashes, it is the only node that knows about the session.
* We want to test that the session data is gone after scavenging.
*/
@Test
public void testOrphanedSession() throws Exception
{
Random random = new Random(System.nanoTime());
// Disable scavenging for the first server, so that we simulate its "crash".
String contextPath = "";
String servletMapping = "/server";
int port1 = random.nextInt(50000) + 10000;
int inactivePeriod = 5;
AbstractTestServer server1 = createServer(port1, inactivePeriod, -1);
server1.addContext(contextPath).addServlet(TestServlet.class, servletMapping);
server1.start();
try
{
int port2 = random.nextInt(50000) + 10000;
int scavengePeriod = 2;
AbstractTestServer server2 = createServer(port2, inactivePeriod, scavengePeriod);
server2.addContext(contextPath).addServlet(TestServlet.class, servletMapping);
server2.start();
try
{
HttpClient client = new HttpClient();
client.setConnectorType(HttpClient.CONNECTOR_SOCKET);
client.start();
try
{
// Connect to server1 to create a session and get its session cookie
ContentExchange exchange1 = new ContentExchange(true);
exchange1.setMethod(HttpMethods.GET);
exchange1.setURL("http://localhost:" + port1 + contextPath + servletMapping + "?action=init");
client.send(exchange1);
exchange1.waitForDone();
assert exchange1.getResponseStatus() == HttpServletResponse.SC_OK;
String sessionCookie = exchange1.getResponseFields().getStringField("Set-Cookie");
assert sessionCookie != null;
// Mangle the cookie, replacing Path with $Path, etc.
sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
// Wait for the session to expire.
// The first node does not do any scavenging, but the session
// must be removed by scavenging done in the other node.
Thread.sleep(TimeUnit.SECONDS.toMillis(inactivePeriod + 2L * scavengePeriod));
System.err.println("FINISHED waiting for session to expire");
// Perform one request to server2 to be sure that the session has been expired
System.err.println("CHECKING NODE2");
ContentExchange exchange2 = new ContentExchange(true);
exchange2.setMethod(HttpMethods.GET);
exchange2.setURL("http://localhost:" + port2 + contextPath + servletMapping + "?action=check");
exchange2.getRequestFields().add("Cookie", sessionCookie);
client.send(exchange2);
exchange2.waitForDone();
assert exchange2.getResponseStatus() == HttpServletResponse.SC_OK;
}
finally
{
client.stop();
}
}
finally
{
server2.stop();
}
}
finally
{
server1.stop();
}
}
public static class TestServlet extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
String action = request.getParameter("action");
if ("init".equals(action))
{
HttpSession session = request.getSession(true);
session.setAttribute("A", "A");
}
else if ("check".equals(action))
{
HttpSession session = request.getSession(false);
assert session == null;
}
}
}
}

View File

@ -0,0 +1,130 @@
// ========================================================================
// Copyright 2004-2010 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.server.session;
import java.io.IOException;
import java.util.Random;
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.http.HttpMethods;
import org.eclipse.jetty.client.ContentExchange;
import org.eclipse.jetty.client.HttpClient;
import org.testng.annotations.Test;
/**
* AbstractReentrantRequestSessionTest
*
*
*/
public abstract class AbstractReentrantRequestSessionTest
{
public abstract AbstractTestServer createServer(int port);
@Test
public void testReentrantRequestSession() throws Exception
{
Random random = new Random(System.nanoTime());
String contextPath = "";
String servletMapping = "/server";
int port = random.nextInt(50000) + 10000;
AbstractTestServer server = createServer(port);
server.addContext(contextPath).addServlet(TestServlet.class, servletMapping);
server.start();
try
{
HttpClient client = new HttpClient();
client.setConnectorType(HttpClient.CONNECTOR_SOCKET);
client.start();
try
{
ContentExchange exchange = new ContentExchange(true);
exchange.setMethod(HttpMethods.GET);
exchange.setURL("http://localhost:" + port + contextPath + servletMapping + "?action=reenter&port=" + port + "&path=" + contextPath + servletMapping);
client.send(exchange);
exchange.waitForDone();
assert exchange.getResponseStatus() == HttpServletResponse.SC_OK;
}
finally
{
client.stop();
}
}
finally
{
server.stop();
}
}
public static class TestServlet extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
HttpSession session = request.getSession(false);
if (session == null) session = request.getSession(true);
String action = request.getParameter("action");
if ("reenter".equals(action))
{
int port = Integer.parseInt(request.getParameter("port"));
String path = request.getParameter("path");
// We want to make another request with a different session
// while this request is still pending, to see if the locking is
// fine grained (per session at least).
try
{
HttpClient client = new HttpClient();
client.setConnectorType(HttpClient.CONNECTOR_SOCKET);
client.start();
try
{
ContentExchange exchange = new ContentExchange(true);
exchange.setMethod(HttpMethods.GET);
exchange.setURL("http://localhost:" + port + path + "?action=none");
client.send(exchange);
exchange.waitForDone();
assert exchange.getResponseStatus() == HttpServletResponse.SC_OK;
}
finally
{
client.stop();
}
}
catch (Exception x)
{
throw new ServletException(x);
}
}
else
{
// Reentrancy was successful, just return
}
}
}
}

View File

@ -0,0 +1,128 @@
// ========================================================================
// Copyright 2004-2008 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.server.session;
import java.io.IOException;
import java.util.Collections;
import java.util.Random;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
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.http.HttpMethods;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.client.ContentExchange;
import org.eclipse.jetty.client.HttpClient;
import org.testng.annotations.Test;
/**
* AbstractServerCrossContextSessionTest
*
*
*/
public abstract class AbstractServerCrossContextSessionTest
{
public abstract AbstractTestServer createServer(int port);
@Test
public void testCrossContextDispatch() throws Exception
{
Random random = new Random(System.nanoTime());
String contextA = "/contextA";
String contextB = "/contextB";
String servletMapping = "/server";
int port = random.nextInt(50000) + 10000;
AbstractTestServer server = createServer(port);
ServletContextHandler ctxA = server.addContext(contextA);
ctxA.addServlet(TestServletA.class, servletMapping);
ServletContextHandler ctxB = server.addContext(contextB);
ctxB.addServlet(TestServletB.class, servletMapping);
server.start();
try
{
HttpClient client = new HttpClient();
client.setConnectorType(HttpClient.CONNECTOR_SOCKET);
client.start();
try
{
// Perform a request, on server side a cross context dispatch will be done
ContentExchange exchange = new ContentExchange(true);
exchange.setMethod(HttpMethods.GET);
exchange.setURL("http://localhost:" + port + contextA + servletMapping);
client.send(exchange);
exchange.waitForDone();
assert exchange.getResponseStatus() == HttpServletResponse.SC_OK;
}
finally
{
client.stop();
}
}
finally
{
server.stop();
}
}
public static class TestServletA extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
HttpSession session = request.getSession(false);
if (session == null) session = request.getSession(true);
// Add something to the session
session.setAttribute("A", "A");
System.out.println("A: session.getAttributeNames() = " + Collections.list(session.getAttributeNames()));
// Perform cross context dispatch to another context
// Over there we will check that the session attribute added above is not visible
ServletContext contextB = getServletContext().getContext("/contextB");
RequestDispatcher dispatcherB = contextB.getRequestDispatcher(request.getServletPath());
dispatcherB.forward(request, response);
// Check that we don't see things put in session by contextB
Object objectB = session.getAttribute("B");
assert objectB == null;
System.out.println("A: session.getAttributeNames() = " + Collections.list(session.getAttributeNames()));
}
}
public static class TestServletB extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse httpServletResponse) throws ServletException, IOException
{
HttpSession session = request.getSession(false);
if (session == null) session = request.getSession(true);
// Be sure nothing from contextA is present
Object objectA = session.getAttribute("A");
assert objectA == null;
// Add something, so in contextA we can check if it is visible (it must not).
session.setAttribute("B", "B");
System.out.println("B: session.getAttributeNames() = " + Collections.list(session.getAttributeNames()));
}
}
}

View File

@ -0,0 +1,138 @@
// ========================================================================
// Copyright 2004-2010 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.server.session;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Random;
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.http.HttpMethods;
import org.eclipse.jetty.client.ContentExchange;
import org.eclipse.jetty.client.HttpClient;
import org.testng.annotations.Test;
/**
* AbstractSessionMigrationTest
*
*
*/
public abstract class AbstractSessionMigrationTest
{
public abstract AbstractTestServer createServer (int port);
@Test
public void testSessionMigration() throws Exception
{
Random random = new Random(System.nanoTime());
String contextPath = "";
String servletMapping = "/server";
int port1 = random.nextInt(50000) + 10000;
AbstractTestServer server1 = createServer(port1);
server1.addContext(contextPath).addServlet(TestServlet.class, servletMapping);
server1.start();
try
{
int port2 = random.nextInt(50000) + 10000;
AbstractTestServer server2 = createServer(port2);
server2.addContext(contextPath).addServlet(TestServlet.class, servletMapping);
server2.start();
try
{
HttpClient client = new HttpClient();
client.setConnectorType(HttpClient.CONNECTOR_SOCKET);
client.start();
try
{
// Perform one request to server1 to create a session
int value = 1;
ContentExchange exchange1 = new ContentExchange(true);
exchange1.setMethod(HttpMethods.POST);
exchange1.setURL("http://localhost:" + port1 + contextPath + servletMapping + "?action=set&value=" + value);
client.send(exchange1);
exchange1.waitForDone();
assert exchange1.getResponseStatus() == HttpServletResponse.SC_OK;
String sessionCookie = exchange1.getResponseFields().getStringField("Set-Cookie");
assert sessionCookie != null;
// Mangle the cookie, replacing Path with $Path, etc.
sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
// Perform a request to server2 using the session cookie from the previous request
// This should migrate the session from server1 to server2.
ContentExchange exchange2 = new ContentExchange(true);
exchange2.setMethod(HttpMethods.GET);
exchange2.setURL("http://localhost:" + port2 + contextPath + servletMapping + "?action=get");
exchange2.getRequestFields().add("Cookie", sessionCookie);
client.send(exchange2);
exchange2.waitForDone();
assert exchange2.getResponseStatus() == HttpServletResponse.SC_OK;
String response = exchange2.getResponseContent();
assert response.trim().equals(String.valueOf(value));
}
finally
{
client.stop();
}
}
finally
{
server2.stop();
}
}
finally
{
server1.stop();
}
}
public static class TestServlet extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
HttpSession session = request.getSession(false);
if (session == null) session = request.getSession(true);
String action = request.getParameter("action");
if ("set".equals(action))
{
int value = Integer.parseInt(request.getParameter("value"));
session.setAttribute("value", value);
PrintWriter writer = response.getWriter();
writer.println(value);
writer.flush();
}
else if ("get".equals(action))
{
int value = (Integer)session.getAttribute("value");
PrintWriter writer = response.getWriter();
writer.println(value);
writer.flush();
}
}
}
}

View File

@ -0,0 +1,98 @@
// ========================================================================
// Copyright 2004-2010 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 org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.SessionIdManager;
import org.eclipse.jetty.server.SessionManager;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.webapp.WebAppContext;
/**
* AbstractTestServer
*
*
*/
public abstract class AbstractTestServer
{
protected final Server _server;
protected final int _maxInactivePeriod;
protected final int _scavengePeriod;
protected final ContextHandlerCollection _contexts;
protected SessionIdManager _sessionIdManager;
public AbstractTestServer(int port)
{
this(port, 30, 10);
}
public AbstractTestServer(int port, int maxInactivePeriod, int scavengePeriod)
{
_server = new Server(port);
_maxInactivePeriod = maxInactivePeriod;
_scavengePeriod = scavengePeriod;
_contexts = new ContextHandlerCollection();
_sessionIdManager = newSessionIdManager();
}
public abstract SessionIdManager newSessionIdManager();
public abstract AbstractSessionManager newSessionManager();
public abstract SessionHandler newSessionHandler(SessionManager sessionManager);
public void start() throws Exception
{
// server -> contexts collection -> context handler -> session handler -> servlet handler
_server.setHandler(_contexts);
_server.start();
}
public ServletContextHandler addContext(String contextPath)
{
ServletContextHandler context = new ServletContextHandler(_contexts, contextPath);
AbstractSessionManager sessionManager = newSessionManager();
sessionManager.setIdManager(_sessionIdManager);
sessionManager.setMaxInactiveInterval(_maxInactivePeriod);
SessionHandler sessionHandler = newSessionHandler(sessionManager);
sessionManager.setSessionHandler(sessionHandler);
context.setSessionHandler(sessionHandler);
return context;
}
public void stop() throws Exception
{
_server.stop();
}
public WebAppContext addWebAppContext(String warPath, String contextPath)
{
WebAppContext context = new WebAppContext(_contexts, warPath, contextPath);
AbstractSessionManager sessionManager = newSessionManager();
sessionManager.setIdManager(_sessionIdManager);
sessionManager.setMaxInactiveInterval(_maxInactivePeriod);
SessionHandler sessionHandler = newSessionHandler(sessionManager);
sessionManager.setSessionHandler(sessionHandler);
context.setSessionHandler(sessionHandler);
return context;
}
}

View File

@ -0,0 +1,162 @@
// ========================================================================
// Copyright 2004-2010 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.server.session;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.util.Random;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpMethods;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.client.ContentExchange;
import org.eclipse.jetty.client.HttpClient;
import org.testng.annotations.Test;
/**
* AbstractWebAppObjectInSessionTest
*
* Target of this test is to check that when a webapp on nodeA puts in the session
* an object of a class loaded from the war (and hence with a WebAppClassLoader),
* the same webapp on nodeB is able to load that object from the session.
*
* This test is only appropriate for clustered session managers.
*
*/
public abstract class AbstractWebAppObjectInSessionTest
{
public abstract AbstractTestServer createServer(int port);
private void copy(File source, File target) throws Exception
{
FileInputStream input = new FileInputStream(source);
FileOutputStream output = new FileOutputStream(target);
int read = -1;
byte[] bytes = new byte[64];
while ((read = input.read(bytes)) >= 0) output.write(bytes, 0, read);
input.close();
output.close();
}
@Test
public void testWebappObjectInSession() throws Exception
{
String contextName = "webappObjectInSessionTest";
String contextPath = "/" + contextName;
String servletMapping = "/server";
File targetDir = new File(System.getProperty("basedir"), "target");
File warDir = new File(targetDir, contextName);
warDir.mkdir();
File webInfDir = new File(warDir, "WEB-INF");
webInfDir.mkdir();
// Write web.xml
File webXml = new File(webInfDir, "web.xml");
String xml =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<web-app xmlns=\"http://java.sun.com/xml/ns/j2ee\"\n" +
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
" xsi:schemaLocation=\"http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd\"\n" +
" version=\"2.4\">\n" +
"\n" +
"</web-app>";
FileWriter w = new FileWriter(webXml);
w.write(xml);
w.close();
File classesDir = new File(webInfDir, "classes");
classesDir.mkdir();
String packageName = WebAppObjectInSessionServlet.class.getPackage().getName();
File packageDirs = new File(classesDir, packageName.replace('.', File.separatorChar));
packageDirs.mkdirs();
String resourceName = WebAppObjectInSessionServlet.class.getName().replace('.', File.separatorChar) + ".class";
Resource res = Resource.newResource(getClass().getClassLoader().getResource(resourceName));
//File sourceFile = new File(getClass().getClassLoader().getResource(resourceName).toURI());
File targetFile = new File(packageDirs, resourceName.substring(packageName.length()));
//copy(sourceFile, targetFile);
resourceName = WebAppObjectInSessionServlet.TestSharedNonStatic.class.getName().replace('.', File.separatorChar) + ".class";
IO.copy(res.getInputStream(), new FileOutputStream(targetFile));
resourceName = WebAppObjectInSessionServlet.TestSharedStatic.class.getName().replace('.', File.separatorChar) + ".class";
res = Resource.newResource(getClass().getClassLoader().getResource(resourceName));
//sourceFile = new File(getClass().getClassLoader().getResource(resourceName).toURI());
targetFile = new File(packageDirs, resourceName.substring(packageName.length()));
//copy(sourceFile, targetFile);
IO.copy(res.getInputStream(), new FileOutputStream(targetFile));
Random random = new Random(System.nanoTime());
int port1 = random.nextInt(50000) + 10000;
AbstractTestServer server1 = createServer(port1);
server1.addWebAppContext(warDir.getCanonicalPath(), contextPath).addServlet(WebAppObjectInSessionServlet.class.getName(), servletMapping);
server1.start();
try
{
int port2 = random.nextInt(50000) + 10000;
AbstractTestServer server2 = createServer(port2);
server2.addWebAppContext(warDir.getCanonicalPath(), contextPath).addServlet(WebAppObjectInSessionServlet.class.getName(), servletMapping);
server2.start();
try
{
HttpClient client = new HttpClient();
client.setConnectorType(HttpClient.CONNECTOR_SOCKET);
client.start();
try
{
// 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=set");
client.send(exchange1);
exchange1.waitForDone();
assert exchange1.getResponseStatus() == HttpServletResponse.SC_OK : exchange1.getResponseStatus();
String sessionCookie = exchange1.getResponseFields().getStringField("Set-Cookie");
assert sessionCookie != null;
// Mangle the cookie, replacing Path with $Path, etc.
sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
// Perform a request to server2 using the session cookie from the previous request
ContentExchange exchange2 = new ContentExchange(true);
exchange2.setMethod(HttpMethods.GET);
exchange2.setURL("http://localhost:" + port2 + contextPath + servletMapping + "?action=get");
exchange2.getRequestFields().add("Cookie", sessionCookie);
client.send(exchange2);
exchange2.waitForDone();
assert exchange2.getResponseStatus() == HttpServletResponse.SC_OK;
}
finally
{
client.stop();
}
}
finally
{
server2.stop();
}
}
finally
{
server1.stop();
}
}
}

View File

@ -0,0 +1,76 @@
// ========================================================================
// Copyright 2004-2010 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.server.session;
import java.io.IOException;
import java.io.Serializable;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* WebAppObjectInSessionServlet
*
*
*/
public class WebAppObjectInSessionServlet extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse httpServletResponse) throws ServletException, IOException
{
try
{
String action = request.getParameter("action");
if ("set".equals(action))
{
HttpSession session = request.getSession(true);
session.setAttribute("staticAttribute", new TestSharedStatic());
// session.setAttribute("objectAttribute", new TestSharedNonStatic());
// The session itself is not shareable, since the implementation class
// refers to the session manager via the hidden field this$0, and
// it seems there is no way to mark the hidden field as transient.
// session.setAttribute("sessionAttribute", session);
}
else if ("get".equals(action))
{
HttpSession session = request.getSession(false);
Object staticAttribute = session.getAttribute("staticAttribute");
assert staticAttribute instanceof TestSharedStatic;
// Object objectAttribute = session.getAttribute("objectAttribute");
// assert objectAttribute instanceof TestSharedNonStatic;
// Object sessionAttribute = session.getAttribute("sessionAttribute");
// assert sessionAttribute instanceof HttpSession;
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
// Non static inner classes are not shareable, because even if this class is portable,
// the hidden field this$0 refers to the servlet, which is a non portable class.
public class TestSharedNonStatic implements Serializable
{
}
// Static inner classes are shareable
public static class TestSharedStatic implements Serializable
{
}
}