/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
* (c) 2014 Boundless
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.cluster.hazelcast.web;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.geoserver.cluster.hazelcast.HzCluster;
import com.google.common.collect.Iterators;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.web.WebFilter;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
/**
* Creates and delegates to a WebFilter if clustering is enabled. The delegate is created lazily.
* @author Kevin Smith, OpenGeo
*
*/
public class HzSessionShareFilter implements Filter {
// Need to use a delegator because WebFilter#doFilter is final and assumes that a Hazelcast
// instance has been created.
// TODO when the Servlet API dependency is updated to 3.0, this can all be made a lot simpler.
WebFilter delegate;
ServletContext srvCtx;
HzCluster cluster;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
srvCtx = filterConfig.getServletContext();
WebApplicationContextUtils.getWebApplicationContext(filterConfig.getServletContext());
}
protected HzCluster getCluster() {
if(cluster==null) {
ApplicationContext ac =
WebApplicationContextUtils.getRequiredWebApplicationContext(srvCtx);
cluster = ac.getBean("hzCluster", HzCluster.class);
}
return cluster;
}
private void createDelegate() throws ServletException {
// Stop if clustering is not enabled
if(!getCluster().isSessionSharing()) return;
// Don't bother if we already have one
if(delegate!=null) return;
// Create the delegate and override its getInstance method to use the cluster's instance
delegate = new WebFilter(){
@Override
protected HazelcastInstance getInstance(Properties properties)
throws ServletException {
return getCluster().getHz();
}
};
initDelegate();
}
private void initDelegate() throws ServletException {
// Set up init-params for the delegate instance
// TODO Maybe make these configurable in cluster.properties
final Map<String, String> params = new HashMap<String,String>();
params.put("map-name", "geoserver-sessions");
params.put("sticky-session", Boolean.toString(getCluster().isStickySession()));
params.put("instance-name", getCluster().getHz().getConfig().getInstanceName());
FilterConfig config = new FilterConfig() {
@Override
public String getFilterName() {
return "hazelcast";
}
@Override
public ServletContext getServletContext() {
return srvCtx;
}
@Override
public String getInitParameter(String name) {
return params.get(name);
}
@Override
public Enumeration<String> getInitParameterNames() {
return Iterators.asEnumeration(params.keySet().iterator());
}
};
delegate.init(config);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
createDelegate();
if(delegate!=null){
delegate.doFilter(request, response, chain);
} else {
chain.doFilter(request, response);
}
}
@Override
public void destroy() {
if(delegate!=null) delegate.destroy();
}
}