![JAR search and dependency download from the Maven repository](/logo.png)
org.eclipse.jetty.session.infinispan.InfinispanSessionDataStore Maven / Gradle / Ivy
The newest version!
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.session.infinispan;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.session.AbstractSessionDataStore;
import org.eclipse.jetty.session.SessionData;
import org.eclipse.jetty.session.UnreadableSessionDataException;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.infinispan.commons.api.BasicCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* InfinispanSessionDataStore
*
*
*/
@ManagedObject
public class InfinispanSessionDataStore extends AbstractSessionDataStore
{
private static final Logger LOG = LoggerFactory.getLogger(InfinispanSessionDataStore.class);
/**
* Clustered cache of sessions
*/
private BasicCache _cache;
private int _infinispanIdleTimeoutSec;
private QueryManager _queryManager;
private boolean _passivating;
private boolean _serialization;
/**
* Get the clustered cache instance.
*
* @return the cache
*/
public BasicCache getCache()
{
return _cache;
}
/**
* Set the clustered cache instance.
*
* @param cache the cache
*/
public void setCache(BasicCache cache)
{
this._cache = cache;
}
@Override
protected void doStart() throws Exception
{
super.doStart();
if (_cache == null)
throw new IllegalStateException("No cache");
try
{
Class> remoteClass = InfinispanSessionDataStore.class.getClassLoader().loadClass("org.infinispan.client.hotrod.RemoteCache");
if (remoteClass.isAssignableFrom(_cache.getClass()) || _serialization)
_passivating = true;
}
catch (ClassNotFoundException e)
{
//expected if not running with remote cache
LOG.info("Hotrod classes not found, assuming infinispan in embedded mode");
}
}
public QueryManager getQueryManager()
{
return _queryManager;
}
public void setQueryManager(QueryManager queryManager)
{
_queryManager = queryManager;
}
@Override
public SessionData doLoad(String id) throws Exception
{
try
{
if (LOG.isDebugEnabled())
LOG.debug("Loading session {} from infinispan", id);
InfinispanSessionData sd = _cache.get(getCacheKey(id));
//Deserialize the attributes now that we are back in a thread that
//has the correct classloader set on it
if (isPassivating() && sd != null)
{
if (LOG.isDebugEnabled())
LOG.debug("Deserializing session attributes for {}", id);
sd.deserializeAttributes();
}
return sd;
}
catch (Exception e)
{
throw new UnreadableSessionDataException(id, _context, e);
}
}
@Override
public boolean delete(String id) throws Exception
{
if (LOG.isDebugEnabled())
LOG.debug("Deleting session with id {} from infinispan", id);
return (_cache.remove(getCacheKey(id)) != null);
}
@Override
public Set doCheckExpired(Set candidates, long time)
{
if (candidates == null || candidates.isEmpty())
return candidates;
Set expired = new HashSet<>();
for (String candidate:candidates)
{
if (LOG.isDebugEnabled())
LOG.debug("Checking expiry for candidate {}", candidate);
try
{
SessionData sd = load(candidate);
//if the session no longer exists
if (sd == null)
{
expired.add(candidate);
if (LOG.isDebugEnabled())
LOG.debug("Session {} does not exist in infinispan", candidate);
}
else
{
if (_context.getWorkerName().equals(sd.getLastNode()))
{
//we are its manager, add it to the expired set if it is expired now
if ((sd.getExpiry() > 0) && sd.getExpiry() <= time)
{
expired.add(candidate);
if (LOG.isDebugEnabled())
LOG.debug("Session {} managed by {} is expired", candidate, _context.getWorkerName());
}
}
}
}
catch (Exception e)
{
LOG.warn("Error checking if candidate {} is expired", candidate, e);
}
}
return expired;
}
@Override
public Set doGetExpired(long time)
{
//If there is a query manager, find the sessions for our context that expired before the time limit
if (_queryManager != null)
{
Set expired = new HashSet<>();
for (String sessionId : _queryManager.queryExpiredSessions(_context, time))
{
expired.add(sessionId);
if (LOG.isDebugEnabled())
LOG.debug("{}- Found expired sessionId={}", _context.getWorkerName(), sessionId);
}
return expired;
}
return Collections.emptySet();
}
@Override
public void doCleanOrphans(long timeLimit)
{
//if there is a query manager, find the sessions for any context that expired before the time limit and delete
if (_queryManager != null)
_queryManager.deleteOrphanSessions(timeLimit);
else
if (LOG.isDebugEnabled())
LOG.debug("Unable to clean orphans, no QueryManager");
}
@Override
public void doStore(String id, SessionData data, long lastSaveTime) throws Exception
{
//prepare for serialization: we need to convert the attributes now while the context
//classloader is set, because infinispan uses a different thread and classloader to
//perform the serialization
if (isPassivating() && data != null)
{
if (LOG.isDebugEnabled())
LOG.debug("Serializing session attributes for {}", id);
((InfinispanSessionData)data).serializeAttributes();
}
//Put an idle timeout on the cache entry if the session is not immortal -
//if no requests arrive at any node before this timeout occurs, or no node
//scavenges the session before this timeout occurs, the session will be removed.
//NOTE: that no session listeners can be called for this.
if (data.getMaxInactiveMs() > 0 && getInfinispanIdleTimeoutSec() > 0)
_cache.put(getCacheKey(id), (InfinispanSessionData)data, -1, TimeUnit.MILLISECONDS, getInfinispanIdleTimeoutSec(), TimeUnit.SECONDS);
else
_cache.put(getCacheKey(id), (InfinispanSessionData)data);
if (LOG.isDebugEnabled())
LOG.debug("Session {} saved to infinispan, expires {} ", id, data.getExpiry());
}
public String getCacheKey(String id)
{
return InfinispanKeyBuilder.build(_context.getCanonicalContextPath(), _context.getVhost(), id);
}
@ManagedAttribute(value = "does store serialize sessions", readonly = true)
@Override
public boolean isPassivating()
{
return _passivating;
}
@Override
public boolean doExists(String id) throws Exception
{
//if we have a query manager we can do a query with a projection to check
//if there is an unexpired session with the given id
if (_queryManager != null)
return _queryManager.exists(_context, id);
else
{
//no query manager, load the entire session data object
SessionData sd = doLoad(id);
if (sd == null)
return false;
if (sd.getExpiry() <= 0)
return true;
else
return (sd.getExpiry() > System.currentTimeMillis()); //not expired yet
}
}
@Override
public SessionData newSessionData(String id, long created, long accessed, long lastAccessed, long maxInactiveMs)
{
return new InfinispanSessionData(id, _context.getCanonicalContextPath(), _context.getVhost(), created, accessed, lastAccessed, maxInactiveMs);
}
/**
* Set the infinispan-specific idle timeout in sec or 0 if not set.
* @param sec the infinispan-specific idle timeout in sec or 0 if not set
*/
public void setInfinispanIdleTimeoutSec(int sec)
{
_infinispanIdleTimeoutSec = sec;
}
@ManagedAttribute(value = "infinispan idle timeout sec", readonly = true)
public int getInfinispanIdleTimeoutSec()
{
return _infinispanIdleTimeoutSec;
}
public void setSerialization(boolean serialization)
{
_serialization = serialization;
}
@Override
public String toString()
{
return String.format("%s[cache=%s,idleTimeoutSec=%d]", super.toString(), (_cache == null ? "" : _cache.getName()), _infinispanIdleTimeoutSec);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy