Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.hazelcast.web.WebFilter Maven / Gradle / Ivy
/*
* Copyright (c) 2008-2013, Hazelcast, Inc. All Rights Reserved.
*
* Licensed 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 com.hazelcast.web;
import com.hazelcast.config.Config;
import com.hazelcast.config.MapConfig;
import com.hazelcast.core.*;
import com.hazelcast.impl.ThreadContext;
import com.hazelcast.logging.ILogger;
import com.hazelcast.logging.Logger;
import com.hazelcast.nio.Data;
import com.hazelcast.util.Clock;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
import java.io.NotSerializableException;
import java.io.Serializable;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Level;
import static com.hazelcast.web.HazelcastInstanceLoader.*;
public class WebFilter implements Filter {
private static final ILogger logger = Logger.getLogger(WebFilter.class.getName());
private static final String HAZELCAST_REQUEST = "*hazelcast-request";
private static final String HAZELCAST_SESSION_COOKIE_NAME = "hazelcast.sessionId";
private static final ConcurrentMap mapOriginalSessions = new ConcurrentHashMap(1000);
private static final ConcurrentMap mapSessions = new ConcurrentHashMap(1000);
private HazelcastInstance hazelcastInstance;
private String clusterMapName = "none";
private String sessionCookieName = HAZELCAST_SESSION_COOKIE_NAME;
private String sessionCookieDomain = null;
private boolean sessionCookieSecure = false;
private boolean sessionCookieHttpOnly = false;
private boolean stickySession = true;
private boolean debug = false;
private boolean shutdownOnDestroy = true;
private Properties properties;
protected ServletContext servletContext;
protected FilterConfig filterConfig;
public WebFilter() {
}
public WebFilter(Properties properties) {
this();
this.properties = properties;
}
public final void init(final FilterConfig config) throws ServletException {
filterConfig = config;
servletContext = config.getServletContext();
initInstance();
String debugParam = getParam("debug");
if (debugParam != null) {
debug = Boolean.valueOf(debugParam);
}
String mapName = getParam("map-name");
if (mapName != null) {
clusterMapName = mapName;
} else {
clusterMapName = "_web_" + servletContext.getServletContextName();
}
try {
Config hzConfig = hazelcastInstance.getConfig();
String sessionTTL = getParam("session-ttl-seconds");
if (sessionTTL != null) {
MapConfig mapConfig = new MapConfig(clusterMapName);
mapConfig.setTimeToLiveSeconds(Integer.valueOf(sessionTTL));
hzConfig.addMapConfig(mapConfig);
}
} catch (UnsupportedOperationException ignored) {
// client cannot access Config.
}
String cookieName = getParam("cookie-name");
if (cookieName != null) {
sessionCookieName = cookieName;
}
String cookieDomain = getParam("cookie-domain");
if (cookieDomain != null) {
sessionCookieDomain = cookieDomain;
}
String cookieSecure = getParam("cookie-secure");
if (cookieSecure != null) {
sessionCookieSecure = Boolean.valueOf(cookieSecure);
}
String cookieHttpOnly = getParam("cookie-http-only");
if (cookieHttpOnly != null) {
sessionCookieHttpOnly = Boolean.valueOf(cookieHttpOnly);
}
String stickySessionParam = getParam("sticky-session");
if (stickySessionParam != null) {
stickySession = Boolean.valueOf(stickySessionParam);
}
String shutdownOnDestroyParam = getParam("shutdown-on-destroy");
if (shutdownOnDestroyParam != null) {
shutdownOnDestroy = Boolean.valueOf(shutdownOnDestroyParam);
}
if (!stickySession) {
getClusterMap().addEntryListener(new EntryListener() {
public void entryAdded(EntryEvent entryEvent) {
}
public void entryRemoved(EntryEvent entryEvent) {
if (entryEvent.getMember() == null || // client events has no owner member
!entryEvent.getMember().localMember()) {
removeSessionLocally((String) entryEvent.getKey());
}
}
public void entryUpdated(EntryEvent entryEvent) {
if (entryEvent.getMember() == null || // client events has no owner member
!entryEvent.getMember().localMember()) {
markSessionDirty((String) entryEvent.getKey());
}
}
public void entryEvicted(EntryEvent entryEvent) {
entryRemoved(entryEvent);
}
}, false);
}
log("sticky:" + stickySession + ", debug: " + debug + ", shutdown-on-destroy: " + shutdownOnDestroy
+ ", map-name: " + clusterMapName);
}
private void initInstance() throws ServletException {
if (properties == null) {
properties = new Properties();
}
setProperty(CONFIG_LOCATION);
setProperty(INSTANCE_NAME);
setProperty(USE_CLIENT);
setProperty(CLIENT_CONFIG_LOCATION);
hazelcastInstance = (HazelcastInstance) getInstance(properties);
}
private void setProperty(String propertyName) {
String value = getParam(propertyName);
if (value != null) {
properties.setProperty(propertyName, value);
}
}
private void removeSessionLocally(String sessionId) {
HazelcastHttpSession hazelSession = mapSessions.remove(sessionId);
if (hazelSession != null) {
mapOriginalSessions.remove(hazelSession.originalSession.getId());
log("Destroying session locally " + hazelSession);
hazelSession.destroy();
}
}
private void markSessionDirty(String sessionId) {
HazelcastHttpSession hazelSession = mapSessions.get(sessionId);
if (hazelSession != null) {
hazelSession.setDirty(true);
}
}
static void destroyOriginalSession(HttpSession originalSession) {
String hazelcastSessionId = mapOriginalSessions.remove(originalSession.getId());
if (hazelcastSessionId != null) {
HazelcastHttpSession hazelSession = mapSessions.remove(hazelcastSessionId);
if (hazelSession != null) {
hazelSession.webFilter.destroySession(hazelSession, false);
}
}
}
protected void log(final Object obj) {
Level level = Level.FINEST;
if (debug) {
level = Level.INFO;
}
logger.log(level, obj.toString());
}
private HazelcastHttpSession createNewSession(RequestWrapper requestWrapper, String existingSessionId) {
String id = existingSessionId != null ? existingSessionId : generateSessionId();
if (requestWrapper.getOriginalSession(false) != null) {
log("Original session exists!!!");
}
HttpSession originalSession = requestWrapper.getOriginalSession(true);
HazelcastHttpSession hazelcastSession = new HazelcastHttpSession(WebFilter.this, id, originalSession);
mapSessions.put(hazelcastSession.getId(), hazelcastSession);
String oldHazelcastSessionId = mapOriginalSessions.put(originalSession.getId(), hazelcastSession.getId());
if (oldHazelcastSessionId != null) {
log("!!! Overriding an existing hazelcastSessionId " + oldHazelcastSessionId);
}
log("Created new session with id: " + id);
log(mapSessions.size() + " is sessions.size and originalSessions.size: " + mapOriginalSessions.size());
addSessionCookie(requestWrapper, id);
return hazelcastSession;
}
/**
* Destroys a session, determining if it should be destroyed clusterwide automatically or via expiry.
*
* @param session The session to be destroyed
* @param removeGlobalSession boolean value - true if the session should be destroyed irrespective of active time
*/
private void destroySession(HazelcastHttpSession session, boolean removeGlobalSession) {
log("Destroying local session: " + session.getId());
mapSessions.remove(session.getId());
mapOriginalSessions.remove(session.originalSession.getId());
session.destroy();
if (removeGlobalSession) {
log("Destroying cluster session: " + session.getId() + " => Ignore-timeout: true");
getClusterMap().remove(session.getId());
}
}
private IMap getClusterMap() {
return hazelcastInstance.getMap(clusterMapName);
}
private HazelcastHttpSession getSessionWithId(final String sessionId) {
HazelcastHttpSession session = mapSessions.get(sessionId);
if (session != null && !session.isValid()) {
destroySession(session, true);
session = null;
}
return session;
}
private class RequestWrapper extends HttpServletRequestWrapper {
HazelcastHttpSession hazelcastSession = null;
final ResponseWrapper res;
String requestedSessionId;
public RequestWrapper(final HttpServletRequest req,
final ResponseWrapper res) {
super(req);
this.res = res;
req.setAttribute(HAZELCAST_REQUEST, this);
}
public void setHazelcastSession(HazelcastHttpSession hazelcastSession, String requestedSessionId) {
this.hazelcastSession = hazelcastSession;
this.requestedSessionId = requestedSessionId;
}
HttpSession getOriginalSession(boolean create) {
return super.getSession(create);
}
@Override
public RequestDispatcher getRequestDispatcher(final String path) {
final ServletRequest original = getRequest();
return new RequestDispatcher() {
public void forward(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
// original.getRequestDispatcher(path).forward(original, servletResponse);
original.getRequestDispatcher(path).forward(RequestWrapper.this, servletResponse);
}
public void include(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
// original.getRequestDispatcher(path).include(original, servletResponse);
original.getRequestDispatcher(path).include(RequestWrapper.this, servletResponse);
}
};
}
public String fetchHazelcastSessionId() {
if (requestedSessionId != null) {
return requestedSessionId;
}
requestedSessionId = getSessionCookie(this);
return requestedSessionId;
}
@Override
public HttpSession getSession() {
return getSession(true);
}
@Override
public HazelcastHttpSession getSession(final boolean create) {
if (hazelcastSession != null && !hazelcastSession.isValid()) {
log("Session is invalid!");
destroySession(hazelcastSession, true);
hazelcastSession = null;
}
if (hazelcastSession == null) {
HttpSession originalSession = getOriginalSession(false);
if (originalSession != null) {
String hazelcastSessionId = mapOriginalSessions.get(originalSession.getId());
if (hazelcastSessionId != null) {
hazelcastSession = mapSessions.get(hazelcastSessionId);
}
if (hazelcastSession == null) {
mapOriginalSessions.remove(originalSession.getId());
originalSession.invalidate();
} else if (hazelcastSession.isDirty()) {
hazelcastSession = null;
}
}
}
if (hazelcastSession != null)
return hazelcastSession;
final String requestedSessionId = fetchHazelcastSessionId();
if (requestedSessionId != null) {
hazelcastSession = getSessionWithId(requestedSessionId);
if (hazelcastSession == null) {
final Map mapSession = (Map) getClusterMap().get(requestedSessionId);
if (mapSession != null) {
// we already have the session in the cluster
// loading it...
hazelcastSession = createNewSession(RequestWrapper.this, requestedSessionId);
overrideSession(hazelcastSession, mapSession);
}
}
}
if (hazelcastSession == null && create) {
hazelcastSession = createNewSession(RequestWrapper.this, null);
} else if (hazelcastSession != null && !stickySession && requestedSessionId != null && hazelcastSession.isDirty()) {
log(requestedSessionId + " is dirty reloading.");
final Map mapSession = (Map) getClusterMap().get(requestedSessionId);
overrideSession(hazelcastSession, mapSession);
}
return hazelcastSession;
}
private void overrideSession(HazelcastHttpSession session, Map mapSession) {
if (session == null || mapSession == null) return;
final Enumeration atts = session.getAttributeNames();
while (atts.hasMoreElements()) {
session.removeAttribute(atts.nextElement());
}
Map mapData = null;
final Set entries = mapSession.entrySet();
for (final Map.Entry entry : entries) {
session.setAttribute((String) entry.getKey(), entry.getValue());
if (mapData == null) {
mapData = new HashMap();
}
mapData.put(entry.getKey(), entry.getValue());
}
session.sessionChanged(session.writeObject(mapData));
session.setDirty(false);
}
} // END of RequestWrapper
private class ResponseWrapper extends HttpServletResponseWrapper {
RequestWrapper req = null;
public ResponseWrapper(final HttpServletResponse original) {
super(original);
}
public void setRequest(final RequestWrapper req) {
this.req = req;
}
}
private class HazelcastHttpSession implements HttpSession {
private Data currentSessionData = null;
volatile boolean valid = true;
volatile boolean dirty = false;
final String id;
final HttpSession originalSession;
final WebFilter webFilter;
private final AtomicNumber timestamp;
public HazelcastHttpSession(WebFilter webFilter, final String sessionId, HttpSession originalSession) {
this.webFilter = webFilter;
this.id = sessionId;
this.originalSession = originalSession;
timestamp = hazelcastInstance.getAtomicNumber(clusterMapName + "_" + id);
}
public Object getAttribute(final String name) {
return originalSession.getAttribute(name);
}
public Enumeration getAttributeNames() {
return originalSession.getAttributeNames();
}
public String getId() {
return id;
}
public ServletContext getServletContext() {
return servletContext;
}
public HttpSessionContext getSessionContext() {
return originalSession.getSessionContext();
}
public Object getValue(final String name) {
return getAttribute(name);
}
public String[] getValueNames() {
return originalSession.getValueNames();
}
public boolean isDirty() {
return dirty;
}
public void setDirty(boolean dirty) {
this.dirty = dirty;
}
public void invalidate() {
originalSession.invalidate();
destroySession(this, true);
}
public boolean isNew() {
return originalSession.isNew();
}
public void putValue(final String name, final Object value) {
setAttribute(name, value);
}
public void removeAttribute(final String name) {
originalSession.removeAttribute(name);
}
public void setAttribute(final String name, final Object value) {
if (value != null && !(value instanceof Serializable)) {
throw new IllegalArgumentException(new NotSerializableException(value.getClass().getName()));
}
originalSession.setAttribute(name, value);
}
public void removeValue(final String name) {
removeAttribute(name);
}
public boolean sessionChanged(final Data data) {
try {
if (data == null) {
return currentSessionData != null;
}
return currentSessionData == null || !data.equals(currentSessionData);
} finally {
currentSessionData = data;
}
}
public long getCreationTime() {
return originalSession.getCreationTime();
}
public long getLastAccessedTime() {
return originalSession.getLastAccessedTime();
}
public int getMaxInactiveInterval() {
return originalSession.getMaxInactiveInterval();
}
public void setMaxInactiveInterval(int maxInactiveSeconds) {
originalSession.setMaxInactiveInterval(maxInactiveSeconds);
}
public synchronized Data writeObject(final Object obj) {
if (obj == null)
return null;
return ThreadContext.get().toData(obj);
}
void destroy() {
valid = false;
timestamp.destroy();
}
public boolean isValid() {
return valid;
}
void setAccessed() {
timestamp.set(Clock.currentTimeMillis());
}
long getLastAccessed() {
return hazelcastInstance.getLifecycleService().isRunning()
? timestamp.get() : 0L;
}
}// END of HazelSession
private static synchronized String generateSessionId() {
final String id = UUID.randomUUID().toString();
final StringBuilder sb = new StringBuilder("HZ");
final char[] chars = id.toCharArray();
for (final char c : chars) {
if (c != '-') {
if (Character.isLetter(c)) {
sb.append(Character.toUpperCase(c));
} else
sb.append(c);
}
}
return sb.toString();
}
private void addSessionCookie(final RequestWrapper req, final String sessionId) {
final Cookie sessionCookie = new Cookie(sessionCookieName, sessionId);
String path = req.getContextPath();
if ("".equals(path)) {
path = "/";
}
sessionCookie.setPath(path);
sessionCookie.setMaxAge(-1);
if (sessionCookieDomain != null) {
sessionCookie.setDomain(sessionCookieDomain);
}
try {
sessionCookie.setHttpOnly(sessionCookieHttpOnly);
} catch (NoSuchMethodError e) {
// must be servlet spec before 3.0, don't worry about it!
}
sessionCookie.setSecure(sessionCookieSecure);
req.res.addCookie(sessionCookie);
}
private String getSessionCookie(final RequestWrapper req) {
final Cookie[] cookies = req.getCookies();
if (cookies != null) {
for (final Cookie cookie : cookies) {
final String name = cookie.getName();
final String value = cookie.getValue();
if (name.equalsIgnoreCase(sessionCookieName)) {
return value;
}
}
}
return null;
}
public final void doFilter(ServletRequest req, ServletResponse res, final FilterChain chain)
throws IOException, ServletException {
if (!(req instanceof HttpServletRequest)) {
chain.doFilter(req, res);
} else {
if (req instanceof RequestWrapper) {
log("Request is instance of RequestWrapper! Continue...");
chain.doFilter(req, res);
return;
}
HttpServletRequest httpReq = (HttpServletRequest) req;
RequestWrapper existingReq = (RequestWrapper) req.getAttribute(HAZELCAST_REQUEST);
final ResponseWrapper resWrapper = new ResponseWrapper((HttpServletResponse) res);
final RequestWrapper reqWrapper = new RequestWrapper(httpReq, resWrapper);
resWrapper.setRequest(reqWrapper);
if (existingReq != null) {
reqWrapper.setHazelcastSession(existingReq.hazelcastSession, existingReq.requestedSessionId);
}
req = null;
res = null;
httpReq = null;
chain.doFilter(reqWrapper, resWrapper);
if (existingReq != null) return;
req = null; // for easy debugging. reqWrapper should be used
HazelcastHttpSession session = reqWrapper.getSession(false);
if (session != null && session.isValid()) {
session.setAccessed();
final Enumeration attNames = session.getAttributeNames();
Map mapData = null;
while (attNames.hasMoreElements()) {
final String attName = attNames.nextElement();
final Object value = session.getAttribute(attName);
if (mapData == null) {
mapData = new HashMap();
}
mapData.put(attName, value);
}
Data data = session.writeObject(mapData);
boolean sessionChanged = session.sessionChanged(data);
if (sessionChanged) {
if (data == null) {
mapData = new HashMap();
data = session.writeObject(mapData);
}
log("PUTTING SESSION " + session.getId());
getClusterMap().put(session.getId(), data);
}
}
}
}
public final void destroy() {
mapSessions.clear();
mapOriginalSessions.clear();
shutdownInstance();
}
protected HazelcastInstance getInstance(Properties properties) throws ServletException {
return HazelcastInstanceLoader.createInstance(filterConfig, properties);
}
protected void shutdownInstance() {
if (shutdownOnDestroy && hazelcastInstance != null) {
hazelcastInstance.getLifecycleService().shutdown();
}
}
private String getParam(String name) {
if (properties != null && properties.containsKey(name)) {
return properties.getProperty(name);
} else {
return filterConfig.getInitParameter(name);
}
}
}// END of WebFilter