Craig R. McClanahan wrote:

> 
> Yep, you've got the pattern down.  It's also legal to use
> HttpServletResponseWrapper if you're wrapping HTTP responses.  And, of
> course, you can wrap the request if you want to do input filtering, in
> pretty much the same manner.
> 
> Craig
> 
> 
> 


Ok, thanks for the help!  I finally got
my first Filter working, with a little
cajoling (and some begging)  ;-)

This is the typical XSL transform that I
plan to use on a set of generic servlets which
will produce XML only, with stylesheets giving
the pages 'skins.'

I know this initial implementation is not optimal,
but it works for now.  The XSLTOutputStream took
a bit of imagination.  It plugs in like this:



<filter>
  <filter-name>XSLT Filter for Skin1</filter-name>
  <filter-class>XSLTFilter</filter-class>
  <init-param>
    <param-name>xsltFileName</param-name>
    <param-value>skin1.xsl</param-value>
  </init-param>
</filter>

<filter-mapping>
  <filter-name>Skin1Command</filter-name>
  <servlet-name>command</servlet-name>
</filter-mapping>











Anyway, thanks again.




Bob
















================= BEGIN XSLTFilter ==================


import java.io.*;
import javax.servlet.*;

public class XSLTFilter implements Filter
{

FilterConfig filterConfig;
String xsltName;
ServletResponse xsltResponse;


//---##### Inner class ServletResponse
class XSLTResponse extends ServletResponseWrapper
{
OutputStream outs;
ServletOutputStream souts;

public ServletOutputStream getOutputStream()
{
  return souts;
}

public XSLTResponse(ServletResponse response,String xslFileName)
           throws ServletException,IOException
{
  super(response);
  outs = new XSLTOutputStream(response.getOutputStream(),xslFileName);
  souts = new ServletOutputStream()
    {
        public void write(int ch) throws IOException
        {
        outs.write(ch);
        }
    };
}
}
//---##### end inner class ServletResponse



public void init(FilterConfig val)
              throws ServletException
{
  filterConfig=val;
  xsltName=filterConfig.getInitParameter("xsltFileName");
  if (xsltName==null)
   throw new ServletException("XSLTFilter.init():no file name given for 
init-param 'xsltFileName'");
}

public void doFilter(ServletRequest request,ServletResponse 
response,FilterChain chain)
              throws IOException,ServletException
{
  if (xsltResponse==null)
   try
     {
     xsltResponse = new XSLTResponse(response,xsltName);
     }
   catch (Exception e)
     {
     throw new ServletException("XSLTFilter.doFilter():"+e);
     }
  chain.doFilter(request,xsltResponse);
}

public void destroy()
{
}


}


================= END XSLTFilter ==================










================= BEGIN XSLTOutputStream ==================

import java.io.*;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;


/**
* This class uses a very simple piping mechanism to "push" XML data through
* an XSL transform.
* @author Bob Jamison
* @date 25 Apr 01
*/
public class XSLTOutputStream extends FilterOutputStream
                             implements Runnable
{
OutputStream outputStream;
Transformer transformer;
PipedInputStream pins;
PipedOutputStream pouts;

public void run()
{
  try
   {
   transformer.transform(new StreamSource(pins),new 
StreamResult(outputStream));
   }
  catch (Exception e)
   {
   }
}

//Implement OutputStream things
/**
* Closes this output stream and releases any system resources
* associated with this stream. The general contract of <code>close</code>
* is that it closes the output stream. A closed stream cannot perform
* output operations and cannot be reopened.
* <p>
* @exception  IOException  if an I/O error occurs.
*/
public void close() throws IOException
{
  pouts.flush();
  pouts.close();
  //pins.close();
}

/**
* Flushes this output stream and forces any buffered output bytes
* to be written out. The general contract of <code>flush</code> is
* that calling it is an indication that, if any bytes previously
* written have been buffered by the implementation of the output
* stream, such bytes should immediately be written to their
* intended destination.
* <p>
* @exception  IOException  if an I/O error occurs.
*/
public void flush() throws IOException
{
  pouts.flush();
}

/**
* Writes <code>b.length</code> bytes from the specified byte array
* to this output stream. The general contract for <code>write(b)</code>
* is that it should have exactly the same effect as the call
* <code>write(b, 0, b.length)</code>.
*
* @param      b   the data.
* @exception  IOException  if an I/O error occurs.
* @see        java.io.OutputStream#write(byte[], int, int)
*/
public void write(byte[] b) throws IOException
{
  pouts.write(b);
}

/**
* Writes <code>len</code> bytes from the specified byte array
* starting at offset <code>off</code> to this output stream.
* The general contract for <code>write(b, off, len)</code> is that
* some of the bytes in the array <code>b</code> are written to the
* output stream in order; element <code>b[off]</code> is the first
* byte written and <code>b[off+len-1]</code> is the last byte written
* by this operation.
* <p>
* The <code>write</code> method of <code>OutputStream</code> calls
* the write method of one argument on each of the bytes to be
* written out. Subclasses are encouraged to override this method and
* provide a more efficient implementation.
* <p>
* If <code>b</code> is <code>null</code>, a
* <code>NullPointerException</code> is thrown.
* <p>
* If <code>off</code> is negative, or <code>len</code> is negative, or
* <code>off+len</code> is greater than the length of the array
* <code>b</code>, then an <tt>IndexOutOfBoundsException</tt> is thrown.
*
* @param      b     the data.
* @param      off   the start offset in the data.
* @param      len   the number of bytes to write.
* @exception  IOException  if an I/O error occurs. In particular,
*             an <code>IOException</code> is thrown if the output
*             stream is closed.
*/
public void write(byte[] b, int off, int len) throws IOException
{
  pouts.write(b,off,len);
}

/**
* Writes the specified byte to this output stream. The general
* contract for <code>write</code> is that one byte is written
* to the output stream. The byte to be written is the eight
* low-order bits of the argument <code>b</code>. The 24
* high-order bits of <code>b</code> are ignored.
* <p>
*
* @param      b   the <code>byte</code>.
* @exception  IOException  if an I/O error occurs. In particular,
*             an <code>IOException</code> may be thrown if the
*             output stream has been closed.
*/
public void write(int b) throws IOException
{
  pouts.write(b);
}

void setup(OutputStream outputStream, Transformer transformer)
                throws IOException
{
  this.transformer = transformer;
  this.outputStream = outputStream;
  pins = new PipedInputStream();
  pouts = new PipedOutputStream(pins);
  (new Thread(this)).start();
}

/**
* Creates an output stream that translates output according to the
* given XSLT Transformer.
*
* @param      outputStream  the existing XML stream to transform
* @param      transformer   the configured XSLT Transformer (see TRaX)
* @exception  IOException  if an I/O error occurs. In particular,
*             an <code>IOException</code> may be thrown if the
*             output stream has been closed.
*/
public XSLTOutputStream(OutputStream outputStream, Transformer transformer)
                 throws IOException
{
  super((OutputStream)null);
  setup(outputStream,transformer);
}

/**
* Creates an output stream that translates output according to the
* given XSLT source file..
*
* @param      outputStream  the existing XML stream to transform
* @param      xslFile       the name of the XSL stylesheet file
* @exception  TransformerException if there is a problem creating a
*             transformer from the named file
* @exception  IOException  if an I/O error occurs. In particular,
*             an <code>IOException</code> may be thrown if the
*             output stream has been closed.
*/
public XSLTOutputStream(OutputStream outputStream, String xslFile)
                throws IOException
{
  super((OutputStream)null);
  try
   {
   TransformerFactory factory = TransformerFactory.newInstance();
   Transformer transformer = factory.newTransformer(new 
StreamSource(xslFile));
   setup(outputStream,transformer);
   }
  catch (TransformerException e)
   {
   throw new IOException("XSLTOutputStreamConstructor:"+e);
   }
}

///### T E S T I N G
static boolean test(String xmlName,String xslName)
{
  try
   {
   FileInputStream ins = new FileInputStream(xmlName);
   XSLTOutputStream outs = new XSLTOutputStream(System.out,xslName);
   while (true)
     {
     int ch = ins.read();
     if (ch<0)
       break;
     outs.write(ch);
     }
   ins.close();
   outs.close();
   }
  catch (Exception e)
   {
   e.printStackTrace();
   return false;
   }
  return true;
}

public static void main(String argv[])
{
  if (argv.length==2)
   {
   test(argv[0],argv[1]);
   }
  else
   {
   System.out.println("usage: XSLOutputStream xmlFile xslFile");
   return;
   }
  }

}



================= END XSLTOutputStream ==================



Reply via email to