Coverage Report - org.seasar.teeda.core.context.html.HtmlResponseWriter
 
Classes in this File Line Coverage Branch Coverage Complexity
HtmlResponseWriter
93%
157/169
81%
35/43
1.966
 
 1  
 /*
 2  
  * Copyright 2004-2011 the Seasar Foundation and the Others.
 3  
  *
 4  
  * Licensed under the Apache License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  *     http://www.apache.org/licenses/LICENSE-2.0
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 13  
  * either express or implied. See the License for the specific language
 14  
  * governing permissions and limitations under the License.
 15  
  */
 16  
 package org.seasar.teeda.core.context.html;
 17  
 
 18  
 import java.io.IOException;
 19  
 import java.io.Writer;
 20  
 import java.net.URLEncoder;
 21  
 
 22  
 import javax.faces.component.UIComponent;
 23  
 import javax.faces.context.ResponseWriter;
 24  
 
 25  
 import org.seasar.framework.util.ArrayUtil;
 26  
 import org.seasar.framework.util.AssertionUtil;
 27  
 import org.seasar.framework.util.StringUtil;
 28  
 import org.seasar.teeda.core.JsfConstants;
 29  
 import org.seasar.teeda.core.util.EmptyElementUtil;
 30  
 import org.seasar.teeda.core.util.HTMLEncodeUtil;
 31  
 
 32  
 /**
 33  
  * @author manhole
 34  
  * @author shot
 35  
  * @author yone
 36  
  */
 37  
 // TODO handle "javascript: xxxx" attribute (really necessary?)
 38  429
 public class HtmlResponseWriter extends ResponseWriter {
 39  
 
 40  1
     private static final char[] reserved = { ';', '/', '?', ':', '@', '&', '=',
 41  
             '+', '$', ',' };
 42  
 
 43  
     private static final char[] unescape;
 44  
 
 45  
     static {
 46  1
         unescape = new char[reserved.length + 1];
 47  1
         System.arraycopy(reserved, 0, unescape, 0, reserved.length);
 48  1
         unescape[unescape.length - 1] = '#';
 49  1
     }
 50  
 
 51  
     private Writer writer;
 52  
 
 53  
     private String contentType;
 54  
 
 55  
     private String characterEncoding;
 56  
 
 57  
     private boolean startTagOpening;
 58  
 
 59  429
     private boolean shouldEscape = DEFAULT_ESCAPE;
 60  
 
 61  
     private static final boolean DEFAULT_ESCAPE = true;
 62  
 
 63  
     public void startElement(final String name,
 64  
             final UIComponent componentForElement) throws IOException {
 65  870
         AssertionUtil.assertNotNull("name", name);
 66  869
         final Writer writer = getWriter();
 67  869
         closeStartTagIfOpening(writer);
 68  869
         writer.write("<");
 69  869
         writer.write(name);
 70  
         // TODO need "style" element ?
 71  869
         if ("script".equalsIgnoreCase(name)) {
 72  7
             shouldEscape = false;
 73  
         } else {
 74  862
             shouldEscape = true;
 75  
         }
 76  869
         startTagOpening = true;
 77  869
     }
 78  
 
 79  
     protected void closeStartTagIfOpening(final Writer writer)
 80  
             throws IOException {
 81  1306
         if (startTagOpening) {
 82  691
             writer.write(">");
 83  691
             startTagOpening = false;
 84  
         }
 85  1306
     }
 86  
 
 87  
     public void endElement(final String name) throws IOException {
 88  806
         AssertionUtil.assertNotNull("name", name);
 89  805
         final Writer writer = getWriter();
 90  805
         if (startTagOpening) {
 91  156
             if (EmptyElementUtil.isEmptyElement(name)) {
 92  118
                 writer.write(" />");
 93  
             } else {
 94  38
                 writer.write(">");
 95  38
                 writer.write("</" + name + ">");
 96  
             }
 97  156
             startTagOpening = false;
 98  
         } else {
 99  649
             writer.write("</" + name + ">");
 100  
         }
 101  805
         shouldEscape = DEFAULT_ESCAPE;
 102  805
     }
 103  
 
 104  
     public void writeAttribute(final String name, final Object value,
 105  
             final String property) throws IOException {
 106  1436
         AssertionUtil.assertNotNull("name", name);
 107  1435
         if (!startTagOpening) {
 108  1
             throw new IllegalStateException(
 109  
                     "there is no currently open element");
 110  
         }
 111  1434
         final String strValue = (value == null) ? "" : value.toString();
 112  1434
         final Writer writer = getWriter();
 113  1434
         writer.write(" ");
 114  1434
         writer.write(name);
 115  1434
         writer.write("=\"");
 116  1434
         writer.write(escapeAttribute(strValue));
 117  1434
         writer.write("\"");
 118  1434
     }
 119  
 
 120  
     public void writeURIAttribute(final String name, final Object value,
 121  
             final String property) throws IOException {
 122  42
         AssertionUtil.assertNotNull("name", name);
 123  41
         if (!startTagOpening) {
 124  1
             throw new IllegalStateException(
 125  
                     "there is no currently open element");
 126  
         }
 127  40
         final Writer writer = getWriter();
 128  40
         final String strValue = value.toString();
 129  
 
 130  40
         writer.write(" ");
 131  40
         writer.write(name);
 132  40
         writer.write("=\"");
 133  40
         if (StringUtil.startsWithIgnoreCase(strValue, "javascript:")) {
 134  1
             writer.write(escapeAttribute(strValue));
 135  
         } else {
 136  39
             writer.write(encodeURIAttribute(strValue));
 137  
         }
 138  40
         writer.write("\"");
 139  40
     }
 140  
 
 141  
     public void writeComment(final Object comment) throws IOException {
 142  3
         AssertionUtil.assertNotNull("comment", comment);
 143  2
         final Writer writer = getWriter();
 144  2
         closeStartTagIfOpening(writer);
 145  2
         writer.write("<!--");
 146  2
         writer.write(comment.toString());
 147  2
         writer.write("-->");
 148  2
     }
 149  
 
 150  
     public void writeText(final Object text, final String property)
 151  
             throws IOException {
 152  320
         AssertionUtil.assertNotNull("text", text);
 153  319
         final Writer writer = getWriter();
 154  319
         closeStartTagIfOpening(writer);
 155  319
         String str = text.toString();
 156  319
         if (shouldEscape) {
 157  317
             str = htmlSpecialChars(str);
 158  
         }
 159  319
         writer.write(str);
 160  319
     }
 161  
 
 162  
     public void writeText(final char text[], final int off, final int len)
 163  
             throws IOException {
 164  4
         AssertionUtil.assertNotNull("text", text);
 165  3
         writeText(new String(text, off, len), null);
 166  3
     }
 167  
 
 168  
     protected String htmlSpecialChars(final String s) {
 169  317
         return HTMLEncodeUtil.encode(s, true, true);
 170  
     }
 171  
 
 172  
     protected String escapeAttribute(final String s) {
 173  1435
         return HTMLEncodeUtil.encode(s, false, false);
 174  
     }
 175  
 
 176  
     public ResponseWriter cloneWithWriter(final Writer writer) {
 177  7
         AssertionUtil.assertNotNull("writer", writer);
 178  6
         final HtmlResponseWriter clone = new HtmlResponseWriter();
 179  6
         clone.setWriter(writer);
 180  6
         clone.setContentType(getContentType());
 181  6
         clone.setCharacterEncoding(getCharacterEncoding());
 182  6
         return clone;
 183  
     }
 184  
 
 185  
     public void write(final char[] cbuf, final int off, final int len)
 186  
             throws IOException {
 187  3
         final Writer writer = getWriter();
 188  3
         closeStartTagIfOpening(writer);
 189  3
         writer.write(cbuf, off, len);
 190  3
     }
 191  
 
 192  
     public void write(final char[] cbuf) throws IOException {
 193  2
         final Writer writer = getWriter();
 194  2
         closeStartTagIfOpening(writer);
 195  2
         writer.write(cbuf);
 196  2
     }
 197  
 
 198  
     public void write(final int c) throws IOException {
 199  2
         final Writer writer = getWriter();
 200  2
         closeStartTagIfOpening(writer);
 201  2
         writer.write(c);
 202  2
     }
 203  
 
 204  
     public void write(final String str) throws IOException {
 205  94
         final Writer writer = getWriter();
 206  94
         closeStartTagIfOpening(writer);
 207  94
         writer.write(str);
 208  94
     }
 209  
 
 210  
     public void write(final String str, final int off, final int len)
 211  
             throws IOException {
 212  2
         final Writer writer = getWriter();
 213  2
         closeStartTagIfOpening(writer);
 214  2
         writer.write(str, off, len);
 215  2
     }
 216  
 
 217  
     public void flush() throws IOException {
 218  7
         final Writer writer = getWriter();
 219  7
         closeStartTagIfOpening(writer);
 220  7
     }
 221  
 
 222  
     public void close() throws IOException {
 223  2
         final Writer writer = getWriter();
 224  2
         closeStartTagIfOpening(writer);
 225  2
         writer.close();
 226  2
     }
 227  
 
 228  
     public void startDocument() throws IOException {
 229  6
     }
 230  
 
 231  
     public void endDocument() throws IOException {
 232  4
         closeStartTagIfOpening(getWriter());
 233  4
     }
 234  
 
 235  
     public String getContentType() {
 236  11
         return contentType;
 237  
     }
 238  
 
 239  
     public void setContentType(final String contentType) {
 240  10
         this.contentType = contentType;
 241  10
     }
 242  
 
 243  
     public String getCharacterEncoding() {
 244  110
         if (characterEncoding == null) {
 245  44
             characterEncoding = JsfConstants.DEFAULT_ENCODING;
 246  
         }
 247  110
         return characterEncoding;
 248  
     }
 249  
 
 250  
     public void setCharacterEncoding(final String characterEncoding) {
 251  10
         this.characterEncoding = characterEncoding;
 252  10
     }
 253  
 
 254  
     public Writer getWriter() {
 255  3943
         return writer;
 256  
     }
 257  
 
 258  
     public void setWriter(final Writer writer) {
 259  414
         this.writer = writer;
 260  414
     }
 261  
 
 262  
     protected String encodeURIAttribute(final String url) throws IOException {
 263  51
         final char[] chars = url.toCharArray();
 264  51
         final StringBuffer sb = new StringBuffer(url.length() + 100);
 265  51
         final int length = chars.length;
 266  51
         final String encoding = getCharacterEncoding();
 267  320
         for (int i = 0; i < length; i++) {
 268  289
             final char c = chars[i];
 269  289
             if (ArrayUtil.contains(unescape, c)) {
 270  54
                 sb.append(c);
 271  54
                 if ('?' == c) {
 272  20
                     if (i < length) {
 273  20
                         sb.append(encodeQueryString(url.substring(i + 1)));
 274  
                     }
 275  
                     break;
 276  
                 }
 277  
             } else {
 278  235
                 sb.append(URLEncoder.encode(String.valueOf(c), encoding));
 279  
             }
 280  
         }
 281  51
         return new String(sb);
 282  
     }
 283  
 
 284  
     public String encodeQueryString(final String s) throws IOException {
 285  20
         final char[] chars = s.toCharArray();
 286  20
         final StringBuffer sb = new StringBuffer(s.length() + 32);
 287  20
         final String encoding = getCharacterEncoding();
 288  223
         for (int i = 0; i < chars.length; i++) {
 289  203
             final char c = chars[i];
 290  203
             switch (c) {
 291  
             case ' ': // 32
 292  1
                 sb.append("%20");
 293  1
                 break;
 294  
             case '!': // 33
 295  0
                 sb.append("!");
 296  0
                 break;
 297  
             case '#': // 35
 298  2
                 sb.append("#");
 299  2
                 break;
 300  
             case '%': // 37
 301  5
                 sb.append("%");
 302  5
                 break;
 303  
             case '&': // 38
 304  
                 //sb.append("&");
 305  7
                 sb.append("&amp;");
 306  7
                 break;
 307  
             case '\'': // 39
 308  0
                 sb.append("'");
 309  0
                 break;
 310  
             case '(': // 40
 311  0
                 sb.append("(");
 312  0
                 break;
 313  
             case ')': // 41
 314  0
                 sb.append(")");
 315  0
                 break;
 316  
             case '+': // 43
 317  0
                 sb.append("+");
 318  0
                 break;
 319  
             case '/': // 47
 320  2
                 sb.append("/");
 321  2
                 break;
 322  
             case '=': // 61
 323  28
                 sb.append("=");
 324  28
                 break;
 325  
             case '~': // 126
 326  0
                 sb.append("~");
 327  0
                 break;
 328  
             default:
 329  158
                 sb.append(URLEncoder.encode(String.valueOf(c), encoding));
 330  
                 break;
 331  
             }
 332  
         }
 333  20
         return new String(sb);
 334  
     }
 335  
 
 336  
     public String toString() {
 337  1
         return writer.toString();
 338  
     }
 339  
 
 340  
 }