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.StringUtils;
23  import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
24  import org.apache.myfaces.tobago.renderkit.html.HtmlTypes;
25  import org.apache.myfaces.tobago.renderkit.html.MarkupLanguageAttributes;
26  import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
27  import org.slf4j.Logger;
28  import org.slf4j.LoggerFactory;
29  
30  import javax.faces.component.UIComponent;
31  import javax.faces.context.ResponseWriter;
32  import java.io.IOException;
33  import java.io.Writer;
34  import java.util.EmptyStackException;
35  import java.util.HashSet;
36  import java.util.Set;
37  import java.util.Stack;
38  
39  public class DebugResponseWriterWrapper extends TobagoResponseWriter {
40  
41    private Stack<Object> stack = new Stack<>();
42    private Set<MarkupLanguageAttributes> usedAttributes = new HashSet<>();
43  
44    private static final Logger LOG = LoggerFactory.getLogger(DebugResponseWriterWrapper.class);
45  
46    private final TobagoResponseWriter responseWriter;
47  
48    public DebugResponseWriterWrapper(final TobagoResponseWriter responseWriter) {
49      this.responseWriter = responseWriter;
50    }
51  
52    @Override
53    public void write(final String string) throws IOException {
54      responseWriter.write(string);
55    }
56  
57    @Override
58    public void writeComment(final Object comment) throws IOException {
59      String commentStr = comment.toString();
60      if (commentStr.indexOf("--") > 0) {
61        LOG.error("Comment must not contain the sequence '--', comment = '" + comment + "'.",
62            new IllegalArgumentException());
63  
64        commentStr = StringUtils.replace(commentStr, "--", "++");
65      }
66      responseWriter.writeComment(commentStr);
67    }
68  
69    @Override
70    public ResponseWriter cloneWithWriter(final Writer writer) {
71      return new DebugResponseWriterWrapper((TobagoResponseWriter) responseWriter.cloneWithWriter(writer));
72    }
73  
74    @Override
75    @Deprecated
76    public void writeAttribute(final String name, final Object value, final String property) throws IOException {
77      responseWriter.writeAttribute(name, value, property);
78    }
79  
80    @Override
81    @Deprecated
82    public void writeText(final Object text, final String property) throws IOException {
83      responseWriter.writeText(text, property);
84    }
85  
86    @Override
87    public void flush() throws IOException {
88      responseWriter.flush();
89    }
90  
91    @Override
92    public void writeAttribute(final MarkupLanguageAttributes name, final String value, final boolean escape)
93        throws IOException {
94      responseWriter.writeAttribute(name, value, escape);
95      if (usedAttributes.contains(name)) {
96        LOG.error("Duplicate attribute '" + name + "' in element <" + stack.peek() + "> with value '" + value + "'!",
97            new IllegalStateException());
98      } else {
99        usedAttributes.add(name);
100     }
101   }
102 
103   @Override
104   public void writeAttribute(final MarkupLanguageAttributes name, final HtmlTypes types) throws IOException {
105     responseWriter.writeAttribute(name, types);
106     if (usedAttributes.contains(name)) {
107       LOG.error("Duplicate attribute '" + name + "' in element <" + stack.peek() + "> with value '" + types + "'!",
108           new IllegalStateException());
109       usedAttributes.add(name);
110     }
111   }
112 
113   @Override
114   public void writeURIAttribute(final MarkupLanguageAttributes name, final String string) throws IOException {
115     responseWriter.writeURIAttribute(name, string);
116     if (usedAttributes.contains(name)) {
117       LOG.error("Duplicate attribute '" + name + "' in element <" + stack.peek() + "> with value '" + string + "'!",
118           new IllegalStateException());
119     } else {
120       usedAttributes.add(name);
121     }
122   }
123 
124   @Override
125   public String getContentType() {
126     return responseWriter.getContentType();
127   }
128 
129   @Override
130   public String getCharacterEncoding() {
131     return responseWriter.getCharacterEncoding();
132   }
133 
134   @Override
135   public void startDocument() throws IOException {
136     responseWriter.startDocument();
137   }
138 
139   @Override
140   public void endDocument() throws IOException {
141     responseWriter.endDocument();
142   }
143 
144   @Override
145   public void writeURIAttribute(final String name, final Object value, final String property) throws IOException {
146     responseWriter.writeURIAttribute(name, value, property);
147   }
148 
149   @Override
150   public void writeText(final char[] text, final int off, final int len) throws IOException {
151     responseWriter.writeText(text, off, len);
152   }
153 
154   @Override
155   public void write(final char[] chars, final int i, final int i1) throws IOException {
156     responseWriter.write(chars, i, i1);
157   }
158 
159   @Override
160   public void close() throws IOException {
161     responseWriter.close();
162   }
163 
164   @Override
165   public void startElement(final String name, final UIComponent currentComponent) throws IOException {
166     if (LOG.isDebugEnabled()) {
167       LOG.debug("start element: '" + name + "'");
168     }
169     stack.push(name);
170     responseWriter.startElement(name, currentComponent);
171 
172     usedAttributes.clear();
173   }
174 
175   @Override
176   public void startElement(final HtmlElements name) throws IOException {
177     if (LOG.isDebugEnabled()) {
178       LOG.debug("start element: '" + name + "'");
179     }
180     stack.push(name);
181     responseWriter.startElement(name);
182 
183     usedAttributes.clear();
184   }
185 
186   @Override
187   public void endElement(final String name) throws IOException {
188     if (LOG.isDebugEnabled()) {
189       LOG.debug("end element: '" + name + "'");
190     }
191     Object top;
192     try {
193       top = stack.pop();
194     } catch (final EmptyStackException e) {
195       LOG.error("Failed to close element \"" + name + "\"!", e);
196       top = "*** failure ***";
197     }
198 
199     if (!top.equals(name)) {
200       LOG.error("Element end with name='" + name + "' doesn't match with top element on the stack='" + top + "'.",
201           new IllegalArgumentException());
202     }
203     responseWriter.endElement(name);
204   }
205 
206   @Override
207   public void endElement(final HtmlElements name) throws IOException {
208     if (LOG.isDebugEnabled()) {
209       LOG.debug("end element: '" + name + "'");
210     }
211     Object top;
212     try {
213       top = stack.pop();
214     } catch (final EmptyStackException e) {
215       LOG.error("Failed to close element \"" + name + "\"!", e);
216       top = "*** failure ***";
217     }
218 
219     if (!top.equals(name)) {
220       LOG.error("Element end with name='" + name + "' doesn't match with top element on the stack='" + top + "'.",
221           new IllegalArgumentException());
222     }
223     responseWriter.endElement(name);
224   }
225 }