2009/05/20 - Apache Shale has been retired.

For more information, please explore the Attic.

View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to you under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.shale.remoting.faces;
19  
20  import java.io.IOException;
21  import java.io.Writer;
22  import javax.faces.component.UIComponent;
23  import javax.faces.context.ResponseWriter;
24  
25  /***
26   * <p>Basic implementation of <code>javax.faces.context.ResponseWriter</code>
27   * for use when a content type other than <code>text/html</code> is desired
28   * (such as <code>text/xml</code>).</p>
29   */
30  public class BasicResponseWriter extends ResponseWriter {
31  
32  
33      // ------------------------------------------------------------ Constructors
34  
35  
36      /***
37       * <p>Create a new instance configured with the specified properties.</p>
38       *
39       * @param writer <code>Writer</code> to be wrapped
40       * @param contentType Content type of this response
41       * @param characterEncoding Character encoding of thie response
42       **/
43      public BasicResponseWriter(Writer writer, String contentType, String characterEncoding) {
44          this.writer = writer;
45          this.contentType = contentType;
46          this.characterEncoding = characterEncoding;
47      }
48  
49  
50      // ------------------------------------------------------ Instance Variables
51  
52  
53      /***
54       * <p>The character encoding of the response we are creating.</p>
55       */
56      private String characterEncoding = null;
57  
58  
59      /***
60       * <p>The content type of the response we are creating.</p>
61       */
62      private String contentType = "text/html";
63  
64  
65      /***
66       * <p>Flag indicating that an element has been started.</p>
67       */
68      private boolean open = false;
69  
70  
71      /***
72       * <p>The <code>Writer</code> we are wrapping.</p>
73       */
74      private Writer writer = null;
75  
76  
77      // ----------------------------------------------------- Mock Object Methods
78  
79  
80  
81      // -------------------------------------------------- ResponseWriter Methods
82  
83  
84      /*** {@inheritDoc} */
85      public ResponseWriter cloneWithWriter(Writer writer) {
86          return new BasicResponseWriter(writer, contentType, characterEncoding);
87      }
88  
89  
90      /*** {@inheritDoc} */
91      public void endDocument() throws IOException {
92          finish();
93          writer.flush();
94      }
95  
96  
97      /*** {@inheritDoc} */
98      public void endElement(String name) throws IOException {
99          if (open) {
100             writer.write("/");
101             finish();
102         } else {
103             writer.write("</");
104             writer.write(name);
105             writer.write(">");
106         }
107     }
108 
109 
110     /*** {@inheritDoc} */
111     public String getCharacterEncoding() {
112         return this.characterEncoding;
113     }
114 
115 
116     /*** {@inheritDoc} */
117     public String getContentType() {
118         return this.contentType;
119     }
120 
121 
122     /*** {@inheritDoc} */
123     public void flush() throws IOException {
124         finish();
125     }
126 
127 
128     /*** {@inheritDoc} */
129     public void startDocument() throws IOException {
130         // Do nothing
131     }
132 
133 
134     /*** {@inheritDoc} */
135     public void startElement(String name, UIComponent component) throws IOException {
136         if (name == null) {
137             throw new NullPointerException();
138         }
139         finish();
140         writer.write('<');
141         writer.write(name);
142         open = true;
143     }
144 
145 
146     /*** {@inheritDoc} */
147     public void writeAttribute(String name, Object value, String property) throws IOException {
148         if ((name == null) || (value == null)) {
149             throw new NullPointerException();
150         }
151         if (!open) {
152             throw new IllegalStateException();
153         }
154         writer.write(" ");
155         writer.write(name);
156         writer.write("=\"");
157         if (value instanceof String) {
158             string((String) value);
159         } else {
160             string(value.toString());
161         }
162         writer.write("\"");
163     }
164 
165 
166     /*** {@inheritDoc} */
167     public void writeComment(Object comment) throws IOException {
168         if (comment == null) {
169             throw new NullPointerException();
170         }
171         finish();
172         writer.write("<!-- ");
173         if (comment instanceof String) {
174             writer.write((String) comment);
175         } else {
176             writer.write(comment.toString());
177         }
178         writer.write(" -->");
179     }
180 
181 
182     /*** {@inheritDoc} */
183     public void writeText(Object text, String property) throws IOException {
184         if (text == null) {
185             throw new NullPointerException();
186         }
187         finish();
188         if (text instanceof String) {
189             string((String) text);
190         } else {
191             string(text.toString());
192         }
193     }
194 
195 
196     /*** {@inheritDoc} */
197     public void writeText(char[] text, int off, int len) throws IOException {
198         if (text == null) {
199             throw new NullPointerException();
200         }
201         if ((off < 0) || (off > text.length) || (len < 0) || (len > text.length)) {
202             throw new IndexOutOfBoundsException();
203         }
204         finish();
205         string(text, off, len);
206     }
207 
208 
209     /*** {@inheritDoc} */
210     public void writeURIAttribute(String name, Object value, String property) throws IOException {
211         if ((name == null) || (value == null)) {
212             throw new NullPointerException();
213         }
214         if (!open) {
215             throw new IllegalStateException();
216         }
217         writer.write(" ");
218         writer.write(name);
219         writer.write("=\"");
220         if (value instanceof String) {
221             string((String) value);
222         } else {
223             string(value.toString());
224         }
225         writer.write("\"");
226     }
227 
228 
229     // ---------------------------------------------------------- Writer Methods
230 
231 
232     /*** {@inheritDoc} */
233     public void close() throws IOException {
234         finish();
235         writer.close();
236     }
237 
238 
239     /*** {@inheritDoc} */
240     public void write(char[] cbuf, int off, int len) throws IOException {
241         finish();
242         writer.write(cbuf, off, len);
243     }
244 
245 
246     // --------------------------------------------------------- Support Methods
247 
248 
249     /***
250      * <p>Write the specified character, filtering if necessary.</p>
251      *
252      * @param ch Character to be written
253      *
254      * @exception IOException if an input/output error occurs
255      */
256     private void character(char ch) throws IOException {
257 
258         if (ch <= 0xff) {
259             // In single byte characters, replace only the five
260             // characters for which well-known entities exist in XML
261             if (ch == 0x22) {
262                 writer.write("&quot;");
263             } else if (ch == 0x26) {
264                 writer.write("&amp;");
265             } else if (ch == 0x27) {
266                 writer.write("&apos;");
267             } else if (ch == 0x3C) {
268                 writer.write("&lt;");
269             } else if (ch == 0X3E) {
270                 writer.write("&gt;");
271             } else {
272                 writer.write(ch);
273             }
274         } else {
275             if (substitution()) {
276                 numeric(writer, ch);
277             } else {
278                 writer.write(ch);
279             }
280         }
281 
282     }
283 
284 
285     /***
286      * <p>Close any element that is currently open.</p>
287      *
288      * @exception IOException if an input/output error occurs
289      */
290     private void finish() throws IOException {
291 
292         if (open) {
293             writer.write(">");
294             open = false;
295         }
296 
297     }
298 
299 
300     /***
301      * <p>Write a numeric character reference for specified character
302      * to the specfied writer.</p>
303      *
304      * @param writer Writer we are writing to
305      * @param ch Character to be translated and appended
306      *
307      * @exception IOException if an input/output error occurs
308      */
309     private void numeric(Writer writer, char ch) throws IOException {
310 
311         writer.write("&#");
312         writer.write(String.valueOf((int) ch));
313         writer.write(";");
314 
315     }
316 
317 
318     /***
319      * <p>Write the specified characters (after performing suitable
320      * replacement of characters by corresponding entities).</p>
321      *
322      * @param text Character array containing text to be written
323      * @param off Starting offset (zero relative)
324      * @param len Number of characters to be written
325      *
326      * @exception IOException if an input/output error occurs
327      */
328     private void string(char[] text, int off, int len) throws IOException {
329 
330         // Process the specified characters
331         for (int i = off; i < (off + len); i++) {
332             character(text[i]);
333         }
334 
335     }
336 
337 
338     /***
339      * <p>Write the specified string (after performing suitable
340      * replacement of characters by corresponding entities).</p>
341      *
342      * @param s String to be filtered and written
343      *
344      * @exception IOException if an input/output error occurs
345      */
346     private void string(String s) throws IOException {
347 
348         for (int i = 0; i < s.length(); i++) {
349             character(s.charAt(i));
350         }
351 
352     }
353 
354 
355     /***
356      * <p>Return true if entity substitution should be performed on double
357      * byte character values.</p>
358      */
359     private boolean substitution() {
360 
361         return !("UTF-8".equals(characterEncoding) || "UTF-16".equals(characterEncoding));
362 
363     }
364 
365 
366 }