KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > filters > XsltFilter


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  * Free SoftwareFoundation, Inc.
23  * 59 Temple Place, Suite 330
24  * Boston, MA 02111-1307 USA
25  *
26  * @author Scott Ferguson
27  */

28
29 package com.caucho.filters;
30
31 import com.caucho.loader.DynamicClassLoader;
32 import com.caucho.log.Log;
33 import com.caucho.server.connection.CauchoRequest;
34 import com.caucho.server.connection.RequestAdapter;
35 import com.caucho.util.CompileException;
36 import com.caucho.util.L10N;
37 import com.caucho.vfs.MergePath;
38 import com.caucho.vfs.Path;
39 import com.caucho.vfs.ReadStream;
40 import com.caucho.vfs.TempStream;
41 import com.caucho.vfs.Vfs;
42 import com.caucho.vfs.WriteStream;
43 import com.caucho.xml.Xml;
44 import com.caucho.xml.XmlUtil;
45 import com.caucho.xpath.XPath;
46 import com.caucho.xpath.XPathException;
47 import com.caucho.xsl.AbstractStylesheetFactory;
48 import com.caucho.xsl.CauchoStylesheet;
49 import com.caucho.xsl.StyleScript;
50 import com.caucho.xsl.TransformerImpl;
51
52 import org.w3c.dom.Document JavaDoc;
53 import org.w3c.dom.ProcessingInstruction JavaDoc;
54
55 import javax.servlet.*;
56 import javax.servlet.http.HttpServletRequest JavaDoc;
57 import javax.servlet.http.HttpServletResponse JavaDoc;
58 import javax.xml.transform.OutputKeys JavaDoc;
59 import javax.xml.transform.Result JavaDoc;
60 import javax.xml.transform.Source JavaDoc;
61 import javax.xml.transform.Templates JavaDoc;
62 import javax.xml.transform.Transformer JavaDoc;
63 import javax.xml.transform.TransformerFactory JavaDoc;
64 import javax.xml.transform.dom.DOMSource JavaDoc;
65 import javax.xml.transform.stream.StreamResult JavaDoc;
66 import javax.xml.transform.stream.StreamSource JavaDoc;
67 import java.io.IOException JavaDoc;
68 import java.io.OutputStream JavaDoc;
69 import java.net.URL JavaDoc;
70 import java.util.ArrayList JavaDoc;
71 import java.util.logging.Level JavaDoc;
72 import java.util.logging.Logger JavaDoc;
73
74 /**
75  * Sends the results of the servlet through XSLT.
76  *
77  * @since Resin 2.0.6
78  */

79 public class XsltFilter implements Filter {
80   private static final L10N L = new L10N(XsltFilter.class);
81   private static final Logger JavaDoc log = Log.open(XsltFilter.class);
82   
83   private String JavaDoc _mimeType = "x-application/xslt";
84   private MergePath _stylePath;
85   private ServletContext _application;
86   private boolean _isConditional = true;
87
88   public void setMimeType(String JavaDoc mimeType)
89   {
90     _mimeType = mimeType;
91   }
92
93   public void setUnconditional(boolean isUnconditional)
94   {
95     _isConditional = ! isUnconditional;
96   }
97   
98   public void init(FilterConfig config)
99     throws ServletException
100   {
101     _stylePath = new MergePath();
102     _stylePath.addMergePath(Vfs.lookup());
103     DynamicClassLoader loader;
104     loader = (DynamicClassLoader) Thread.currentThread().getContextClassLoader();
105     String JavaDoc resourcePath = loader.getResourcePathSpecificFirst();
106     _stylePath.addClassPath(resourcePath);
107
108     _application = config.getServletContext();
109
110     if ("true".equals(config.getInitParameter("unconditional")))
111       _isConditional = false;
112   }
113   
114   /**
115    * Creates a wrapper to compress the output.
116    */

117   public void doFilter(ServletRequest JavaDoc request, ServletResponse JavaDoc response,
118                        FilterChain nextFilter)
119     throws ServletException, IOException JavaDoc
120   {
121     HttpServletRequest JavaDoc req = (HttpServletRequest JavaDoc) request;
122     HttpServletResponse JavaDoc res = (HttpServletResponse JavaDoc) response;
123
124     XsltResponse xsltResponse = new XsltResponse(req, res);
125
126     nextFilter.doFilter(req, xsltResponse);
127     xsltResponse.finish(req, res);
128   }
129   
130   /**
131    * Any cleanup for the filter.
132    */

133   public void destroy()
134   {
135   }
136
137   class XsltResponse extends CauchoResponseWrapper {
138     private HttpServletRequest JavaDoc _request;
139     private XsltTempStream _xsltStream;
140     private String JavaDoc _chainingType;
141     
142     XsltResponse(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response)
143     {
144       super(response);
145
146       _request = request;
147     }
148
149     /**
150      * This needs to be bypassed because the file's content
151      * length has nothing to do with the returned length.
152      */

153     public void setContentLength(int length)
154     {
155     }
156
157     /**
158      * Sets the content type of the filter.
159      */

160     public void setContentType(String JavaDoc contentType)
161     {
162       super.setContentType(contentType);
163
164       int p = contentType.indexOf(';');
165
166       if (p > 0)
167         contentType = contentType.substring(0, p);
168
169       if (! _isConditional ||
170       contentType.equals("x-application/xslt") ||
171           contentType.equals("x-application/xsl") ||
172           contentType.equals("x-application/stylescript")) {
173         _chainingType = contentType;
174
175     if (log.isLoggable(Level.FINER))
176       log.finer(L.l("'{0}' chaining xslt with {1}",
177             _request.getRequestURI(), contentType));
178
179         if (_xsltStream == null)
180           _xsltStream = new XsltTempStream(_response);
181         
182         _xsltStream.setChaining();
183       }
184     }
185
186     /**
187      * Calculates and returns the proper stream.
188      */

189     protected OutputStream JavaDoc getStream() throws IOException JavaDoc
190     {
191       if (_xsltStream == null)
192         _xsltStream = new XsltTempStream(_response);
193
194       return _xsltStream;
195     }
196
197     /**
198      * Flushes the stream's buffer.
199      */

200     public void flushBuffer()
201       throws IOException JavaDoc
202     {
203       super.flushBuffer();
204       
205       if (_stream != null)
206     _stream.flush();
207     }
208
209     /**
210      * Complets the request.
211      */

212     public void finish(HttpServletRequest JavaDoc req,
213                        HttpServletResponse JavaDoc res)
214       throws IOException JavaDoc, ServletException
215     {
216       try {
217     flushBuffer();
218
219         if (_chainingType == null)
220           return;
221
222         TempStream ts = _xsltStream.getTempStream();
223
224         Document JavaDoc doc = null;
225         
226         ReadStream is = ts.openRead(true);
227         Path userPath = Vfs.lookup();
228         if (req instanceof CauchoRequest)
229           userPath.setUserPath(((CauchoRequest) req).getPageURI());
230         else
231           userPath.setUserPath(req.getRequestURI());
232         is.setPath(userPath);
233
234         try {
235           doc = new Xml().parseDocument(is);
236         } finally {
237           is.close();
238         }
239       
240         String JavaDoc href = (String JavaDoc) req.getAttribute("caucho.xsl.stylesheet");
241
242         if (href == null)
243           href = getStylesheetHref(doc);
244     
245         if (href == null)
246           href = "default.xsl";
247
248         Templates JavaDoc stylesheet = null;
249         
250         //Path path = Vfs.lookup(href);
251
try {
252           //ReadStream sis = path.openRead();
253

254           TransformerFactory JavaDoc factory;
255           
256           if (_chainingType.equals("x-application/stylescript"))
257             factory = new StyleScript();
258           else {
259             factory = TransformerFactory.newInstance();
260       }
261
262       if (factory instanceof AbstractStylesheetFactory)
263         ((AbstractStylesheetFactory) factory).setStylePath(_stylePath);
264
265       Path path = null;
266       
267       if (href.startsWith("/"))
268         path = Vfs.getPwd().lookup(_application.getRealPath(href));
269       else {
270         String JavaDoc servletPath = RequestAdapter.getPageServletPath(req);
271       
272         Path pwd = Vfs.getPwd();
273         pwd = pwd.lookup(_application.getRealPath(servletPath));
274         path = pwd.getParent().lookup(href);
275       }
276
277       if (! path.canRead()) {
278         Thread JavaDoc thread = Thread.currentThread();
279         ClassLoader JavaDoc loader = thread.getContextClassLoader();
280         
281         URL JavaDoc url = loader.getResource(href);
282
283         if (url != null) {
284           Path newPath = Vfs.getPwd().lookup(url.toString());
285           if (newPath.canRead())
286         path = newPath;
287         }
288       }
289       
290       Source JavaDoc source;
291       if (path.canRead())
292         source = new StreamSource JavaDoc(path.getURL());
293       else
294         source = new StreamSource JavaDoc(href);
295
296       if (log.isLoggable(Level.FINE))
297         log.fine(L.l("'{0}' XSLT filter using stylesheet {1}",
298              req.getRequestURI(), source.getSystemId()));
299
300       stylesheet = factory.newTemplates(source);
301         } finally {
302           // is.close();
303
}
304         
305         Transformer JavaDoc transformer = null;
306
307         transformer = (Transformer JavaDoc) stylesheet.newTransformer();
308
309     TransformerImpl cauchoTransformer = null;
310     if (transformer instanceof TransformerImpl)
311       cauchoTransformer = (TransformerImpl) transformer;
312
313         String JavaDoc mediaType = (String JavaDoc) transformer.getOutputProperty(OutputKeys.MEDIA_TYPE);
314         String JavaDoc encoding = (String JavaDoc) transformer.getOutputProperty(OutputKeys.ENCODING);
315         String JavaDoc method = (String JavaDoc) transformer.getOutputProperty(OutputKeys.METHOD);
316
317         if (encoding != null) {
318         }
319         else if (method == null) {
320         }
321         else if (method.equals("xml"))
322           encoding = "UTF-8";
323
324         if (encoding != null) {
325           if (mediaType == null)
326             mediaType = "text/html";
327           res.setContentType(mediaType + "; charset=" + encoding);
328         }
329         else if (mediaType != null)
330           res.setContentType(mediaType);
331         else
332           res.setContentType("text/html");
333
334         if (encoding == null)
335           encoding = "ISO-8859-1";
336         transformer.setOutputProperty(OutputKeys.ENCODING, encoding);
337
338     ArrayList JavaDoc params = null;;
339     if (cauchoTransformer != null) {
340       params = (ArrayList JavaDoc) cauchoTransformer.getProperty(CauchoStylesheet.GLOBAL_PARAM);
341     }
342
343         for (int i = 0; params != null && i < params.size(); i++) {
344           String JavaDoc param = (String JavaDoc) params.get(i);
345         
346           transformer.setParameter(param, req.getParameter(param));
347         }
348
349     DOMSource JavaDoc domSource = new DOMSource JavaDoc(doc);
350     domSource.setSystemId(userPath.getUserPath());
351
352     Result JavaDoc result = getResult(res.getOutputStream());
353
354         transformer.transform(domSource, result);
355       } catch (IOException JavaDoc e) {
356         throw e;
357       } catch (Exception JavaDoc e) {
358         if (e instanceof CompileException)
359       throw new ServletException(e.getMessage(), e);
360     else
361       throw new ServletException(e.toString(), e);
362       }
363     }
364
365     /**
366      * Returns the result object.
367      */

368     protected Result JavaDoc getResult(OutputStream JavaDoc out)
369     {
370       return new StreamResult JavaDoc(out);
371     }
372
373     /**
374      * Returns the stylesheet specified by the page.
375      *
376      * The syntax is:
377      * <pre>
378      * &lt;?xml-stylesheet HREF='...'?>
379      * </pre>
380      *
381      * @return the href of the xml-stylesheet processing-instruction or
382      * "default.xsl" if none is found.
383      */

384     private String JavaDoc getStylesheetHref(Document JavaDoc doc)
385       throws XPathException
386     {
387       ProcessingInstruction JavaDoc pi = null;
388
389       pi = (ProcessingInstruction JavaDoc) XPath.find("//processing-instruction('xml-stylesheet')", doc);
390       
391       if (pi == null)
392         return null;
393
394       String JavaDoc value = pi.getNodeValue();
395     
396       return XmlUtil.getPIAttribute(value, "href");
397     }
398   }
399   
400   static class XsltTempStream extends OutputStream JavaDoc {
401     private ServletResponse JavaDoc _response;
402     private OutputStream JavaDoc _os;
403     
404     private TempStream _tempStream;
405
406     XsltTempStream(ServletResponse JavaDoc response)
407     {
408       _response = response;
409     }
410
411     void setChaining()
412     {
413       if (_os != null)
414         throw new IllegalStateException JavaDoc(L.l("setContentType for XSLT chaining must be before any data."));
415       
416       _tempStream = new TempStream(null);
417       _tempStream.openWrite();
418
419       _os = new WriteStream(_tempStream);
420     }
421
422     TempStream getTempStream()
423       throws IOException JavaDoc
424     {
425       if (_tempStream != null) {
426         _os.close();
427         _os = null;
428       }
429       
430       return _tempStream;
431     }
432
433     /**
434      * Writes a buffer to the underlying stream.
435      *
436      * @param ch the byte to write
437      */

438     public void write(int ch)
439       throws IOException JavaDoc
440     {
441       if (_os == null)
442         _os = _response.getOutputStream();
443
444       _os.write(ch);
445     }
446
447     /**
448      * Writes a buffer to the underlying stream.
449      *
450      * @param buffer the byte array to write.
451      * @param offset the offset into the byte array.
452      * @param length the number of bytes to write.
453      */

454     public void write(byte []buffer, int offset, int length)
455       throws IOException JavaDoc
456     {
457       if (_os == null)
458         _os = _response.getOutputStream();
459
460       _os.write(buffer, offset, length);
461     }
462
463     public void flush()
464       throws IOException JavaDoc
465     {
466       if (_os == null)
467         _os = _response.getOutputStream();
468
469       _os.flush();
470     }
471   }
472 }
473
Popular Tags