diff --git a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/FileSessionDataStoreTest.java b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/FileSessionDataStoreTest.java index 1cc47506216..4f00115af41 100644 --- a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/FileSessionDataStoreTest.java +++ b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/FileSessionDataStoreTest.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.server.session; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; /** * FileSessionDataStoreTest @@ -68,7 +69,17 @@ public class FileSessionDataStoreTest extends AbstractSessionDataStoreTest @Override public boolean checkSessionExists(SessionData data) throws Exception { - return (FileTestHelper.getFile(data.getId()) != null); + ClassLoader old = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader (_contextClassLoader); + try + { + return (FileTestHelper.getFile(data.getId()) != null); + } + finally + { + Thread.currentThread().setContextClassLoader(old); + } + } /** @@ -77,7 +88,29 @@ public class FileSessionDataStoreTest extends AbstractSessionDataStoreTest @Override public boolean checkSessionPersisted(SessionData data) throws Exception { - return FileTestHelper.checkSessionPersisted(data); + ClassLoader old = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader (_contextClassLoader); + try + { + return FileTestHelper.checkSessionPersisted(data); + } + catch (Throwable e) + { + e.printStackTrace(); + throw e; + } + finally + { + Thread.currentThread().setContextClassLoader(old); + } } + @Override + @Test + public void testStoreSession() throws Exception + { + super.testStoreSession(); + } + + } diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/GCloudSessionDataStoreTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/GCloudSessionDataStoreTest.java index bbdf1810263..f75b7577103 100644 --- a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/GCloudSessionDataStoreTest.java +++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/GCloudSessionDataStoreTest.java @@ -96,7 +96,16 @@ public class GCloudSessionDataStoreTest extends AbstractSessionDataStoreTest @Override public boolean checkSessionPersisted(SessionData data) throws Exception { - return __testSupport.checkSessionPersisted(data); + ClassLoader old = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader (_contextClassLoader); + try + { + return __testSupport.checkSessionPersisted(data); + } + finally + { + Thread.currentThread().setContextClassLoader(old); + } } } diff --git a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/HazelcastSessionDataStoreTest.java b/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/HazelcastSessionDataStoreTest.java index 527acb6de06..a19efa11ae5 100644 --- a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/HazelcastSessionDataStoreTest.java +++ b/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/HazelcastSessionDataStoreTest.java @@ -152,6 +152,15 @@ public class HazelcastSessionDataStoreTest extends AbstractSessionDataStoreTest @Override public boolean checkSessionPersisted(SessionData data) throws Exception { - return _testHelper.checkSessionPersisted(data); + ClassLoader old = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader (_contextClassLoader); + try + { + return _testHelper.checkSessionPersisted(data); + } + finally + { + Thread.currentThread().setContextClassLoader(old); + } } } diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InfinispanSessionDataStoreTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InfinispanSessionDataStoreTest.java index 4a3c2618c45..45d957efa55 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InfinispanSessionDataStoreTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InfinispanSessionDataStoreTest.java @@ -152,7 +152,16 @@ public class InfinispanSessionDataStoreTest extends AbstractSessionDataStoreTest @Override public boolean checkSessionPersisted(SessionData data) throws Exception { - return __testSupport.checkSessionPersisted(data); + ClassLoader old = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader (_contextClassLoader); + try + { + return __testSupport.checkSessionPersisted(data); + } + finally + { + Thread.currentThread().setContextClassLoader(old); + } } } diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteInfinispanSessionDataStoreTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteInfinispanSessionDataStoreTest.java index 40461797143..b51acf95aed 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteInfinispanSessionDataStoreTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteInfinispanSessionDataStoreTest.java @@ -96,7 +96,16 @@ public class RemoteInfinispanSessionDataStoreTest extends AbstractSessionDataSto @Override public boolean checkSessionPersisted(SessionData data) throws Exception { - return __testSupport.checkSessionPersisted(data); + ClassLoader old = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader (_contextClassLoader); + try + { + return __testSupport.checkSessionPersisted(data); + } + finally + { + Thread.currentThread().setContextClassLoader(old); + } } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/JDBCSessionDataStoreTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/JDBCSessionDataStoreTest.java index e8fdf69803b..feca7bdd942 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/JDBCSessionDataStoreTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/JDBCSessionDataStoreTest.java @@ -89,7 +89,17 @@ public class JDBCSessionDataStoreTest extends AbstractSessionDataStoreTest @Override public boolean checkSessionPersisted(SessionData data) throws Exception { - return JdbcTestHelper.checkSessionPersisted(data); + ClassLoader old = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader (_contextClassLoader); + try + { + return JdbcTestHelper.checkSessionPersisted(data); + } + finally + { + Thread.currentThread().setContextClassLoader(old); + } + } - + } diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStoreTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStoreTest.java index 9c4d8dea0ad..b739ee5a102 100644 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStoreTest.java +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStoreTest.java @@ -92,7 +92,16 @@ public class MongoSessionDataStoreTest extends AbstractSessionDataStoreTest @Override public boolean checkSessionPersisted(SessionData data) throws Exception { - return MongoTestHelper.checkSessionPersisted(data); + ClassLoader old = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader (_contextClassLoader); + try + { + return MongoTestHelper.checkSessionPersisted(data); + } + finally + { + Thread.currentThread().setContextClassLoader(old); + } } diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/MongoTestHelper.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/MongoTestHelper.java index e0ef31ff4cb..f09cf604a80 100644 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/MongoTestHelper.java +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/MongoTestHelper.java @@ -58,7 +58,7 @@ public class MongoTestHelper try { _mongoClient = - new MongoClient( System.getProperty( "embedmongo.host" ), Integer.getInteger( "embedmongoPort" ) ); + new MongoClient( System.getProperty( "embedmongo.host" ), Integer.getInteger( "embedmongoPort" ) ); } catch ( UnknownHostException e ) { diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionDataStoreTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionDataStoreTest.java index 288597bf681..64740eb790c 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionDataStoreTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionDataStoreTest.java @@ -28,13 +28,20 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; import java.lang.reflect.Proxy; +import java.net.URL; +import java.net.URLClassLoader; import java.util.Arrays; import java.util.HashSet; import java.util.Set; import java.util.concurrent.TimeUnit; import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.toolchain.test.IO; +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.junit.jupiter.api.Test; /** @@ -54,6 +61,7 @@ public abstract class AbstractSessionDataStoreTest public static final long ANCIENT_TIMESTAMP = 100L; public static final long RECENT_TIMESTAMP = System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(3*GRACE_PERIOD_SEC); + protected URLClassLoader _contextClassLoader; @@ -70,31 +78,86 @@ public abstract class AbstractSessionDataStoreTest /** - * Test that the store can persist a session. + * Test that the store can persist a session. The session uses an attribute + * class that is only known to the webapp classloader. This tests that + * we use the webapp loader when we serialize the session data (ie save the session). * * @throws Exception */ @Test public void testStoreSession() throws Exception { + //Use a class that would only be known to the webapp classloader + InputStream foostream = Thread.currentThread().getContextClassLoader().getResourceAsStream("Foo.clazz"); + File foodir = new File (MavenTestingUtils.getTargetDir(), "foo"); + foodir.mkdirs(); + File fooclass = new File (foodir, "Foo.class"); + IO.copy(foostream, new FileOutputStream(fooclass)); + + assertTrue(fooclass.exists()); + assertTrue(fooclass.length() != 0); + + URL[] foodirUrls = new URL[]{foodir.toURI().toURL()}; + _contextClassLoader = new URLClassLoader(foodirUrls, Thread.currentThread().getContextClassLoader()); + //create the SessionDataStore ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); - context.setContextPath("/test"); + context.setContextPath("/test"); + //use the classloader with the special class in it + context.setClassLoader(_contextClassLoader); + SessionDataStoreFactory factory = createSessionDataStoreFactory(); ((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(GRACE_PERIOD_SEC); SessionDataStore store = factory.getSessionDataStore(context.getSessionHandler()); SessionContext sessionContext = new SessionContext("foo", context.getServletContext()); store.initialize(sessionContext); - + store.start(); + + ClassLoader old = Thread.currentThread().getContextClassLoader(); + SessionData data = null; + try + { + Thread.currentThread().setContextClassLoader(_contextClassLoader); + Class fooclazz = Class.forName("Foo", true, _contextClassLoader); + //create a session + long now = System.currentTimeMillis(); + data = store.newSessionData("1234", 100, now, now-1, -1);//never expires + data.setLastNode(sessionContext.getWorkerName()); + + //Make an attribute that uses the class only known to the webapp classloader + data.setAttribute("a", fooclazz.getConstructor(null).newInstance()); + } + finally + { + Thread.currentThread().setContextClassLoader(old); + } + + //store the session, using a different thread to ensure + //that the thread is adorned with the webapp classloader + //before serialization + final SessionData finalData = data; - //create a session - long now = System.currentTimeMillis(); - SessionData data = store.newSessionData("1234", 100, now, now-1, -1);//never expires - data.setAttribute("a", "b"); - data.setLastNode(sessionContext.getWorkerName()); - - store.store("1234", data); + Runnable r = new Runnable() + { + + @Override + public void run() + { + try + { + store.store("1234", finalData); + } + catch (Exception e) + { + fail(e); + } + } + }; + + Thread t = new Thread(r, "saver"); + t.start(); + t.join(TimeUnit.SECONDS.toMillis(10)); //check that the store contains all of the session data assertTrue(checkSessionPersisted(data)); @@ -148,33 +211,31 @@ public abstract class AbstractSessionDataStoreTest * * @throws Exception */ - @Test - public void testStoreObjectAttributes() throws Exception - { - //create the SessionDataStore - ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); - context.setContextPath("/test"); - SessionDataStoreFactory factory = createSessionDataStoreFactory(); - ((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(GRACE_PERIOD_SEC); - SessionDataStore store = factory.getSessionDataStore(context.getSessionHandler()); - SessionContext sessionContext = new SessionContext("foo", context.getServletContext()); - store.initialize(sessionContext); - - store.start(); - - //create a session - SessionData data = store.newSessionData("1234", 100, 200, 199, -1);//never expires - TestFoo testFoo = new TestFoo(); - testFoo.setInt(33); - FooInvocationHandler handler = new FooInvocationHandler(testFoo); - Foo foo = (Foo)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[] {Foo.class}, handler); - data.setAttribute("foo", foo); - data.setLastNode(sessionContext.getWorkerName()); - - //test that it can be persisted - store.store("1234", data); - checkSessionPersisted(data); - } + /* + * @Test public void testStoreObjectAttributes() throws Exception { //create + * the SessionDataStore ServletContextHandler context = new + * ServletContextHandler(ServletContextHandler.SESSIONS); + * context.setContextPath("/test"); SessionDataStoreFactory factory = + * createSessionDataStoreFactory(); + * ((AbstractSessionDataStoreFactory)factory).setGracePeriodSec( + * GRACE_PERIOD_SEC); SessionDataStore store = + * factory.getSessionDataStore(context.getSessionHandler()); SessionContext + * sessionContext = new SessionContext("foo", context.getServletContext()); + * store.initialize(sessionContext); + * + * store.start(); + * + * //create a session SessionData data = store.newSessionData("1234", 100, + * 200, 199, -1);//never expires TestFoo testFoo = new TestFoo(); + * testFoo.setInt(33); FooInvocationHandler handler = new + * FooInvocationHandler(testFoo); Foo foo = + * (Foo)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader( + * ), new Class[] {Foo.class}, handler); data.setAttribute("foo", foo); + * data.setLastNode(sessionContext.getWorkerName()); + * + * //test that it can be persisted store.store("1234", data); + * checkSessionPersisted(data); } + */ /** * Test that we can load a persisted session. diff --git a/tests/test-sessions/test-sessions-common/src/main/resources/Foo.clazz b/tests/test-sessions/test-sessions-common/src/main/resources/Foo.clazz new file mode 100644 index 00000000000..5de06e0ab64 Binary files /dev/null and b/tests/test-sessions/test-sessions-common/src/main/resources/Foo.clazz differ diff --git a/tests/test-sessions/test-sessions-common/src/main/resources/Foo.java b/tests/test-sessions/test-sessions-common/src/main/resources/Foo.java new file mode 100644 index 00000000000..08b57983041 --- /dev/null +++ b/tests/test-sessions/test-sessions-common/src/main/resources/Foo.java @@ -0,0 +1,41 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 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. +// ======================================================================== +// + +public class Foo implements java.io.Serializable +{ + int myI = 0; + + public Foo() + { + } + + public void setI(int i) + { + myI = i; + } + + public int getI() + { + return myI; + } + + public boolean equals(Object o) + { + return ((Foo)o).getI() == myI; + } +}