/*
* WebFlow Navigation Manager: webflow definiton, server side navigation history and automatic session cleaning.
* Distributed under LGPL license at web site http://wfnm.sourceforge.net .
*/
package net.sf.wfnm.web;
import net.sf.wfnm.AttributeContainer;
import net.sf.wfnm.Config;
import net.sf.wfnm.NavigationManager;
import net.sf.wfnm.NavigationManagerFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* This filter allows to avoid multiple form submits.
*
* @author <a href="mailto:malbari@users.sourceforge.net">Maurizio Albari </a>
* @version 1.0.6
*/
public class NoMultipleSubmitFilter implements Filter {
/**
* The log
*/
private static Log log = LogFactory.getLog(NoMultipleSubmitFilter.class);
/**
* The URL rewriter
*/
private UrlRewriter urlRewriter;
/**
* Creates a new PageNotifierFilter object.
*/
public NoMultipleSubmitFilter() {
super();
}
/**
* Destroy the filter.
*/
public void destroy() {
}
/**
* Filter the request in order to notify that a page has been reached.
*
* @param servletRequest the servlet request
* @param servletResponse the servlet response
* @param filterChain the filter chain
*
* @throws IOException if an input/output exception ocours
* @throws ServletException if a servlet exception ocours
*/
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
AttributeContainer sessionWrapper = (AttributeContainer) HttpSessionWrapper.wrapItIfNecessary(req.getSession());
if (!Config.getInstance().isEnabled() || !NavigationManagerFactory.existsInstance(sessionWrapper)) {
filterChain.doFilter(servletRequest, servletResponse);
} else {
NavigationManager navigationManager = NavigationManagerFactory.getInstance(sessionWrapper);
Object lock = navigationManager.getLock();
boolean isFirst = (lock == null);
try {
if (isFirst) {
synchronized (req.getSession()) {
lock = navigationManager.getLock();
isFirst = (lock == null);
if (isFirst) {
lock = new Object();
navigationManager.setLock(lock);
filterChain.doFilter(servletRequest, servletResponse);
}
}
}
} finally {
if (isFirst) {
synchronized (req.getSession()) {
synchronized (lock) {
navigationManager.setLock(null);
lock.notifyAll();
}
}
} else {
synchronized (lock) {
Object currentLock = navigationManager.getLock();
if (currentLock == lock) {
try {
lock.wait();
} catch (InterruptedException ie) {
log.warn("Interrupted exception");
}
}
}
synchronized (req.getSession()) {
String url = navigationManager.getCurrentPage();
String rewrittenUrl = ((urlRewriter != null) ? urlRewriter.rewriteUrl(url) : url);
String fullUrl = req.getContextPath() + rewrittenUrl;
HttpServletResponse res = (HttpServletResponse) servletResponse;
res.sendRedirect(fullUrl);
}
}
}
}
}
/**
* Initialize the filter.
*
* @param filterConfig the filter configuration
*
* @throws ServletException if a servlet exception ocours
*/
public void init(FilterConfig filterConfig) throws ServletException {
Class urlRewriterClass = Config.getInstance().getUrlRewriter();
if (urlRewriterClass != null) {
try {
this.urlRewriter = (UrlRewriter) urlRewriterClass.newInstance();
} catch (Exception e) {
throw new ServletException("Unable to instantiate the class '" + urlRewriterClass.getName() + "'", e);
}
}
}
}