package org.python.util; import java.io.File; import java.io.IOException; 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.python.core.PyException; import org.python.util.PythonInterpreter; /** * Enables you to write Jython modules that inherit from javax.servlet.Filter, and to * insert them in your servlet container's filter chain, like any Java Filter. * *

* Example: * *

* /WEB-INF/filters/HeaderFilter.py: * *

 * from javax.servlet import Filter
 *
 * # Module must contain a class with the same name as the module
 * # which in turn must implement javax.servlet.Filter
 * class HeaderFilter (Filter):
 *   def init(self, config):
 *       self.header = config.getInitParameter('header')
 *
 *   def doFilter(self, request, response, chain):
 *       response.setHeader(self.header, "Yup")
 *       chain.doFilter(request, response)
 * 
* *

* web.xml: *

* *
 * <!-- Initialize the Jython runtime -->
 *   <listener>
 *       <listener-class>org.python.util.PyServletInitializer</listener-class>
 *       <load-on-startup>1</load-on-startup>
 *   </listener>
 *
 * <!-- Declare a uniquely-named PyFilter -->
 * <filter>
 *  <filter-name>HeaderFilter</filter-name>
 *  <filter-class>org.python.util.PyFilter</filter-class>
 *
 *  <!-- The special param __filter__ gives the context-relative path to the Jython source file -->
 *  <init-param>
 *    <param-name>__filter__</param-name>
 *    <param-value>/WEB-INF/pyfilter/HeaderFilter.py</param-value>
 *  </init-param>
 *
 *  <!-- Other params are passed on the the Jython filter -->
 *  <init-param>
 *    <param-name>header</param-name>
 *    <param-value>X-LookMaNoJava</param-value>
 *  </init-param>
 * </filter>
 * <filter-mapping>
 *  <filter-name>HeaderFilter</filter-name>
 *  <url-pattern>/*</url-pattern>
 * </filter-mapping>
 * 
*/ public class PyFilter implements Filter { public static final String FILTER_PATH_PARAM = "__filter__"; public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setAttribute("pyfilter", this); getFilter().doFilter(request, response, chain); } public void init(FilterConfig config) throws ServletException { if (config.getServletContext().getAttribute(PyServlet.INIT_ATTR) == null) { throw new ServletException("Jython has not been initialized. Add " + "org.python.util.PyServletInitializer as a listener to your " + "web.xml."); } this.config = config; String filterPath = config.getInitParameter(FILTER_PATH_PARAM); if (filterPath == null) { throw new ServletException("Missing required param '" + FILTER_PATH_PARAM + "'"); } source = new File(getRealPath(config.getServletContext(), filterPath)); if (!source.exists()) { throw new ServletException(source.getAbsolutePath() + " does not exist."); } interp = PyServlet.createInterpreter(config.getServletContext()); } private String getRealPath(ServletContext context, String appPath) { String realPath = context.getRealPath(appPath); // This madness seems to be necessary on Windows return realPath.replaceAll("\\\\", "/"); } private Filter getFilter() throws ServletException, IOException { if (cached == null || source.lastModified() > loadedMtime) { return loadFilter(); } return cached; } private Filter loadFilter() throws ServletException, IOException { loadedMtime = source.lastModified(); cached = PyServlet.createInstance(interp, source, Filter.class); try { cached.init(config); } catch (PyException e) { throw new ServletException(e); } return cached; } public void destroy() { if (cached != null) { cached.destroy(); } if (interp != null) { interp.cleanup(); } } private PythonInterpreter interp; private FilterConfig config; private File source; private Filter cached; private long loadedMtime; }