View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.custom.transform;
20  
21  import java.io.ByteArrayInputStream;
22  import java.io.File;
23  import java.io.FileInputStream;
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.io.Writer;
27  import java.net.URI;
28  import java.net.URL;
29  
30  import javax.faces.component.UIComponentBase;
31  import javax.faces.context.FacesContext;
32  import javax.faces.el.ValueBinding;
33  import javax.xml.transform.Transformer;
34  import javax.xml.transform.TransformerException;
35  import javax.xml.transform.TransformerFactory;
36  import javax.xml.transform.stream.StreamResult;
37  import javax.xml.transform.stream.StreamSource;
38  
39  /**
40   * Transforms XML using and XSL stylesheet.
41   * 
42   * Used to transform XML (from either a String or URL) using either XSLT or
43   * Velocity.
44   *
45   * @JSFComponent
46   *   name = "t:xmlTransform"
47   *   class = "org.apache.myfaces.custom.transform.XmlTransform"
48   *   tagClass = "org.apache.myfaces.custom.transform.XmlTransformTag"
49   * @since 1.1.7
50   * @author Sean Schofield
51   */
52  public abstract class AbstractXmlTransform extends UIComponentBase
53  {
54      public static final String COMPONENT_TYPE = "org.apache.myfaces.tomahawk.XmlTransform";
55      public static final String COMPONENT_FAMILY = "org.apache.myfaces.tomahawk.Transform";
56  
57      private Object contentStream;
58      private Object styleStream;
59      
60      // see superclass for documentation
61      public String getFamily()
62      {
63          return COMPONENT_FAMILY;
64      }
65  
66      public void encodeBegin(FacesContext context)
67              throws IOException
68      {
69          InputStream xmlStream = (InputStream)getContentStream();
70          String xml = getContent();
71          String xmlLocation = getContentLocation();
72  
73          InputStream xslStream = (InputStream)getStyleStream();
74          String xsl = getStylesheet();
75          String xslLocation = getStylesheetLocation();
76  
77          if (context == null) throw new NullPointerException("context");
78          if (!isRendered()) return;
79  
80          if (getContent() == null && getContentLocation() == null && getContentStream() == null)
81              throw new NullPointerException("content/contentLocation/contentStream cannot all be null");
82  
83          //TODO - handle all cases
84          if (xmlLocation != null)
85          {
86              ClassLoader loader = Thread.currentThread().getContextClassLoader();
87              if (loader == null)
88              {
89                  loader = AbstractXmlTransform.class.getClassLoader();
90              }
91  
92              URL url = loader.getResource(xmlLocation);
93              xmlStream = new FileInputStream(new File(URI.create(url.toString())));
94          }
95  
96          if (xslLocation != null)
97          {
98              ClassLoader loader = Thread.currentThread().getContextClassLoader();
99              if (loader == null)
100             {
101                 loader = AbstractXmlTransform.class.getClassLoader();
102             }
103 
104             URL url = loader.getResource(xslLocation);
105             xslStream = new FileInputStream(new File(URI.create(url.toString())));
106         }
107 
108         if (xml != null)
109         {
110             xmlStream = new ByteArrayInputStream(xml.getBytes());
111         }
112 
113         if (xsl != null)
114         {
115             xslStream = new ByteArrayInputStream(xsl.getBytes());
116         }
117 
118         if (xmlStream != null && xslStream != null)
119         {
120             transformContent(xmlStream, xslStream);
121         }
122     }
123 
124     /**
125      * Transforms an XML string using the stylesheet string provided.
126      *
127      * @param content The XML to transform
128      * @param stylesheet The stylesheet to use in the transformation
129      * @throws IOException
130      */
131     private void transformContent(InputStream content, InputStream stylesheet)
132         throws IOException
133     {
134         try
135         {
136             TransformerFactory tFactory = TransformerFactory.newInstance();
137             Transformer transformer = tFactory.newTransformer(new StreamSource(stylesheet));
138 
139             Writer responseWriter = FacesContext.getCurrentInstance().getResponseWriter();
140             transformer.transform(new StreamSource(content), new StreamResult(responseWriter));
141         }
142         catch (TransformerException te)
143         {
144             throw new IOException("Error while transforming XML: " + te.getMessage());
145         }
146     }
147 
148     // component does not need to manage its own children (its not allowed to have any)
149     public void encodeChildren(FacesContext context)
150             throws IOException
151     {}
152 
153     // nothing special to do here
154     public void encodeEnd(FacesContext context)
155             throws IOException
156     {}
157 
158     /**
159      * String containing the XML content to be transformed.
160      * 
161      * @JSFProperty
162      */
163     public abstract String getContent();
164 
165     /**
166      * String containing the location of the XML content to be transformed.
167      * 
168      * @JSFProperty
169      */
170     public abstract String getContentLocation();
171 
172     /**
173      * String containing the XSL information to use in the transformation.
174      * 
175      * @JSFProperty
176      */
177     public abstract String getStylesheet();
178     
179     public void setContentStream(Object contentStream)
180     {
181         this.contentStream = contentStream;
182     }
183 
184     /**
185      * Value binding expression referencing an InputStream from which the XML content is to be read.
186      * 
187      * @JSFProperty
188      */
189     public Object getContentStream()
190     {
191         if (contentStream != null) return contentStream;
192 
193         ValueBinding vb = getValueBinding("contentStream");
194         return (vb != null) ? vb.getValue(getFacesContext()) : null;
195     }
196     
197 
198     /**
199      * String containing the location of the XSL stylesheet to use in the transformation.
200      * 
201      * @JSFProperty
202      */
203     public abstract String getStylesheetLocation();
204   
205     public void setStyleStream(Object styleStream)
206     {
207         this.styleStream = styleStream;
208     }
209 
210     /**
211      * Value binding expression referencing an InputStream from which the XSL stylesheet is to be read.
212      * 
213      * @JSFProperty
214      */
215     public Object getStyleStream()
216     {
217         if (styleStream != null) return styleStream;
218 
219         ValueBinding vb = getValueBinding("styleStream");
220         return (vb != null) ? vb.getValue(getFacesContext()) : null;
221     }
222     
223 }