| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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.apache.catalina.session; |
| |
| import java.io.IOException; |
| import java.util.Arrays; |
| import java.util.concurrent.atomic.AtomicInteger; |
| |
| 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.junit.After; |
| import org.junit.Assert; |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| import org.apache.catalina.Context; |
| import org.apache.catalina.LifecycleException; |
| import org.apache.catalina.Session; |
| import org.apache.catalina.core.StandardContext; |
| import org.apache.catalina.startup.Tomcat; |
| import org.apache.catalina.startup.TomcatBaseTest; |
| import org.apache.catalina.valves.PersistentValve; |
| |
| public class TestPersistentManagerIntegration extends TomcatBaseTest { |
| |
| private final String ACTIVITY_CHECK = "org.apache.catalina.session.StandardSession.ACTIVITY_CHECK"; |
| |
| private String oldActivityCheck; |
| |
| /** |
| * As documented in config/manager.html, the "ACTIVITY_CHECK" property must |
| * be set to "true" for PersistentManager to function correctly. |
| */ |
| @Before |
| public void setActivityCheck() { |
| oldActivityCheck = System.setProperty(ACTIVITY_CHECK, "true"); |
| } |
| |
| @After |
| public void resetActivityCheck() { |
| if (oldActivityCheck != null) { |
| System.setProperty(ACTIVITY_CHECK, oldActivityCheck); |
| } else { |
| System.clearProperty(ACTIVITY_CHECK); |
| } |
| } |
| |
| /** |
| * Wait enough for the system clock to update its value. On some systems |
| * (e.g. old Windows) the clock granularity is tens of milliseconds. |
| */ |
| private void waitForClockUpdate() throws InterruptedException { |
| long startTime = System.currentTimeMillis(); |
| int waitTime = 1; |
| do { |
| Thread.sleep(waitTime); |
| waitTime *= 10; |
| } while (System.currentTimeMillis() == startTime); |
| } |
| |
| /** |
| * Wait while session access counter has a positive value. |
| */ |
| private void waitWhileSessionIsActive(StandardSession session) |
| throws InterruptedException { |
| long maxWaitTime = System.currentTimeMillis() + 60000; |
| AtomicInteger accessCount = session.accessCount; |
| while (accessCount.get() > 0) { |
| // Wait until o.a.c.connector.Request.recycle() completes, |
| // as it updates lastAccessedTime. |
| Assert.assertTrue(System.currentTimeMillis() < maxWaitTime); |
| Thread.sleep(200); |
| } |
| } |
| |
| @Test |
| public void noSessionCreate_57637() throws IOException, LifecycleException { |
| |
| // Setup Tomcat instance |
| Tomcat tomcat = getTomcatInstance(); |
| |
| // No file system docBase required |
| StandardContext ctx = (StandardContext) tomcat.addContext("", null); |
| ctx.setDistributable(true); |
| |
| Tomcat.addServlet(ctx, "DummyServlet", new DummyServlet()); |
| ctx.addServletMappingDecoded("/dummy", "DummyServlet"); |
| |
| PersistentManager manager = new PersistentManager(); |
| TesterStore store = new TesterStore(); |
| |
| manager.setStore(store); |
| manager.setMaxIdleBackup(0); |
| ctx.setManager(manager); |
| ctx.addValve(new PersistentValve()); |
| tomcat.start(); |
| Assert.assertEquals(manager.getActiveSessions(), 0); |
| Assert.assertTrue("No sessions managed", manager.getSessionIdsFull().isEmpty()); |
| Assert.assertEquals( |
| "NO_SESSION", |
| getUrl( |
| "http://localhost:" + getPort() |
| + "/dummy?no_create_session=true").toString()); |
| Assert.assertEquals(manager.getActiveSessions(), 0); |
| Assert.assertTrue("No sessions where created", manager.getSessionIdsFull().isEmpty()); |
| } |
| |
| @Test |
| public void testCreateSessionAndPassivate() throws IOException, LifecycleException, ClassNotFoundException { |
| |
| // Setup Tomcat instance |
| Tomcat tomcat = getTomcatInstance(); |
| |
| // No file system docBase required |
| StandardContext ctx = (StandardContext) tomcat.addContext("", null); |
| ctx.setDistributable(true); |
| |
| Tomcat.addServlet(ctx, "DummyServlet", new DummyServlet()); |
| ctx.addServletMappingDecoded("/dummy", "DummyServlet"); |
| |
| PersistentManager manager = new PersistentManager(); |
| TesterStore store = new TesterStore(); |
| |
| manager.setStore(store); |
| manager.setMaxIdleBackup(0); |
| ctx.setManager(manager); |
| ctx.addValve(new PersistentValve()); |
| tomcat.start(); |
| Assert.assertEquals("No active sessions", manager.getActiveSessions(), 0); |
| Assert.assertTrue("No sessions managed", manager.getSessionIdsFull().isEmpty()); |
| String sessionId = getUrl( |
| "http://localhost:" + getPort() |
| + "/dummy?no_create_session=false").toString(); |
| Assert.assertNotNull("Session is stored", store.load(sessionId)); |
| Assert.assertEquals("All sessions are passivated", manager.getActiveSessions(), 0); |
| Assert.assertTrue("One session was created", !manager.getSessionIdsFull().isEmpty()); |
| } |
| |
| @Test |
| public void backsUpOnce_56698() throws IOException, LifecycleException, |
| InterruptedException { |
| |
| // Setup Tomcat instance |
| Tomcat tomcat = getTomcatInstance(); |
| |
| // No file system docBase required |
| Context ctx = tomcat.addContext("", null); |
| ctx.setDistributable(true); |
| |
| Tomcat.addServlet(ctx, "DummyServlet", new DummyServlet()); |
| ctx.addServletMappingDecoded("/dummy", "DummyServlet"); |
| |
| PersistentManager manager = new PersistentManager(); |
| TesterStore store = new TesterStore(); |
| |
| manager.setStore(store); |
| manager.setMaxIdleBackup(0); |
| ctx.setManager(manager); |
| tomcat.start(); |
| String sessionId = getUrl("http://localhost:" + getPort() + "/dummy") |
| .toString(); |
| |
| // Note: PersistenceManager.findSession() silently updates |
| // session.lastAccessedTime, so call it only once before other work. |
| Session session = manager.findSession(sessionId); |
| |
| // Wait until request processing ends, as Request.recycle() updates |
| // session.lastAccessedTime via session.endAccess(). |
| waitWhileSessionIsActive((StandardSession) session); |
| |
| long lastAccessedTime = session.getLastAccessedTimeInternal(); |
| |
| // Session should be idle at least for 0 second (maxIdleBackup) |
| // to be eligible for persistence, thus no need to wait. |
| |
| // Waiting a bit, to catch changes in last accessed time of a session |
| waitForClockUpdate(); |
| |
| manager.processPersistenceChecks(); |
| Assert.assertEquals(Arrays.asList(sessionId), store.getSavedIds()); |
| Assert.assertEquals(lastAccessedTime, session.getLastAccessedTimeInternal()); |
| |
| // session was not accessed, so no save will be performed |
| waitForClockUpdate(); |
| manager.processPersistenceChecks(); |
| Assert.assertEquals(Arrays.asList(sessionId), store.getSavedIds()); |
| Assert.assertEquals(lastAccessedTime, session.getLastAccessedTimeInternal()); |
| |
| // access session |
| session.access(); |
| session.endAccess(); |
| |
| // session was accessed, so it will be saved once again |
| manager.processPersistenceChecks(); |
| Assert.assertEquals(Arrays.asList(sessionId, sessionId), |
| store.getSavedIds()); |
| |
| // session was not accessed, so once again no save will happen |
| manager.processPersistenceChecks(); |
| Assert.assertEquals(Arrays.asList(sessionId, sessionId), |
| store.getSavedIds()); |
| } |
| |
| private static class DummyServlet extends HttpServlet { |
| |
| private static final long serialVersionUID = -3696433049266123995L; |
| |
| @Override |
| protected void doGet(HttpServletRequest req, HttpServletResponse resp) |
| throws ServletException, IOException { |
| boolean createSession = !Boolean.parseBoolean(req |
| .getParameter("no_create_session")); |
| HttpSession session = req.getSession(createSession); |
| if (session == null) { |
| resp.getWriter().print("NO_SESSION"); |
| } else { |
| String id = session.getId(); |
| resp.getWriter().print(id); |
| } |
| } |
| |
| } |
| } |