![JAR search and dependency download from the Maven repository](/logo.png)
com.github.jeckep.spark.PSF Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sparkjava-redis-session-manager Show documentation
Show all versions of sparkjava-redis-session-manager Show documentation
Classes to store sparkjava session attributes in redis
package com.github.jeckep.spark;
import org.eclipse.jetty.server.session.AbstractSession;
import spark.Filter;
import spark.Request;
import spark.Response;
import spark.Session;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import java.io.Serializable;
import java.util.*;
/*
* Persist session filter.
* As there is no way to modify configuration of embedded jetty
* related to session manager to use another session manager.
* The only option is to create custom filter, use own cookie
* instead of JSESSIONID cookie
* */
public class PSF {
public static final String SESSION_COOKIE_NAME = "PERSISTENT_SESSION";
private Persister persister;
private List listeners = new ArrayList<>();
private int expire = 20 * 60; //sec = 20min
private boolean secure = false; //cookie passed only over https if true
public PSF(Persister persister) {
this.persister = persister;
addEventListener(new SessionChangedListener());
}
private Filter beforeFilter = (Request request, Response response) -> {
addListenersIfItIsFirstRequest(request.session());
Cookie sessionCookie = getCookieFromRequest(request, SESSION_COOKIE_NAME);
if(sessionCookie == null){
sessionCookie = genCookie();
//save cookie value in session to use it in after-filter
request.session().attribute(SESSION_COOKIE_NAME, sessionCookie.getValue());
}else{
//save cookie value in session to use it in after-filter
request.session().attribute(SESSION_COOKIE_NAME, sessionCookie.getValue());
// we have to restore session from persistent storage every time,
// if we have more than one app node and load balancer without sticky session
Map attrs = persister.restore(sessionCookie.getValue(), expire);
for(String key: attrs.keySet()){
request.session().attribute(key, attrs.get(key));
}
}
// add cookie to every response, to update expire time in user browser
// we have to generate it again in order to set correct cookie attributes, cookie from request has wrong attributes
response.raw().addCookie(genCookie(sessionCookie.getValue()));
};
private Filter afterFilter = (Request request, Response response) -> {
final Session session = request.session();
if(SessionChangedListener.checkChanged(session)) {
SessionChangedListener.setUnchanged(session);
Map sessionAttrs = new HashMap<>();
for(String key: session.attributes()){
// do not store session cookie value in a map, because it is a key,
// we can do it, but there is no need
if(PSF.SESSION_COOKIE_NAME.equals(key)) continue;
sessionAttrs.put(key, session.attribute(key));
}
String sessionCookieValue = request.session().attribute(SESSION_COOKIE_NAME);
persister.save(sessionCookieValue, sessionAttrs, expire);
}
};
private Cookie genCookie(){
return genCookie(UUID.randomUUID().toString());
}
private Cookie genCookie(String cookieValue){
Cookie cookie = new Cookie(SESSION_COOKIE_NAME, cookieValue);
cookie.setHttpOnly(true);
cookie.setSecure(secure);
cookie.setMaxAge(expire);
cookie.setPath("/");
return cookie;
}
private static Cookie getCookieFromRequest(Request req, String name){
Cookie[] cookies = req.raw().getCookies();
if(cookies != null){
for(Cookie cookie: req.raw().getCookies()){
if(name.equals(cookie.getName())){
return cookie;
}
}
}
return null;
}
public PSF setExpire(int expire) {
this.expire = expire;
return this;
}
public PSF setSecure(boolean secure) {
this.secure = secure;
return this;
}
public PSF addEventListener(EventListener listener){
listeners.add(listener);
return this;
}
public Filter getBeforeFilter() {
return beforeFilter;
}
public Filter getAfterFilter() {
return afterFilter;
}
private static class SessionChangedListener implements HttpSessionAttributeListener {
private static final String ATTR_NAME = "SESSION_CHANGED";
@Override
public void attributeAdded(HttpSessionBindingEvent event) {
setChanged(event);
}
@Override
public void attributeRemoved(HttpSessionBindingEvent event) {
setChanged(event);
}
@Override
public void attributeReplaced(HttpSessionBindingEvent event) {
setChanged(event);
}
private void setChanged(HttpSessionBindingEvent event){
if(!ATTR_NAME.equals(event.getName())){
event.getSession().setAttribute(ATTR_NAME,Boolean.TRUE);
}
}
public static Boolean checkChanged(Session session){
return session.attribute(SessionChangedListener.ATTR_NAME) != null;
}
public static void setUnchanged(Session session){
session.removeAttribute(ATTR_NAME);
}
}
//it is hack because I don't know how to get get access to SessionManager during configuration of spark
private boolean firstRequest = true;
private void addListenersIfItIsFirstRequest(Session session){
if(firstRequest){
for(EventListener l: listeners){
((AbstractSession)session.raw()).getSessionManager().addEventListener(l);
}
}
firstRequest = false;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy