Klangworks.org


Code Snippets


ServletFilter that creates a chain of XMLFilter(s) 

a class that extends ServletFilter that can make a chain of XMLFilter objects apply to the output. The basic idea is that you can infinitely add SAX Filters to the Xml before it is output. I had a need to do this for a while with something resembling a rules engine. The idea was to store all information about fields in a seperate configuration - such as required, length etc... and use that information to effect the html output


package org.klangworks;

import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.Enumeration;
import java.util.StringTokenizer;

import java.io.CharArrayWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;

import org.xml.sax.XMLReader;
import org.xml.sax.XMLFilter;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
import org.xml.sax.DTDHandler;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.InputSource;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.AttributesImpl;

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.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

import org.apache.log4j.Logger;

import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.TransformerException;

import org.xml.sax.helpers.XMLFilterImpl;

/**
* Servlet Filter to apply XMLFilters to the content
* before it is sent to the browser
* 
*@author  rob nelson
*@created August 4, 2005
*/
public class XMLServletFilter implements Filter {

private FilterConfig filterConfig = null;

private SAXParser parser;
private XMLReader reader;
private Transformer transformer;

private String contentType;
private String filterStr;

private List filters;
private XMLFilter theFilter;

/**
* Log4j Logger
*/
public static Logger logger =
  Logger.getLogger("net.klangworks.XMLServletFilter");


/**
* Initialization routine.  Reads parameters from web.xml
* sets up the parsers and reads in and creates all the
* XMLFilter[] filters
*
*@param filterConfig          The web.xml configuration info
*@exception ServletException  Exception on the servlet
*/
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;

filterStr = filterConfig.getInitParameter("filters");
contentType = filterConfig.getInitParameter("content-type");

filters = new ArrayList();

try {

  StringTokenizer st = new StringTokenizer(filterStr, ",");

  while (st.hasMoreTokens()) {
    Class clazz = Class.forName(st.nextToken());
    XMLFilter filter = (XMLFilter) clazz.newInstance();
    filters.add(filter);
  }

  SAXParserFactory spf = SAXParserFactory.newInstance();
  spf.setNamespaceAware(true);
  parser = spf.newSAXParser();
  reader = parser.getXMLReader();

  SAXTransformerFactory stf =
      (SAXTransformerFactory) TransformerFactory.newInstance();
  transformer = stf.newTransformer();

  transformer.setOutputProperty(
      javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION,
      "yes");

  XMLFilter[] filterArray = (XMLFilter[]) filters.toArray(new XMLFilter[0]);
  filterArray[0].setParent(reader);

  int size = filterArray.length;
  int flag = 1;
  while (flag < size) {
    filterArray[1].setParent(filterArray[flag - 1]);
    flag++;
  }

  theFilter = filterArray[size - 1];

} catch (Exception e) {
  throw new ServletException(e);
}

}


/**
* What to do when the filter is applied.  The will be called
* for every page it is applied ot
*
*@param request               HttpRequest
*@param response              HttpResponse
*@param chain                 The existing chain of filters
*@exception IOException       an exception with I/O
*@exception ServletException  a servlet wide exception
*/
public void doFilter(
  ServletRequest request,
  ServletResponse response,
  FilterChain chain)
   throws IOException, ServletException {

response.setContentType(contentType);

CharResponseWrapper wrapper =
    new CharResponseWrapper((HttpServletResponse) response);

chain.doFilter(request, wrapper);

logger.debug("trying to run XMLServletFilter");

try {

  InputSource source =
      new InputSource(new StringReader(wrapper.toString()));

  SAXSource saxSource = new SAXSource(theFilter, source);
  StreamResult result = new StreamResult(response.getWriter());

  transformer.transform(saxSource, result);

} catch (TransformerException tfe) {
  throw new ServletException(tfe);
}
}


/**
* What happens when the Filter is removed
*/
public void destroy() {
this.filterConfig = null;
}

}


It requires this simple class:

package org.klangworks;

import java.io.CharArrayWriter;
import java.io.PrintWriter;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

/**
* A Wrapper around a Servlet Response so we can intercept it and write
* something else
*
*@author  robnelson
*@created August 2, 2005
*/
public class CharResponseWrapper extends HttpServletResponseWrapper {
private CharArrayWriter output;


/**
* Get the output as a String
*
*@return   A string representation of the output
*/
public String toString() {
return output.toString();
}


/**
* Constructor
*
*@param response  The response to wrap
*/
public CharResponseWrapper(HttpServletResponse response) {
super(response);
output = new CharArrayWriter();
}


/**
* Gets the writer attribute of the CharResponseWrapper object
*
*@return   The writer value
*/
public PrintWriter getWriter() {
return new PrintWriter(output);
}

}

04/28/06