package decoratorexample.controller;
import java.io.*;
import java.net.*;
import java.util.*;
import java.text.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.*;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
import org.w3c.dom.*;
/**
* A filter that performs an XSLT filtering operation on the selected file
* before it is output.
*/
public class XSLTFilter implements Filter {
/** The filter configuration object */
private FilterConfig filterConfig = null;
/**
* Constructor
*/
public XSLTFilter() {
}
/**
* Called by the container when the filter is initialized
*/
public void init(FilterConfig filterConfig) {
this.filterConfig = filterConfig;
}
/**
* Perform the actual filtering. Wrap the respsponse with an XSLT
* response wrapper.
*/
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws IOException, ServletException
{
ServletContext sc = filterConfig.getServletContext();
sc.log("DoFilter");
// wrap the response
XSLTResponseWrapper xsltResponse =
new XSLTResponseWrapper((HttpServletResponse)response,
"/SimpleTransform.xml");
HttpServletRequest httpRequest = (HttpServletRequest) request;
// forward to the next filter
chain.doFilter(httpRequest, xsltResponse);
// write the actual response to the client
sc.log("write response");
xsltResponse.writeResponse();
}
/**
* Called by the container when the filter is removed
*/
public void destroy() {
}
/**
* A utility class to adapt a ByteArrayOutputStream to be a subclass
* of ServletOutputStream
*/
class CacheOutputStream extends ServletOutputStream {
/** the ByteArrayOutputStream */
private ByteArrayOutputStream bos;
public CacheOutputStream() {
bos = new ByteArrayOutputStream();
}
/**
* Write a single byte to the output stream
*/
public void write(int b) {
bos.write(b);
}
/**
* Write an array of bytes to the output stream
*/
public void write(byte[] b, int offset, int len) {
bos.write(b, offset, len);
}
/**
* Convert this output stream to a byte array
*/
public byte[] toByteArray() {
return bos.toByteArray();
}
}
class XSLTResponseWrapper extends HttpServletResponseWrapper {
/** the original response */
private HttpServletResponse orig;
/** writer and output stream */
private PrintWriter writer;
private ServletOutputStream stream;
private ServletOutputStream outStream;
/** the name fo the XML transform */
private String transform;
/** whether the output page is XML */
private boolean isXML = false;
/**
* Constructor stores the original response and transform
*/
public XSLTResponseWrapper(HttpServletResponse response,
String transform)
{
super(response);
orig = response;
this.transform = transform;
}
/**
* Create the output stream. If the response is encoded, store it
* for transforming later. Otheriwse, just use the original stream.
*/
public ServletOutputStream createOutputStream() throws IOException {
if (containsHeader("XML-Encoded")) {
isXML = true;
outStream = new CacheOutputStream();
return outStream;
} else {
return orig.getOutputStream();
}
}
/**
* Return the output stream. Fail if getWriter() has already been
* called.
*/
public ServletOutputStream getOutputStream() throws IOException {
if (stream != null) {
return stream;
}
if (writer != null) {
throw new IOException("getWriter() already called");
}
stream = createOutputStream();
return stream;
}
/**
* Return the writer. Fail if getOutputStream() has already been
* called.
*/
public PrintWriter getWriter() throws IOException {
if (writer != null) {
return writer;
}
if (stream != null) {
throw new IOException("getOutputStream() already called");
}
writer = new PrintWriter(new OutputStreamWriter(createOutputStream()));
return writer;
}
/**
* Called byt the filter to do the actual XML transformation. Return
* immediately if the data was not in XML format.
*/
public void writeResponse() throws IOException {
if (!isXML) {
return;
}
ServletContext sc = filterConfig.getServletContext();
if (outStream == null) {
throw new IOException("No stream to commit");
}
// read the data from the cache
byte[] data = ((CacheOutputStream) outStream).toByteArray();
InputStream is = new ByteArrayInputStream(data);
sc.log("Do transform");
// do the actual transform
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
// read cached response data
Document doc = db.parse(is);
// apply the transform
TransformerFactory tf = TransformerFactory.newInstance();
StreamSource stylesheet =
new StreamSource(sc.getResourceAsStream(transform));
Transformer transformer = tf.newTransformer(stylesheet);
DOMSource source = new DOMSource(doc);
// send the results to the original output stream
StreamResult result = new StreamResult(orig.getOutputStream());
transformer.transform(source, result);
} catch( Exception ex ) {
sc.log("Error Transforming", ex);
}
}
}
}
|