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.webapp;
21  
22  import org.apache.myfaces.tobago.ajax.AjaxUtils;
23  import org.apache.myfaces.tobago.internal.util.StringUtils;
24  import org.apache.myfaces.tobago.renderkit.css.Classes;
25  import org.apache.myfaces.tobago.renderkit.css.CssItem;
26  import org.apache.myfaces.tobago.renderkit.css.FontAwesomeIconEncoder;
27  import org.apache.myfaces.tobago.renderkit.css.IconEncoder;
28  import org.apache.myfaces.tobago.renderkit.css.Icons;
29  import org.apache.myfaces.tobago.renderkit.css.Style;
30  import org.apache.myfaces.tobago.renderkit.html.DataAttributes;
31  import org.apache.myfaces.tobago.renderkit.html.HtmlAttributes;
32  import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
33  import org.apache.myfaces.tobago.renderkit.html.HtmlTypes;
34  import org.apache.myfaces.tobago.renderkit.html.MarkupLanguageAttributes;
35  
36  import javax.faces.component.UIComponent;
37  import javax.faces.context.FacesContext;
38  import javax.faces.context.ResponseWriter;
39  import java.io.IOException;
40  import java.io.Writer;
41  
42  /**
43   * <p>
44   * This provides an alternative ResponseWriter interfaces, which allows optimizations.
45   * E. g. some attributes needed to to be escaped.
46   * </p>
47   */
48  public abstract class TobagoResponseWriter extends ResponseWriter {
49  
50    private static final CssItem[] NO_CSS_ITEMS = new CssItem[0];
51  
52    private IconEncoder iconEncoder = new FontAwesomeIconEncoder();
53  
54    // same as in ResponseWriter
55  
56    /**
57     * @deprecated Should not directly called via this interface. There is be a special method which might be better.
58     */
59    @Deprecated
60    @Override
61    public abstract void startElement(String name, UIComponent component) throws IOException;
62  
63    public abstract void startElement(HtmlElements name) throws IOException;
64  
65    /**
66     * @deprecated Should not directly called via this interface. There is be a special method which might be better.
67     */
68    @Deprecated
69    @Override
70    public abstract void endElement(String name) throws IOException;
71      
72    public abstract void endElement(HtmlElements name) throws IOException;
73  
74    @Override
75    public abstract void write(String string) throws IOException;
76  
77    @Override
78    public abstract void writeComment(Object comment) throws IOException;
79  
80    @Override
81    public abstract ResponseWriter cloneWithWriter(Writer writer);
82  
83    /**
84     * @deprecated Should not directly called via this interface. There is be a special method which might be better.
85     */
86    @Override
87    @Deprecated
88    public abstract void writeAttribute(String name, Object value, final String property) throws IOException;
89  
90    /**
91     * @deprecated Should not directly called via this interface. There is be a special method which might be better.
92     */
93    @Override
94    @Deprecated
95    public abstract void writeURIAttribute(String name, Object value, final String property) throws IOException;
96  
97    /**
98     * @deprecated Should not directly called via this interface. There is be a special method which might be better.
99     */
100   @Override
101   @Deprecated
102   public abstract void writeText(Object text, String property) throws IOException;
103 
104   @Override
105   public abstract void flush() throws IOException;
106 
107   // others (not from ResponseWriter)
108 
109   /**
110    * Writes a string attribute. The renderer may set escape=false to switch of escaping of the string,
111    * if it is not necessary.
112    */
113   public abstract void writeAttribute(MarkupLanguageAttributes name, String string, boolean escape) throws IOException;
114 
115   public abstract void writeAttribute(MarkupLanguageAttributes name, HtmlTypes type) throws IOException;
116 
117   /**
118    * Writes a string attribute URL encoded.
119    */
120   public abstract void writeURIAttribute(MarkupLanguageAttributes name, String string) throws IOException;
121 
122   /**
123    * Writes a boolean attribute. The value will not escaped.
124    */
125   public void writeAttribute(final MarkupLanguageAttributes name, final boolean on) throws IOException {
126     if (on) {
127       writeAttribute(name, name.getValue(), false);
128     }
129   }
130 
131   /**
132    * Writes a {@link Integer} attribute, if the value is not {@code null}. The value will not be escaped.
133    */
134   public void writeAttribute(final MarkupLanguageAttributes name, final Integer number) throws IOException {
135     if (number != null) {
136       writeAttribute(name, Integer.toString(number), false);
137     }
138   }
139 
140   /**
141    * Write the id attribute. The value will not escaped.
142    */
143   public void writeIdAttribute(final String id) throws IOException {
144     writeAttribute(HtmlAttributes.ID, id, false);
145   }
146 
147   /**
148    * Write the name attribute. The value will not escaped.
149    */
150   public void writeNameAttribute(final String name) throws IOException {
151     writeAttribute(HtmlAttributes.NAME, name, false);
152   }
153 
154   /**
155    * Write the class attribute. The value will not escaped.
156    * @param classes The abstract representation of the css class string, normally created by the renderer.
157    */
158   public void writeClassAttribute(final Classes classes) throws IOException {
159     final String stringValue = classes.getStringValue();
160     if (StringUtils.isNotBlank(stringValue)) {
161       writeAttribute(HtmlAttributes.CLASS, stringValue, false);
162     }
163   }
164 
165   public void writeClassAttribute(final CssItem first) throws IOException {
166     writeClassAttribute(first, null, NO_CSS_ITEMS);
167   }
168 
169   public void writeClassAttribute(final CssItem first, final CssItem second) throws IOException {
170     writeClassAttribute(first, second, NO_CSS_ITEMS);
171   }
172 
173   public void writeClassAttribute(final CssItem first, final CssItem second, final CssItem... others)
174       throws IOException {
175     StringBuilder builder = new StringBuilder();
176     if (first != null) {
177       builder.append(first.getName());
178       builder.append(' ');
179     }
180     if (second != null) {
181       builder.append(second.getName());
182       builder.append(' ');
183     }
184     for (CssItem other : others) {
185       if (other != null) {
186         builder.append(other.getName());
187         builder.append(' ');
188       }
189     }
190     if (builder.length() > 0) {
191       writeAttribute(HtmlAttributes.CLASS, builder.deleteCharAt(builder.length() - 1).toString(), false);
192     }
193   }
194 
195   public void writeClassAttribute(final Classes classes, final CssItem... others) throws IOException {
196     StringBuilder builder = new StringBuilder(classes.getStringValue());
197     for (CssItem other : others) {
198       if (other != null) {
199         builder.append(' ');
200         builder.append(other.getName());
201       }
202     }
203     writeAttribute(HtmlAttributes.CLASS, builder.toString(), false);
204   }
205 
206   /**
207    * Write the style attribute. The value may be escaped (depending of the content).
208    */
209   public void writeStyleAttribute(final Style style) throws IOException {
210     if (style != null) {
211       final String json = style.encodeJson();
212       if (json.length() > 2) { // empty "{}" needs not to be written
213         final FacesContext facesContext = FacesContext.getCurrentInstance();
214         writeAttribute(
215             DataAttributes.STYLE, json, style.needsToBeEscaped() || AjaxUtils.isAjaxRequest(facesContext));
216         // in case of AJAX we need to escape the " as long we use
217         // org.apache.myfaces.tobago.internal.webapp.JsonResponseWriter
218       }
219     }
220   }
221 
222   /**
223    * Write the style attribute. The value will not escaped.
224    * @deprecated since 1.5.0, use writeStyleAttribute(Style) instead.
225    */
226   @Deprecated
227   public void writeStyleAttribute(final String style) throws IOException {
228     writeAttribute(HtmlAttributes.STYLE, style, false);
229   }
230 
231   /**
232    * Writes an supported icon.
233    */
234   public void writeIcon(final Icons icon, final CssItem... cssItems) throws IOException {
235     writeIcon(icon, null, cssItems);
236   }
237 
238   /**
239    * Writes an supported icon with explicit style information.
240    */
241   public void writeIcon(final Icons icon, final Style style, final CssItem... cssItems) throws IOException {
242     iconEncoder.encode(this, icon, style, cssItems);
243   }
244 
245   /**
246    * @deprecated Should not be used, because it conflicts with CSP.
247    */
248   @Deprecated
249   public void writeJavascript(final String script) throws IOException {
250     startJavascript();
251     write(script);
252     endJavascript();
253   }
254 
255   /**
256    * @deprecated Should not be used, because it conflicts with CSP.
257    */
258   @Deprecated
259   public void endJavascript() throws IOException {
260 //    write("\n// -->\n"); // todo: for XHMTL we may need
261     endElement(HtmlElements.SCRIPT);
262   }
263 
264   /**
265    * @deprecated Should not be used, because it conflicts with CSP.
266    */
267   @Deprecated
268   public void startJavascript() throws IOException {
269     startElement(HtmlElements.SCRIPT);
270     writeAttribute(HtmlAttributes.TYPE, "text/javascript", false);
271   }
272 
273   /**
274    * Write text content. The text will be escaped.
275    */
276   public void writeText(final String text) throws IOException {
277     writeText(text, null);
278   }
279 
280   public String getContentTypeWithCharSet() {
281     String contentType = getContentType();
282     if (contentType == null) {
283       contentType = "text/html";
284     }
285     String characterEncoding = getCharacterEncoding();
286     if (characterEncoding == null) {
287       characterEncoding = "UTF-8";
288     }
289 
290     return contentType + "; charset=" + characterEncoding;
291   }
292 
293   @Override
294   public void startCDATA() throws IOException {
295     write("<![CDATA[");
296   }
297 
298   @Override
299   public void endCDATA() throws IOException {
300     write("]]>");
301   }
302 
303 //  protected abstract void writeNewline() throws IOException;
304 }