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.component.Attributes;
23  import org.apache.myfaces.tobago.internal.util.FastStringWriter;
24  import org.apache.myfaces.tobago.internal.util.HtmlWriterUtils;
25  import org.apache.myfaces.tobago.internal.util.JsonWriterUtils;
26  import org.apache.myfaces.tobago.internal.util.StringUtils;
27  import org.apache.myfaces.tobago.internal.util.WriterUtils;
28  import org.apache.myfaces.tobago.renderkit.css.Style;
29  import org.apache.myfaces.tobago.renderkit.html.HtmlAttributes;
30  import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
31  
32  import javax.faces.component.UIComponent;
33  import javax.faces.context.ResponseWriter;
34  import java.io.IOException;
35  import java.io.Writer;
36  import java.util.Arrays;
37  import java.util.Map;
38  
39  public class HtmlResponseWriter extends TobagoResponseWriterBase {
40  
41    private static final String HTML_DOCTYPE =
42        "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">";
43  
44    private final WriterUtils helper;
45    private FastStringWriter javascriptWriter;
46    private boolean javascriptMode;
47  
48    public HtmlResponseWriter(
49        Writer writer, String contentType, String characterEncoding) {
50      super(writer, contentType, characterEncoding);
51      if ("application/json".equals(contentType)) {
52        this.helper = new JsonWriterUtils(writer, characterEncoding);
53      } else {
54        this.helper = new HtmlWriterUtils(writer, characterEncoding);
55      }
56      this.javascriptWriter = new FastStringWriter();
57    }
58  
59    /**
60     * @deprecated Should not be used, because it conflicts with CSP.
61     */
62    @Deprecated
63    @Override
64    public void endJavascript() throws IOException {
65      javascriptMode = false;
66    }
67  
68    /**
69     * @deprecated Should not be used, because it conflicts with CSP.
70     */
71    @Deprecated
72    @Override
73    public void startJavascript() throws IOException {
74      javascriptMode = true;
75    }
76  
77    @Override
78    public void write(String string) throws IOException {
79      if (javascriptMode) {
80        writeJavascript(string);
81      } else {
82        writeInternal(getWriter(), string);
83      }
84    }
85  
86    /**
87     * @deprecated Should not be used, because it conflicts with CSP.
88     */
89    @Deprecated
90    @Override
91    public void writeJavascript(String script) throws IOException {
92      writeInternal(javascriptWriter, script);
93    }
94  
95    public String getJavascript() {
96      return javascriptWriter.toString();
97    }
98  
99    public final WriterUtils getHelper() {
100     return helper;
101   }
102 
103   public void writeText(final Object text, final String property)
104       throws IOException {
105     closeOpenTag();
106     final String value = findValue(text, property);
107     helper.writeText(value);
108   }
109 
110   public void writeText(final char[] text, final int offset, final int length)
111       throws IOException {
112     closeOpenTag();
113     helper.writeText(text, offset, length);
114   }
115 
116   @Override
117   public void write(final char[] cbuf, final int off, final int len) throws IOException {
118     // Related to http://java.net/jira/browse/JAVASERVERFACES_SPEC_PUBLIC-696
119     if (Arrays.equals(cbuf, XML_VERSION_1_0_ENCODING_UTF_8_CHARS)) {
120       // drop
121     } else {
122       super.write(cbuf, off, len);
123     }
124   }
125 
126   @Override
127   protected final void closeEmptyTag() throws IOException {
128     getWriter().write("\n>");
129   }
130 
131   @Override
132   protected void writerAttributeValue(String value, boolean escape) throws IOException {
133     if (escape) {
134       helper.writeAttributeValue(value);
135     } else {
136       getWriter().write(value);
137     }
138   }
139 
140   public ResponseWriter cloneWithWriter(final Writer originalWriter) {
141     return new HtmlResponseWriter(
142         originalWriter, getContentType(), getCharacterEncoding());
143   }
144 
145   /**
146    * @deprecated
147    */
148   @Deprecated
149   public static Style ensureHtmlStyleMap(UIComponent component, Style styles) {
150     if (styles == null) {
151       styles = new Style();
152       ((Map<String, Object>) component.getAttributes()).put(Attributes.STYLE, styles);
153     }
154     return styles;
155   }
156 
157   @Override
158   public void startDocument() throws IOException {
159     getWriter().write(HTML_DOCTYPE);
160     getWriter().write('\n');
161     startElement(HtmlElements.HTML, null);
162   }
163 
164   @Override
165   public void endElement(String name) throws IOException {
166     if (name == HtmlElements.BODY) {
167       String javascript = getJavascript();
168       if (StringUtils.isNotEmpty(javascript)) {
169         startElement(HtmlElements.SCRIPT, null);
170         writeAttribute(HtmlAttributes.TYPE, "text/javascript", false);
171         write(getJavascript());
172         super.endElement(HtmlElements.SCRIPT);
173       }
174     }
175     super.endElement(name);
176   }
177 
178   @Override
179   public void endDocument() throws IOException {
180 
181     endElement(HtmlElements.HTML);
182   }
183 }