FileDocCategorySizeDatePackage
XSLTFilter.javaAPI DocExample6991Sun Nov 23 16:09:00 GMT 2003decoratorexample.controller

XSLTFilter.java

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);
            } 
        }
    }             
}