KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > taglibs > standard > tag > common > xml > TransformSupport


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.taglibs.standard.tag.common.xml;
18
19 import java.io.IOException JavaDoc;
20 import java.io.InputStream JavaDoc;
21 import java.io.Reader JavaDoc;
22 import java.io.StringReader JavaDoc;
23 import java.io.Writer JavaDoc;
24 import java.util.List JavaDoc;
25
26 import javax.servlet.http.HttpServletRequest JavaDoc;
27 import javax.servlet.jsp.JspException JavaDoc;
28 import javax.servlet.jsp.JspTagException JavaDoc;
29 import javax.servlet.jsp.PageContext JavaDoc;
30 import javax.servlet.jsp.tagext.BodyTagSupport JavaDoc;
31 import javax.xml.parsers.DocumentBuilder JavaDoc;
32 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
33 import javax.xml.parsers.ParserConfigurationException JavaDoc;
34 import javax.xml.transform.Result JavaDoc;
35 import javax.xml.transform.Source JavaDoc;
36 import javax.xml.transform.Transformer JavaDoc;
37 import javax.xml.transform.TransformerConfigurationException JavaDoc;
38 import javax.xml.transform.TransformerException JavaDoc;
39 import javax.xml.transform.TransformerFactory JavaDoc;
40 import javax.xml.transform.URIResolver JavaDoc;
41 import javax.xml.transform.dom.DOMResult JavaDoc;
42 import javax.xml.transform.dom.DOMSource JavaDoc;
43 import javax.xml.transform.sax.SAXSource JavaDoc;
44 import javax.xml.transform.stream.StreamResult JavaDoc;
45 import javax.xml.transform.stream.StreamSource JavaDoc;
46
47 import org.apache.taglibs.standard.resources.Resources;
48 import org.apache.taglibs.standard.tag.common.core.ImportSupport;
49 import org.apache.taglibs.standard.tag.common.core.Util;
50 import org.w3c.dom.Document JavaDoc;
51 import org.w3c.dom.Node JavaDoc;
52 import org.xml.sax.InputSource JavaDoc;
53 import org.xml.sax.SAXException JavaDoc;
54 import org.xml.sax.XMLReader JavaDoc;
55 import org.xml.sax.helpers.XMLReaderFactory JavaDoc;
56
57 /**
58  * <p>Support for tag handlers for &lt;transform&gt;, the XML transformation
59  * tag.</p>
60  *
61  * @author Shawn Bayern
62  */

63 public abstract class TransformSupport extends BodyTagSupport JavaDoc {
64
65     //*********************************************************************
66
// Protected state
67

68     protected Object JavaDoc xml; // attribute
69
protected String JavaDoc xmlSystemId; // attribute
70
protected Object JavaDoc xslt; // attribute
71
protected String JavaDoc xsltSystemId; // attribute
72
protected Result JavaDoc result; // attribute
73

74     //*********************************************************************
75
// Private state
76

77     private String JavaDoc var; // 'var' attribute
78
private int scope; // processed 'scope' attr
79
private Transformer JavaDoc t; // actual Transformer
80
private TransformerFactory JavaDoc tf; // reusable factory
81
private DocumentBuilder JavaDoc db; // reusable factory
82
private DocumentBuilderFactory JavaDoc dbf; // reusable factory
83

84
85     //*********************************************************************
86
// Constructor and initialization
87

88     public TransformSupport() {
89     super();
90     init();
91     }
92
93     private void init() {
94     xml = xslt = null;
95     xmlSystemId = xsltSystemId = null;
96     var = null;
97     result = null;
98     tf = null;
99         scope = PageContext.PAGE_SCOPE;
100     }
101
102
103     //*********************************************************************
104
// Tag logic
105

106     public int doStartTag() throws JspException JavaDoc {
107       /*
108        * We can set up our Transformer here, so we do so, and we let
109        * it receive parameters directly from subtags (instead of
110        * caching them.
111        */

112       try {
113
114     //************************************
115
// Initialize
116

117     // set up our DocumentBuilderFactory if necessary
118
if (dbf == null) {
119         dbf = DocumentBuilderFactory.newInstance();
120             dbf.setNamespaceAware(true);
121             dbf.setValidating(false);
122     }
123         if (db == null)
124         db = dbf.newDocumentBuilder();
125
126     // set up the TransformerFactory if necessary
127
if (tf == null)
128             tf = TransformerFactory.newInstance();
129
130     //************************************
131
// Produce transformer
132

133     Source JavaDoc s;
134     if (xslt != null) {
135         if (!(xslt instanceof String JavaDoc) && !(xslt instanceof Reader JavaDoc)
136                     && !(xslt instanceof javax.xml.transform.Source JavaDoc))
137         throw new JspTagException JavaDoc(
138             Resources.getMessage("TRANSFORM_XSLT_UNRECOGNIZED"));
139         s = getSource(xslt, xsltSystemId);
140     } else {
141         throw new JspTagException JavaDoc(
142             Resources.getMessage("TRANSFORM_NO_TRANSFORMER"));
143         }
144     tf.setURIResolver(new JstlUriResolver(pageContext));
145         t = tf.newTransformer(s);
146
147     return EVAL_BODY_BUFFERED;
148
149       } catch (SAXException JavaDoc ex) {
150     throw new JspException JavaDoc(ex);
151       } catch (ParserConfigurationException JavaDoc ex) {
152     throw new JspException JavaDoc(ex);
153       } catch (IOException JavaDoc ex) {
154     throw new JspException JavaDoc(ex);
155       } catch (TransformerConfigurationException JavaDoc ex) {
156     throw new JspException JavaDoc(ex);
157       }
158     }
159
160     // parse 'xml' or body, transform via our Transformer,
161
// and store as 'var' or through 'result'
162
public int doEndTag() throws JspException JavaDoc {
163       try {
164
165     //************************************
166
// Determine source XML
167

168     // if we haven't gotten a source, use the body (which may be empty)
169
Object JavaDoc xml = this.xml;
170     if (xml == null) // still equal
171
if (bodyContent != null && bodyContent.getString() != null)
172             xml = bodyContent.getString().trim();
173         else
174         xml = "";
175
176     // let the Source be with you
177
Source JavaDoc source = getSource(xml, xmlSystemId);
178
179     //************************************
180
// Conduct the transformation
181

182     // we can assume at most one of 'var' or 'result' is specified
183
if (result != null)
184         // we can write directly to the Result
185
t.transform(source, result);
186     else if (var != null) {
187         // we need a Document
188
Document JavaDoc d = db.newDocument();
189         Result JavaDoc doc = new DOMResult JavaDoc(d);
190         t.transform(source, doc);
191         pageContext.setAttribute(var, d, scope);
192     } else {
193         Result JavaDoc page =
194         new StreamResult JavaDoc(new SafeWriter(pageContext.getOut()));
195         t.transform(source, page);
196     }
197
198     return EVAL_PAGE;
199       } catch (SAXException JavaDoc ex) {
200     throw new JspException JavaDoc(ex);
201       } catch (ParserConfigurationException JavaDoc ex) {
202     throw new JspException JavaDoc(ex);
203       } catch (IOException JavaDoc ex) {
204     throw new JspException JavaDoc(ex);
205       } catch (TransformerException JavaDoc ex) {
206     throw new JspException JavaDoc(ex);
207       }
208     }
209
210     // Releases any resources we may have (or inherit)
211
public void release() {
212     init();
213     }
214
215
216     //*********************************************************************
217
// Public methods for subtags
218

219     /** Sets (adds) a transformation parameter on our transformer. */
220     public void addParameter(String JavaDoc name, Object JavaDoc value) {
221     t.setParameter(name, value);
222     }
223
224
225     //*********************************************************************
226
// Utility methods
227

228     /**
229      * Wraps systemId with a "jstl:" prefix to prevent the parser from
230      * thinking that the URI is truly relative and resolving it against
231      * the current directory in the filesystem.
232      */

233     private static String JavaDoc wrapSystemId(String JavaDoc systemId) {
234       if (systemId == null)
235           return "jstl:";
236       else if (ImportSupport.isAbsoluteUrl(systemId))
237           return systemId;
238       else
239           return ("jstl:" + systemId);
240     }
241
242     /**
243      * Retrieves a Source from the given Object, whether it be a String,
244      * Reader, Node, or other supported types (even a Source already).
245      * If 'url' is true, then we must be passed a String and will interpret
246      * it as a URL. A null input always results in a null output.
247      */

248     private Source JavaDoc getSource(Object JavaDoc o, String JavaDoc systemId)
249         throws SAXException JavaDoc, ParserConfigurationException JavaDoc, IOException JavaDoc {
250     if (o == null)
251         return null;
252         else if (o instanceof Source JavaDoc) {
253         return (Source JavaDoc) o;
254         } else if (o instanceof String JavaDoc) {
255         // if we've got a string, chain to Reader below
256
return getSource(new StringReader JavaDoc((String JavaDoc) o), systemId);
257         } else if (o instanceof Reader JavaDoc) {
258         // explicitly go through SAX to maintain control
259
// over how relative external entities resolve
260
XMLReader JavaDoc xr = XMLReaderFactory.createXMLReader();
261             xr.setEntityResolver(
262                 new ParseSupport.JstlEntityResolver(pageContext));
263             InputSource JavaDoc s = new InputSource JavaDoc((Reader JavaDoc) o);
264             s.setSystemId(wrapSystemId(systemId));
265             Source JavaDoc result = new SAXSource JavaDoc(xr, s);
266             result.setSystemId(wrapSystemId(systemId));
267         return result;
268         } else if (o instanceof Node JavaDoc) {
269         return new DOMSource JavaDoc((Node JavaDoc) o);
270         } else if (o instanceof List JavaDoc) {
271         // support 1-item List because our XPath processor outputs them
272
List JavaDoc l = (List JavaDoc) o;
273         if (l.size() == 1) {
274             return getSource(l.get(0), systemId); // unwrap List
275
} else {
276             throw new IllegalArgumentException JavaDoc(
277                   Resources.getMessage("TRANSFORM_SOURCE_INVALID_LIST"));
278         }
279         } else {
280         throw new IllegalArgumentException JavaDoc(
281            Resources.getMessage("TRANSFORM_SOURCE_UNRECOGNIZED")
282              + o.getClass());
283     }
284     }
285
286
287     //*********************************************************************
288
// Tag attributes
289

290     public void setVar(String JavaDoc var) {
291     this.var = var;
292     }
293
294     public void setScope(String JavaDoc scope) {
295         this.scope = Util.getScope(scope);
296     }
297
298
299     //*********************************************************************
300
// Private utility classes
301

302     /**
303      * A Writer based on a wrapped Writer but ignoring requests to
304      * close() and flush() it. (Someone must have wrapped the
305      * toilet in my office similarly...)
306      */

307     private static class SafeWriter extends Writer JavaDoc {
308     private Writer JavaDoc w;
309     public SafeWriter(Writer JavaDoc w) { this.w = w; }
310     public void close() { }
311     public void flush() { }
312     public void write(char[] cbuf, int off, int len) throws IOException JavaDoc {
313         w.write(cbuf, off, len);
314     }
315     }
316
317     //*********************************************************************
318
// JSTL-specific URIResolver class
319

320     /** Lets us resolve relative external entities. */
321     private static class JstlUriResolver implements URIResolver JavaDoc {
322         private final PageContext JavaDoc ctx;
323         public JstlUriResolver(PageContext JavaDoc ctx) {
324             this.ctx = ctx;
325         }
326         public Source JavaDoc resolve(String JavaDoc href, String JavaDoc base)
327             throws TransformerException JavaDoc {
328
329             // pass if we don't have a systemId
330
if (href == null)
331                 return null;
332
333         // remove "jstl" marker from 'base'
334
// NOTE: how 'base' is determined varies among different Xalan
335
// xsltc implementations
336
int index;
337             if (base != null && (index = base.indexOf("jstl:")) != -1) {
338                 base = base.substring(index + 5);
339             }
340
341             // we're only concerned with relative URLs
342
if (ImportSupport.isAbsoluteUrl(href)
343             || (base != null && ImportSupport.isAbsoluteUrl(base)))
344                 return null;
345
346         // base is relative; remove everything after trailing '/'
347
if (base == null || base.lastIndexOf("/") == -1)
348         base = "";
349         else
350         base = base.substring(0, base.lastIndexOf("/") + 1);
351
352         // concatenate to produce the real URL we're interested in
353
String JavaDoc target = base + href;
354
355             // for relative URLs, load and wrap the resource.
356
// don't bother checking for 'null' since we specifically want
357
// the parser to fail if the resource doesn't exist
358
InputStream JavaDoc s;
359             if (target.startsWith("/")) {
360                 s = ctx.getServletContext().getResourceAsStream(target);
361                 if (s == null)
362                     throw new TransformerException JavaDoc(
363                         Resources.getMessage("UNABLE_TO_RESOLVE_ENTITY",
364                          href));
365             } else {
366                 String JavaDoc pagePath =
367                     ((HttpServletRequest JavaDoc) ctx.getRequest()).getServletPath();
368                 String JavaDoc basePath =
369                     pagePath.substring(0, pagePath.lastIndexOf("/"));
370                 s = ctx.getServletContext().getResourceAsStream(
371                       basePath + "/" + target);
372         if (s == null)
373             throw new TransformerException JavaDoc(
374                         Resources.getMessage("UNABLE_TO_RESOLVE_ENTITY",
375                          href));
376             }
377             return new StreamSource JavaDoc(s);
378         }
379     }
380
381 }
382
Popular Tags