Merge remote-tracking branch 'origin/jetty-9.4.x'

This commit is contained in:
Jan Bartel 2016-06-01 20:14:08 +10:00
commit 6f25ce42b2
13 changed files with 273 additions and 177 deletions

View File

@ -46,6 +46,7 @@ import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.jetty.server.session.AbstractSessionDataStore;
import org.eclipse.jetty.server.session.SessionContext;
import org.eclipse.jetty.server.session.SessionData;
import org.eclipse.jetty.server.session.UnreadableSessionDataException;
import org.eclipse.jetty.server.session.UnwriteableSessionDataException;
import org.eclipse.jetty.util.ClassLoadingObjectInputStream;
import org.eclipse.jetty.util.StringUtil;
@ -472,6 +473,10 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
Object o = ois.readObject();
session.putAllAttributes((Map<String,Object>)o);
}
catch (Exception e)
{
throw new UnreadableSessionDataException (id, _context, e);
}
reference.set(session);
}
catch (Exception e)

View File

@ -12,6 +12,7 @@
<New class="org.eclipse.jetty.server.session.DefaultSessionCacheFactory">
<Set name="evictionPolicy"><Property name="jetty.session.evictionPolicy" default="-1" /></Set>
<Set name="saveOnInactiveEvict"><Property name="jetty.session.saveOnInactiveEvict" default="false" /></Set>
<Set name="removeUnloadableSessions"><Property name="jetty.session.removeUnloadableSessions" default="false"/></Set>
</New>
</Arg>
</Call>

View File

@ -10,15 +10,13 @@
<Call name="addBean">
<Arg>
<New class="org.eclipse.jetty.server.session.JDBCSessionDataStoreFactory">
<Set name="gracePeriod"><Property name="jetty.session.gracePeriod.seconds" default="3600" /></Set>
<Set name="loadAttempts"><Property name="jetty.session.loadAttempts" default="-1" /></Set>
<Set name="deleteUnloadables"><Property name="jetty.session.deleteUnloadables" default="false" /></Set>
<Set name="gracePeriodSec"><Property name="jetty.session.gracePeriod.seconds" default="3600" /></Set>
<Set name="databaseAdaptor">
<Ref id="databaseAdaptor"/>
</Set>
<Set name="sessionTableSchema">
<New
class="org.eclipse.jetty.server.session.JDBCSessionDataStore.SessionTableSchema">
class="org.eclipse.jetty.server.session.JDBCSessionDataStore$SessionTableSchema">
<Set name="accessTimeColumn">
<Property name="jetty.sessionTableSchema.accessTimeColumn" default="accessTime" />
</Set>

View File

@ -16,3 +16,4 @@ etc/sessions/hash-session-cache.xml
[ini-template]
#jetty.session.evictionPolicy=-1
#jetty.session.saveOnInactiveEvict=false
#jetty.session.removeUnloadableSessions=false

View File

@ -20,8 +20,6 @@ db-connection-type=datasource
##
#jetty.session.gracePeriod.seconds=3600
#jetty.session.deleteUnloadables=false
#jetty.session.loadAttempts=-1
## Connection type:Datasource
db-connection-type=datasource

View File

@ -88,6 +88,9 @@ public abstract class AbstractSessionCache extends ContainerLifeCycle implements
*/
protected boolean _saveOnInactiveEviction;
protected boolean _removeUnloadableSessions;
/**
@ -281,6 +284,29 @@ public abstract class AbstractSessionCache extends ContainerLifeCycle implements
}
/**
* @return true if sessions that can't be loaded are deleted from the store
*/
@Override
public boolean isRemoveUnloadableSessions()
{
return _removeUnloadableSessions;
}
/**
* If a session's data cannot be loaded from the store without error, remove
* it from the persistent store.
*
* @param removeUnloadableSessions
*/
@Override
public void setRemoveUnloadableSessions(boolean removeUnloadableSessions)
{
_removeUnloadableSessions = removeUnloadableSessions;
}
/**
* Get a session object.
*
@ -429,7 +455,8 @@ public abstract class AbstractSessionCache extends ContainerLifeCycle implements
catch (UnreadableSessionDataException e)
{
//can't load the session, delete it
_sessionDataStore.delete(id);
if (isRemoveUnloadableSessions())
_sessionDataStore.delete(id);
throw e;
}
}
@ -580,7 +607,7 @@ public abstract class AbstractSessionCache extends ContainerLifeCycle implements
*/
@Override
public Session delete(String id) throws Exception
{
{
//get the session, if its not in memory, this will load it
Session session = get(id);

View File

@ -20,18 +20,35 @@
package org.eclipse.jetty.server.session;
/**
* MemorySessionStoreFactory
*
* DefaultSessionCacheFactory
*
* Factory for creating new DefaultSessionCaches.
*/
public class DefaultSessionCacheFactory implements SessionCacheFactory
{
int _evictionPolicy;
boolean _saveOnInactiveEvict;
boolean _removeUnloadableSessions;
public boolean isRemoveUnloadableSessions()
{
return _removeUnloadableSessions;
}
public void setRemoveUnloadableSessions(boolean removeUnloadableSessions)
{
_removeUnloadableSessions = removeUnloadableSessions;
}
public int getEvictionPolicy()
{
return _evictionPolicy;
@ -64,7 +81,6 @@ public class DefaultSessionCacheFactory implements SessionCacheFactory
/**
* @see org.eclipse.jetty.server.session.SessionCacheFactory#getSessionCache(org.eclipse.jetty.server.session.SessionHandler)
*/
@ -72,8 +88,9 @@ public class DefaultSessionCacheFactory implements SessionCacheFactory
public SessionCache getSessionCache (SessionHandler handler)
{
DefaultSessionCache cache = new DefaultSessionCache(handler);
cache.setEvictionPolicy(_evictionPolicy);
cache.setSaveOnInactiveEviction(_saveOnInactiveEvict);
cache.setEvictionPolicy(getEvictionPolicy());
cache.setSaveOnInactiveEviction(isSaveOnInactiveEvict());
cache.setRemoveUnloadableSessions(isRemoveUnloadableSessions());
return cache;
}

View File

@ -51,13 +51,10 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session");
protected boolean _initialized = false;
protected Map<String, AtomicInteger> _unloadables = new ConcurrentHashMap<>();
private DatabaseAdaptor _dbAdaptor;
private SessionTableSchema _sessionTableSchema;
private int _attempts = -1; // <= 0 means unlimited attempts to load a session
private boolean _deleteUnloadables = false; //true means if attempts exhausted delete the session
/**
* SessionTableSchema
@ -625,7 +622,6 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
if (_dbAdaptor == null)
throw new IllegalStateException("No jdbc config");
_unloadables.clear();
initialize();
super.doStart();
}
@ -636,7 +632,6 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
@Override
protected void doStop() throws Exception
{
_unloadables.clear();
super.doStop();
}
@ -667,9 +662,6 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
@Override
public SessionData load(String id) throws Exception
{
if (getLoadAttempts() > 0 && loadAttemptsExhausted(id))
throw new UnreadableSessionDataException(id, _context, true);
final AtomicReference<SessionData> reference = new AtomicReference<SessionData>();
final AtomicReference<Exception> exception = new AtomicReference<Exception>();
@ -704,16 +696,9 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
}
catch (Exception e)
{
if (getLoadAttempts() > 0)
{
incLoadAttempt (id);
}
throw new UnreadableSessionDataException (id, _context, e);
}
//if the session successfully loaded, remove failed attempts
_unloadables.remove(id);
if (LOG.isDebugEnabled())
LOG.debug("LOADED session {}", data);
}
@ -723,23 +708,6 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
reference.set(data);
}
catch (UnreadableSessionDataException e)
{
if (getLoadAttempts() > 0 && loadAttemptsExhausted(id) && isDeleteUnloadableSessions())
{
try
{
delete (id);
_unloadables.remove(id);
}
catch (Exception x)
{
LOG.warn("Problem deleting unloadable session {}", id);
}
}
exception.set(e);
}
catch (Exception e)
{
exception.set(e);
@ -762,7 +730,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
*/
@Override
public boolean delete(String id) throws Exception
{
{
try (Connection connection = _dbAdaptor.getConnection();
PreparedStatement statement = _sessionTableSchema.getDeleteStatement(connection, id, _context))
{
@ -1008,78 +976,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
_sessionTableSchema = schema;
}
public void setLoadAttempts (int attempts)
{
checkStarted();
_attempts = attempts;
}
public int getLoadAttempts ()
{
return _attempts;
}
public boolean loadAttemptsExhausted (String id)
{
AtomicInteger i = _unloadables.get(id);
if (i == null)
return false;
return (i.get() >= _attempts);
}
public void setDeleteUnloadableSessions (boolean delete)
{
checkStarted();
_deleteUnloadables = delete;
}
/**
* @return true if we should delete data for sessions that we cant reconstitute
*/
public boolean isDeleteUnloadableSessions ()
{
return _deleteUnloadables;
}
protected void incLoadAttempt (String id)
{
AtomicInteger i = new AtomicInteger(0);
AtomicInteger count = _unloadables.putIfAbsent(id, i);
if (count == null)
count = i;
count.incrementAndGet();
}
/**
* @param id the id
* @return number of attempts to load the given id
*/
public int getLoadAttempts (String id)
{
AtomicInteger i = _unloadables.get(id);
if (i == null)
return 0;
return i.get();
}
/**
* @return how many sessions we've failed to load
*/
public Set<String> getUnloadableSessions ()
{
return new HashSet<String>(_unloadables.keySet());
}
/**
*
*/
public void clearUnloadableSessions()
{
_unloadables.clear();
}
/**
@ -1094,7 +991,6 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
/**
* @see org.eclipse.jetty.server.session.SessionDataStore#exists(java.lang.String)
*/

View File

@ -31,54 +31,11 @@ public class JDBCSessionDataStoreFactory extends AbstractSessionDataStoreFactory
*
*/
DatabaseAdaptor _adaptor;
/**
*
*/
JDBCSessionDataStore.SessionTableSchema _schema;
/**
*
*/
boolean _deleteUnloadableSessions;
/**
*
*/
int _loadAttempts;
/**
* @return
*/
public boolean isDeleteUnloadableSessions()
{
return _deleteUnloadableSessions;
}
/**
* @param deleteUnloadableSessions
*/
public void setDeleteUnloadableSessions(boolean deleteUnloadableSessions)
{
_deleteUnloadableSessions = deleteUnloadableSessions;
}
/**
* @return
*/
public int getLoadAttempts()
{
return _loadAttempts;
}
/**
* @param loadAttempts
*/
public void setLoadAttempts(int loadAttempts)
{
_loadAttempts = loadAttempts;
}
/**
@ -90,9 +47,7 @@ public class JDBCSessionDataStoreFactory extends AbstractSessionDataStoreFactory
JDBCSessionDataStore ds = new JDBCSessionDataStore();
ds.setDatabaseAdaptor(_adaptor);
ds.setSessionTableSchema(_schema);
ds.setDeleteUnloadableSessions(_deleteUnloadableSessions);
ds.setGracePeriodSec(_gracePeriodSec);
ds.setLoadAttempts(_loadAttempts);
ds.setGracePeriodSec(getGracePeriodSec());
return ds;
}

View File

@ -80,4 +80,6 @@ public interface SessionCache extends LifeCycle
boolean isSaveOnInactiveEviction ();
void setSaveOnCreate(boolean saveOnCreate);
boolean isSaveOnCreate();
void setRemoveUnloadableSessions(boolean removeUnloadableSessions);
boolean isRemoveUnloadableSessions();
}

View File

@ -20,40 +20,46 @@
package org.eclipse.jetty.server.session;
/**
* UnreadableSessionData
* UnreadableSessionDataException
*
*
*/
public class UnreadableSessionDataException extends Exception
{
/**
*
*/
private static final long serialVersionUID = 1806303483488966566L;
private String _id;
private SessionContext _sessionContext;
/**
* @return the session id
*/
public String getId()
{
return _id;
}
/**
* @return the SessionContext to which the unreadable session belongs
*/
public SessionContext getSessionContext()
{
return _sessionContext;
}
/**
* @param id
* @param contextId
* @param t
*/
public UnreadableSessionDataException (String id, SessionContext contextId, Throwable t)
{
super ("Unreadable session "+id+" for "+contextId, t);
_sessionContext = contextId;
_id = id;
}
public UnreadableSessionDataException (String id, SessionContext contextId, boolean loadAttemptsExhausted)
{
super("Unreadable session "+id+" for "+contextId+(loadAttemptsExhausted?" max load attempts":""));
_sessionContext = contextId;
_id = id;
}
}

View File

@ -0,0 +1,189 @@
//
// ========================================================================
// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.server.session;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import java.io.IOException;
import java.util.Set;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.StacklessLogging;
import org.junit.Test;
/**
* DeleteUnloadableSessionTest
*
*
*/
public class DeleteUnloadableSessionTest
{
/**
* TestSessionDataStore
*
*
*/
public static class TestSessionDataStore extends AbstractSessionDataStore
{
int count = 0;
/**
* @see org.eclipse.jetty.server.session.SessionDataStore#isPassivating()
*/
@Override
public boolean isPassivating()
{
return true;
}
/**
* @see org.eclipse.jetty.server.session.SessionDataStore#exists(java.lang.String)
*/
@Override
public boolean exists(String id) throws Exception
{
return false;
}
/**
* @see org.eclipse.jetty.server.session.SessionDataMap#load(java.lang.String)
*/
@Override
public SessionData load(String id) throws Exception
{
++count;
if (count == 1)
throw new UnreadableSessionDataException(id, _context, new IllegalStateException());
return new SessionData(id, "", "", System.currentTimeMillis(), System.currentTimeMillis(), System.currentTimeMillis(), -1);
}
/**
* @see org.eclipse.jetty.server.session.SessionDataMap#delete(java.lang.String)
*/
@Override
public boolean delete(String id) throws Exception
{
return true;
}
/**
* @see org.eclipse.jetty.server.session.AbstractSessionDataStore#doStore(java.lang.String, org.eclipse.jetty.server.session.SessionData, long)
*/
@Override
public void doStore(String id, SessionData data, long lastSaveTime) throws Exception
{
//pretend it was saved
}
/**
* @see org.eclipse.jetty.server.session.AbstractSessionDataStore#doGetExpired(java.util.Set)
*/
@Override
public Set<String> doGetExpired(Set<String> candidates)
{
return null;
}
}
/**
* TestServlet
*
*
*/
public static class TestServlet extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse httpServletResponse) throws ServletException, IOException
{
String action = request.getParameter("action");
if ("test".equals(action))
{
HttpSession session = request.getSession(false);
assertNull(session);
}
}
}
/**
* Test that session data that can't be loaded results in a null Session object
* @throws Exception
*/
@Test
public void testDeleteUnloadableSession () throws Exception
{
String contextPath = "";
String servletMapping = "/server";
int inactivePeriod = -1;
int scavengePeriod = 100;
JdbcTestServer server = new JdbcTestServer(0, inactivePeriod, scavengePeriod, SessionCache.NEVER_EVICT);
ServletContextHandler context = server.addContext(contextPath);
context.getSessionHandler().getSessionCache().setRemoveUnloadableSessions(true);
TestSessionDataStore ds = new TestSessionDataStore();
context.getSessionHandler().getSessionCache().setSessionDataStore(ds);
TestServlet servlet = new TestServlet();
ServletHolder holder = new ServletHolder(servlet);
context.addServlet(holder, servletMapping);
try (StacklessLogging stackless = new StacklessLogging(Log.getLogger("org.eclipse.jetty.server.session")))
{
server.start();
int port = server.getPort();
HttpClient client = new HttpClient();
client.start();
try
{
String sessionCookie = "JSESSIONID=w0rm3zxpa6h1zg1mevtv76b3te00.w0;$Path=/";
Request request = client.newRequest("http://localhost:" + port + contextPath + servletMapping+ "?action=test");
request.header("Cookie", sessionCookie);
ContentResponse response = request.send();
assertEquals(HttpServletResponse.SC_OK,response.getStatus());
}
finally
{
client.stop();
}
}
finally
{
server.stop();
}
}
}

View File

@ -92,6 +92,7 @@ public class ReloadedSessionMissingClassTest
AbstractTestServer server1 = new JdbcTestServer(0, AbstractTestServer.DEFAULT_MAX_INACTIVE, AbstractTestServer.DEFAULT_SCAVENGE_SEC, AbstractTestServer.DEFAULT_EVICTIONPOLICY);
WebAppContext webApp = server1.addWebAppContext(unpackedWarDir.getCanonicalPath(), contextPath);
webApp.getSessionHandler().getSessionCache().setRemoveUnloadableSessions(true);
webApp.setClassLoader(loaderWithFoo);
webApp.addServlet("Bar", "/bar");
server1.start();
@ -120,7 +121,7 @@ public class ReloadedSessionMissingClassTest
//restart webapp
webApp.start();
Request request = client.newRequest("http://localhost:" + port1 + contextPath + "/bar?action=get");
request.header("Cookie", sessionCookie);
response = request.send();