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 ==================