blob: eb2a54f752f77c6822a0de96c9bf1f6bcfb4f7c6 [file] [log] [blame]
//
// ========================================================================
// 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 java.util.Collections;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.thread.Locker.Lock;
/**
* AbstractSessionStore
*
* Basic behaviour for maintaining an in-memory store of Session objects and
* making sure that any backing SessionDataStore is kept in sync.
*/
public abstract class AbstractSessionStore extends AbstractLifeCycle implements SessionStore
{
final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session");
protected SessionDataStore _sessionDataStore;
protected StalenessStrategy _staleStrategy;
protected SessionManager _manager;
protected SessionContext _context;
/**
* Create a new Session object from session data
* @param data
* @return
*/
public abstract Session newSession (SessionData data);
/**
* Get the session matching the key
* @param id session id
* @return
*/
public abstract Session doGet(String id);
/**
* Put the session into the map if it wasn't already there
*
* @param id the identity of the session
* @param session the session object
* @return null if the session wasn't already in the map, or the existing entry otherwise
*/
public abstract Session doPutIfAbsent (String id, Session session);
/**
* Check to see if the session exists in the store
* @param id
* @return
*/
public abstract boolean doExists (String id);
/**
* Remove the session with this identity from the store
* @param id
* @return true if removed false otherwise
*/
public abstract Session doDelete (String id);
/**
* Get a list of keys for sessions that the store thinks has expired
* @return
*/
public abstract Set<String> doGetExpiredCandidates();
/**
*
*/
public AbstractSessionStore ()
{
}
public void setSessionManager (SessionManager manager)
{
_manager = manager;
}
public SessionManager getSessionManager()
{
return _manager;
}
public void initialize (SessionContext context)
{
if (isStarted())
throw new IllegalStateException("Context set after session store started");
_context = context;
}
@Override
protected void doStart() throws Exception
{
if (_sessionDataStore == null)
throw new IllegalStateException ("No session data store configured");
if (_manager == null)
throw new IllegalStateException ("No session manager");
if (_context == null)
throw new IllegalStateException ("No ContextId");
_sessionDataStore.initialize(_context);
_sessionDataStore.start();
super.doStart();
}
@Override
protected void doStop() throws Exception
{
_sessionDataStore.stop();
super.doStop();
}
public SessionDataStore getSessionDataStore()
{
return _sessionDataStore;
}
public void setSessionDataStore(SessionDataStore sessionDataStore)
{
_sessionDataStore = sessionDataStore;
}
public StalenessStrategy getStaleStrategy()
{
return _staleStrategy;
}
public void setStaleStrategy(StalenessStrategy staleStrategy)
{
_staleStrategy = staleStrategy;
}
/**
* Get a session object.
*
* If the session object is not in this session store, try getting
* the data for it from a SessionDataStore associated with the
* session manager.
*
* @see org.eclipse.jetty.server.session.SessionStore#get(java.lang.String)
*/
@Override
public Session get(String id, boolean staleCheck) throws Exception
{
//look locally
Session session = doGet(id);
if (staleCheck && isStale(session))
{
//delete from session store so should reload from session data store
doDelete(id);
session = null;
}
//not in session store, load the data for the session if possible
if (session == null && _sessionDataStore != null)
{
SessionData data = _sessionDataStore.load(id);
if (data != null)
{
session = newSession(data);
session.setSessionManager(_manager);
Session existing = doPutIfAbsent(id, session);
if (existing != null)
{
//some other thread has got in first and added the session
//so use it
session = existing;
}
}
}
return session;
}
/**
* Put the Session object into the session store.
* If the session manager supports a session data store, write the
* session data through to the session data store.
*
* @see org.eclipse.jetty.server.session.SessionStore#put(java.lang.String, org.eclipse.jetty.server.session.Session)
*/
@Override
public void put(String id, Session session) throws Exception
{
if (id == null || session == null)
throw new IllegalArgumentException ("Put key="+id+" session="+(session==null?"null":session.getId()));
session.setSessionManager(_manager);
//if the session is new, the data has changed, or the cache is considered stale, write it to any backing store
try (Lock lock = session.lock())
{
if ((session.isNew() || session.getSessionData().isDirty() || isStale(session)) && _sessionDataStore != null)
{
if (_sessionDataStore.isPassivating())
{
session.willPassivate();
try
{
_sessionDataStore.store(id, session.getSessionData());
}
finally
{
session.didActivate();
}
}
else
_sessionDataStore.store(id, session.getSessionData());
}
}
doPutIfAbsent(id,session);
}
/**
* Check to see if the session object exists in this store.
*
* @see org.eclipse.jetty.server.session.SessionStore#exists(java.lang.String)
*/
@Override
public boolean exists(String id)
{
return doExists(id);
}
/**
* Remove a session object from this store and from any backing store.
*
* @see org.eclipse.jetty.server.session.SessionStore#delete(java.lang.String)
*/
@Override
public Session delete(String id) throws Exception
{
if (_sessionDataStore != null)
{
boolean dsdel = _sessionDataStore.delete(id);
if (LOG.isDebugEnabled()) LOG.debug("Session {} deleted in db {}",id, dsdel);
}
return doDelete(id);
}
/**
* @param session
* @return
*/
public boolean isStale (Session session)
{
if (_staleStrategy != null)
return _staleStrategy.isStale(session);
return false;
}
/**
* @see org.eclipse.jetty.server.session.SessionStore#getExpired()
*/
@Override
public Set<String> getExpired()
{
if (!isStarted())
return Collections.emptySet();
Set<String> candidates = doGetExpiredCandidates();
return _sessionDataStore.getExpired(candidates);
}
@Override
public Session newSession(HttpServletRequest request, String id, long time, long maxInactiveMs)
{
return null;
}
}