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  
20  package org.apache.myfaces.tobago.internal.webapp;
21  
22  import org.apache.myfaces.tobago.internal.util.Deprecation;
23  import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
24  import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
25  import org.slf4j.Logger;
26  import org.slf4j.LoggerFactory;
27  
28  import javax.faces.component.UIComponent;
29  import java.io.IOException;
30  import java.io.Writer;
31  import java.net.URI;
32  import java.util.Arrays;
33  import java.util.HashSet;
34  import java.util.Set;
35  
36  public abstract class TobagoResponseWriterBase extends TobagoResponseWriter {
37  
38    private static final Logger LOG = LoggerFactory.getLogger(TobagoResponseWriterBase.class);
39  
40    protected static final Set<String> EMPTY_TAG = new HashSet<String>(Arrays.asList(
41        HtmlElements.BR,
42        HtmlElements.AREA,
43        HtmlElements.LINK,
44        HtmlElements.IMG,
45        HtmlElements.PARAM,
46        HtmlElements.HR,
47        HtmlElements.INPUT,
48        HtmlElements.COL,
49        HtmlElements.BASE,
50        HtmlElements.META));
51  
52    /** @deprecated Since Tobago 1.5.3 */
53    @Deprecated
54    public static final String XML_VERSION_1_0_ENCODING_UTF_8 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
55  
56    /** @deprecated Since Tobago 1.5.3 */
57    @Deprecated
58    public static final int XML_VERSION_1_0_ENCODING_UTF_8_LENGTH = XML_VERSION_1_0_ENCODING_UTF_8.length();
59  
60    protected static final char[] XML_VERSION_1_0_ENCODING_UTF_8_CHARS = XML_VERSION_1_0_ENCODING_UTF_8.toCharArray();
61  
62    private UIComponent component;
63  
64    private boolean startStillOpen;
65  
66    private final Writer writer;
67  
68    private final String contentType;
69  
70    private final String characterEncoding;
71  
72    protected TobagoResponseWriterBase(Writer writer, String contentType, String characterEncoding) {
73      this.writer = writer;
74      this.contentType = contentType;
75      this.characterEncoding = characterEncoding != null ? characterEncoding : "UTF-8";
76    }
77  
78    protected final Writer getWriter() {
79      return writer;
80    }
81  
82    protected final UIComponent getComponent() {
83      return component;
84    }
85  
86    protected final void setComponent(UIComponent component) {
87      this.component = component;
88    }
89  
90    protected final boolean isStartStillOpen() {
91      return startStillOpen;
92    }
93  
94    protected final void setStartStillOpen(boolean startStillOpen) {
95      this.startStillOpen = startStillOpen;
96    }
97  
98    protected final String findValue(final Object value, final String property) {
99      if (value != null) {
100       return value instanceof String ? (String) value : value.toString();
101     } else if (property != null) {
102       if (component != null) {
103         final Object object = component.getAttributes().get(property);
104         if (object != null) {
105           return object instanceof String ? (String) object : object.toString();
106         } else {
107           return null;
108         }
109       } else {
110         final String trace = getCallingClassStackTraceElementString();
111         LOG.error("Don't know what to do! "
112             + "Property defined, but no component to get a value. "
113             + trace.substring(trace.indexOf('(')));
114         LOG.error("value = 'null'");
115         LOG.error("property = '" + property + "'");
116         return null;
117       }
118     } else {
119       final String trace = getCallingClassStackTraceElementString();
120       LOG.error("Don't know what to do! "
121           + "No value and no property defined. "
122           + trace.substring(trace.indexOf('(')));
123       LOG.error("value = 'null'");
124       LOG.error("property = 'null'");
125       return null;
126     }
127   }
128 
129   public void write(final char[] cbuf, final int off, final int len)
130       throws IOException {
131     writer.write(cbuf, off, len);
132   }
133 
134   @Override
135   public void write(String string) throws IOException {
136     writeInternal(writer, string);
137   }
138 
139   protected final void writeInternal(Writer writer, String string) throws IOException {
140     closeOpenTag();
141     writer.write(string);
142   }
143 
144   @Override
145   public void write(int i) throws IOException {
146     closeOpenTag();
147     writer.write(i);
148   }
149 
150   @Override
151   public void write(char[] chars) throws IOException {
152     closeOpenTag();
153     writer.write(chars);
154   }
155 
156   @Override
157   public void write(String string, int i, int i1) throws IOException {
158     closeOpenTag();
159     writer.write(string, i, i1);
160   }
161 
162   public void close() throws IOException {
163     closeOpenTag();
164     writer.close();
165   }
166 
167   public void flush() throws IOException {
168     /*
169     From the api:
170     Flush any ouput buffered by the output method to the underlying Writer or OutputStream.
171     This method will not flush the underlying Writer or OutputStream;
172     it simply clears any values buffered by this ResponseWriter.
173      */
174     closeOpenTag();
175   }
176 
177 
178 
179 
180 
181 
182   protected void closeOpenTag() throws IOException {
183     if (startStillOpen) {
184       writer.write("\n>");
185       startStillOpen = false;
186     }
187   }
188 
189   public void startDocument() throws IOException {
190     // nothing to do
191   }
192 
193   public void endDocument() throws IOException {
194     // nothing to do
195   }
196 
197   public String getContentType() {
198     return contentType;
199   }
200 
201   public String getCharacterEncoding() {
202     return characterEncoding;
203   }
204 
205   public void startElement(final String name, final UIComponent currentComponent)
206       throws IOException {
207     startElementInternal(writer, name, currentComponent);
208   }
209 
210   protected void startElementInternal(Writer writer, String name, UIComponent currentComponent)
211       throws IOException {
212     this.component = currentComponent;
213 //    closeOpenTag();
214     if (startStillOpen) {
215       writer.write("\n>");
216     }
217     writer.write("<");
218     writer.write(name);
219     startStillOpen = true;
220   }
221 
222   public void endElement(final String name) throws IOException {
223     endElementInternal(writer, name);
224   }
225 
226   public void writeComment(final Object obj) throws IOException {
227     closeOpenTag();
228     String comment = obj.toString();
229     write("<!--");
230     write(comment);
231     write("-->");
232   }
233 
234 
235 
236   public void writeAttribute(final String name, final Object value, final String property)
237       throws IOException {
238 
239     final String attribute = findValue(value, property);
240     writeAttribute(name, attribute, true);
241   }
242 
243   protected final String getCallingClassStackTraceElementString() {
244     final StackTraceElement[] stackTrace = new Exception().getStackTrace();
245     int i = 1;
246     while (stackTrace[i].getClassName().contains("TobagoResponseWriter")) {
247       i++;
248     }
249     return stackTrace[i].toString();
250   }
251 
252   public void writeURIAttribute(final String name, final Object value, final String property)
253       throws IOException {
254     if (value != null) {
255       final URI uri = URI.create(value.toString());
256       writeAttribute(name, uri.toASCIIString(), property);
257     }
258   }
259 
260 // interface TobagoResponseWriter //////////////////////////////////////////////////////////////////////////////////
261 
262   public void writeAttribute(final String name, final String value, final boolean escape)
263       throws IOException {
264     writeAttributeInternal(writer, name, value, escape);
265   }
266 
267   @Override
268   /**
269    * @deprecated Since Tobago 2.0.0
270    */
271   @Deprecated
272   public String getStyleClasses() {
273     if (component == null) {
274       return null;
275     }
276     Deprecation.LOG.error("Can't get style classes.");
277     return null;
278   }
279 
280   /**
281    * @deprecated since Tobago 1.5.0
282    */
283   @Deprecated
284   public void writeClassAttribute() throws IOException {
285     Deprecation.LOG.error("Please use writeClassAttribute(org.apache.myfaces.tobago.renderkit.css.Classes)");
286   }
287 
288 
289   protected void endElementInternal(Writer writer, String name) throws IOException {
290     if (EMPTY_TAG.contains(name)) {
291       closeEmptyTag();
292     } else {
293       if (startStillOpen) {
294         writer.write("\n>");
295       }
296       writer.write("</");
297       writer.write(name);
298 //      writer.write("\n>"); // FIXME: this makes problems with Tidy
299       writer.write(">");
300     }
301     startStillOpen = false;
302   }
303   protected abstract void closeEmptyTag() throws IOException;
304 
305   protected void writeAttributeInternal(Writer writer, String name, String value, boolean escape)
306       throws IOException {
307     if (!startStillOpen) {
308       String trace = getCallingClassStackTraceElementString();
309       String error = "Cannot write attribute when start-tag not open. "
310           + "name = '" + name + "' "
311           + "value = '" + value + "' "
312           + trace.substring(trace.indexOf('('));
313       LOG.error(error);
314       throw new IllegalStateException(error);
315     }
316 
317     if (value != null) {
318       writer.write(' ');
319       writer.write(name);
320       writer.write("=\"");
321       writerAttributeValue(value, escape);
322       writer.write('\"');
323     }
324   }
325   protected abstract void writerAttributeValue(String value, boolean escape) throws IOException;
326 
327 
328 }
329