Coverage Report - org.apache.myfaces.shared.renderkit.html.HtmlResponseWriterImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
HtmlResponseWriterImpl
46%
184/397
36%
96/266
4.191
 
 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  
 package org.apache.myfaces.shared.renderkit.html;
 20  
 
 21  
 import java.io.IOException;
 22  
 import java.io.Writer;
 23  
 import java.nio.charset.Charset;
 24  
 import java.util.ArrayList;
 25  
 import java.util.List;
 26  
 import java.util.Map;
 27  
 import java.util.logging.Level;
 28  
 import java.util.logging.Logger;
 29  
 import javax.el.ValueExpression;
 30  
 
 31  
 import javax.faces.FacesException;
 32  
 import javax.faces.component.UIComponent;
 33  
 import javax.faces.context.FacesContext;
 34  
 import javax.faces.context.ResponseWriter;
 35  
 import javax.faces.render.Renderer;
 36  
 
 37  
 import org.apache.myfaces.shared.config.MyfacesConfig;
 38  
 import org.apache.myfaces.shared.renderkit.ContentTypeUtils;
 39  
 import org.apache.myfaces.shared.renderkit.RendererUtils;
 40  
 import org.apache.myfaces.shared.renderkit.html.util.UnicodeEncoder;
 41  
 import org.apache.myfaces.shared.util.CommentUtils;
 42  
 import org.apache.myfaces.shared.util.StreamCharBuffer;
 43  
 
 44  
 public class HtmlResponseWriterImpl
 45  
         extends ResponseWriter
 46  
 {
 47  
     //private static final Log log = LogFactory.getLog(HtmlResponseWriterImpl.class);
 48  1
     private static final Logger log = Logger.getLogger(HtmlResponseWriterImpl.class.getName());
 49  
 
 50  
     private static final String DEFAULT_CONTENT_TYPE = "text/html";
 51  
     private static final String DEFAULT_CHARACTER_ENCODING = "ISO-8859-1";
 52  
     private static final String UTF8 = "UTF-8";
 53  
 
 54  
     private static final String APPLICATION_XML_CONTENT_TYPE = "application/xml";
 55  
     private static final String TEXT_XML_CONTENT_TYPE = "text/xml";
 56  
     
 57  
     //private boolean _writeDummyForm = false;
 58  
     //private Set _dummyFormParams = null;
 59  
 
 60  
     /**
 61  
      * The writer used as output, or in other words, the one passed on the constructor
 62  
      */
 63  
     private Writer _outputWriter;
 64  
     
 65  
     /**
 66  
      * The writer we are using to store data.
 67  
      */
 68  
     private Writer _currentWriter;
 69  
     
 70  
     /**
 71  
      * The writer used to buffer script and style content
 72  
      */
 73  
     private StreamCharBuffer _buffer;
 74  
     
 75  
     private String _contentType;
 76  
     
 77  
     private String _writerContentTypeMode;
 78  
     
 79  
     /**
 80  
      * This var prevents check if the contentType is for xhtml multiple times.
 81  
      */
 82  
     private boolean _isXhtmlContentType;
 83  
     
 84  
     /**
 85  
      * Indicate the current response writer should not close automatically html elements
 86  
      * and let the writer close them.
 87  
      */
 88  
     private boolean _useStraightXml;
 89  
     
 90  
     private String _characterEncoding;
 91  
     private boolean _wrapScriptContentWithXmlCommentTag;
 92  
     private boolean _isUTF8;
 93  
     
 94  
     private String _startElementName;
 95  23
     private boolean _isInsideScript = false;
 96  23
     private boolean _isStyle = false;
 97  
     private Boolean _isTextArea;
 98  
     private UIComponent _startElementUIComponent;
 99  
     private boolean _startTagOpen;
 100  
     private Map<String, Object> _passThroughAttributesMap;
 101  
     private FacesContext _facesContext;
 102  
 
 103  
     private boolean _cdataOpen;
 104  
     
 105  
     private List<String> _startedChangedElements;
 106  
     private List<Integer> _startedElementsCount;
 107  
 
 108  
     private static final String CDATA_START = "<![CDATA[ \n";
 109  
     private static final String CDATA_START_NO_LINE_RETURN = "<![CDATA[";
 110  
     private static final String COMMENT_START = "<!--\n";
 111  
     private static final String CDATA_COMMENT_START = "//<![CDATA[ \n";
 112  
     private static final String CDATA_COMMENT_END = "\n//]]>";
 113  
     private static final String CDATA_END = "\n]]>";
 114  
     private static final String CDATA_END_NO_LINE_RETURN = "]]>";
 115  
     private static final String COMMENT_COMMENT_END = "\n//-->";
 116  
     private static final String COMMENT_END = "\n-->";
 117  
 
 118  1
     static private final String[][] EMPTY_ELEMENT_ARR = new String[256][];
 119  
 
 120  1
     static private final String[] A_NAMES = new String[]
 121  
     {
 122  
       "area",
 123  
     };
 124  
 
 125  1
     static private final String[] B_NAMES = new String[]
 126  
     {
 127  
       "br",
 128  
       "base",
 129  
       "basefont",
 130  
     };
 131  
 
 132  1
     static private final String[] C_NAMES = new String[]
 133  
     {
 134  
       "col",
 135  
     };
 136  
 
 137  1
     static private final String[] E_NAMES = new String[]
 138  
     {
 139  
       "embed",
 140  
     };
 141  
 
 142  1
     static private final String[] F_NAMES = new String[]
 143  
     {
 144  
       "frame",
 145  
     };
 146  
 
 147  1
     static private final String[] H_NAMES = new String[]
 148  
     {
 149  
       "hr",
 150  
     };
 151  
 
 152  1
     static private final String[] I_NAMES = new String[]
 153  
     {
 154  
       "img",
 155  
       "input",
 156  
       "isindex",
 157  
     };
 158  
 
 159  1
     static private final String[] L_NAMES = new String[]
 160  
     {
 161  
       "link",
 162  
     };
 163  
 
 164  1
     static private final String[] M_NAMES = new String[]
 165  
     {
 166  
       "meta",
 167  
     };
 168  
 
 169  1
     static private final String[] P_NAMES = new String[]
 170  
     {
 171  
       "param",
 172  
     };
 173  
 
 174  
     static
 175  
     {
 176  1
       EMPTY_ELEMENT_ARR['a'] = A_NAMES;
 177  1
       EMPTY_ELEMENT_ARR['A'] = A_NAMES;
 178  1
       EMPTY_ELEMENT_ARR['b'] = B_NAMES;
 179  1
       EMPTY_ELEMENT_ARR['B'] = B_NAMES;
 180  1
       EMPTY_ELEMENT_ARR['c'] = C_NAMES;
 181  1
       EMPTY_ELEMENT_ARR['C'] = C_NAMES;
 182  1
       EMPTY_ELEMENT_ARR['e'] = E_NAMES;
 183  1
       EMPTY_ELEMENT_ARR['E'] = E_NAMES;
 184  1
       EMPTY_ELEMENT_ARR['f'] = F_NAMES;
 185  1
       EMPTY_ELEMENT_ARR['F'] = F_NAMES;
 186  1
       EMPTY_ELEMENT_ARR['h'] = H_NAMES;
 187  1
       EMPTY_ELEMENT_ARR['H'] = H_NAMES;
 188  1
       EMPTY_ELEMENT_ARR['i'] = I_NAMES;
 189  1
       EMPTY_ELEMENT_ARR['I'] = I_NAMES;
 190  1
       EMPTY_ELEMENT_ARR['l'] = L_NAMES;
 191  1
       EMPTY_ELEMENT_ARR['L'] = L_NAMES;
 192  1
       EMPTY_ELEMENT_ARR['m'] = M_NAMES;
 193  1
       EMPTY_ELEMENT_ARR['M'] = M_NAMES;
 194  1
       EMPTY_ELEMENT_ARR['p'] = P_NAMES;
 195  1
       EMPTY_ELEMENT_ARR['P'] = P_NAMES;
 196  1
     }    
 197  
     
 198  
     public HtmlResponseWriterImpl(Writer writer, String contentType, String characterEncoding)
 199  
     {
 200  13
         this(writer,contentType,characterEncoding,true);
 201  13
     }
 202  
 
 203  
     public HtmlResponseWriterImpl(Writer writer, String contentType, String characterEncoding,
 204  
             boolean wrapScriptContentWithXmlCommentTag)
 205  
     {
 206  23
         this(writer,contentType, characterEncoding, wrapScriptContentWithXmlCommentTag, 
 207  
                 contentType != null && HtmlRendererUtils.isXHTMLContentType(contentType) ? 
 208  
                     ContentTypeUtils.XHTML_CONTENT_TYPE : ContentTypeUtils.HTML_CONTENT_TYPE);
 209  23
     }
 210  
     
 211  
     public HtmlResponseWriterImpl(Writer writer, String contentType, String characterEncoding,
 212  
              boolean wrapScriptContentWithXmlCommentTag, String writerContentTypeMode)
 213  
     throws FacesException
 214  23
     {
 215  23
         _outputWriter = writer;
 216  
         //The current writer to be used is the one used as output 
 217  23
         _currentWriter = _outputWriter;
 218  23
         _wrapScriptContentWithXmlCommentTag = wrapScriptContentWithXmlCommentTag;
 219  
         
 220  23
         _contentType = contentType;
 221  23
         if (_contentType == null)
 222  
         {
 223  0
             if (log.isLoggable(Level.FINE))
 224  
             {
 225  0
                 log.fine("No content type given, using default content type " + DEFAULT_CONTENT_TYPE);
 226  
             }
 227  0
             _contentType = DEFAULT_CONTENT_TYPE;
 228  
         }
 229  23
         _writerContentTypeMode = writerContentTypeMode;
 230  23
         _isXhtmlContentType = writerContentTypeMode.indexOf(ContentTypeUtils.XHTML_CONTENT_TYPE) != -1;
 231  
         
 232  23
         _useStraightXml = _isXhtmlContentType && (_contentType.indexOf(APPLICATION_XML_CONTENT_TYPE) != -1 ||
 233  
                           _contentType.indexOf(TEXT_XML_CONTENT_TYPE) != -1);
 234  
 
 235  23
         if (characterEncoding == null)
 236  
         {
 237  0
             if (log.isLoggable(Level.FINE))
 238  
             {
 239  0
                 log.fine("No character encoding given, using default character encoding " +
 240  
                         DEFAULT_CHARACTER_ENCODING);
 241  
             }
 242  0
             _characterEncoding = DEFAULT_CHARACTER_ENCODING;
 243  
         }
 244  
         else
 245  
         {
 246  
             // canonize to uppercase, that's the standard format
 247  23
             _characterEncoding = characterEncoding.toUpperCase();
 248  
             
 249  
             // Check if encoding is valid by javadoc of RenderKit.createResponseWriter()
 250  23
             if (!Charset.isSupported(_characterEncoding))
 251  
             {
 252  0
                 throw new IllegalArgumentException("Encoding "+_characterEncoding
 253  
                         +" not supported by HtmlResponseWriterImpl");
 254  
             }
 255  
         }
 256  23
         _isUTF8 = UTF8.equals(_characterEncoding);
 257  23
         _startedChangedElements = new ArrayList<String>();
 258  23
         _startedElementsCount = new ArrayList<Integer>();
 259  23
     }
 260  
 
 261  
     public static boolean supportsContentType(String contentType)
 262  
     {
 263  0
         String[] supportedContentTypes = HtmlRendererUtils.getSupportedContentTypes();
 264  
 
 265  0
         for (int i = 0; i < supportedContentTypes.length; i++)
 266  
         {
 267  0
             String supportedContentType = supportedContentTypes[i];
 268  
 
 269  0
             if(supportedContentType.indexOf(contentType)!=-1)
 270  
             {
 271  0
                 return true;
 272  
             }
 273  
         }
 274  0
         return false;
 275  
     }
 276  
 
 277  
     public String getContentType()
 278  
     {
 279  0
         return _contentType;
 280  
     }
 281  
     
 282  
     public String getWriterContentTypeMode()
 283  
     {
 284  0
         return _writerContentTypeMode;
 285  
     }
 286  
 
 287  
     public String getCharacterEncoding()
 288  
     {
 289  0
         return _characterEncoding;
 290  
     }
 291  
 
 292  
     public void flush() throws IOException
 293  
     {
 294  
         // API doc says we should not flush the underlying writer
 295  
         //_writer.flush();
 296  
         // but rather clear any values buffered by this ResponseWriter:
 297  0
         closeStartTagIfNecessary();
 298  0
     }
 299  
 
 300  
     public void startDocument()
 301  
     {
 302  
         // do nothing
 303  13
     }
 304  
 
 305  
     public void endDocument() throws IOException
 306  
     {
 307  13
         MyfacesConfig myfacesConfig = MyfacesConfig.getCurrentInstance(
 308  
             FacesContext.getCurrentInstance().getExternalContext());
 309  13
         if (myfacesConfig.isEarlyFlushEnabled())
 310  
         {
 311  0
             _currentWriter.flush();
 312  
         }
 313  13
         _facesContext = null;
 314  13
     }
 315  
 
 316  
     public void startElement(String name, UIComponent uiComponent) throws IOException
 317  
     {
 318  21
         if (name == null)
 319  
         {
 320  0
             throw new NullPointerException("elementName name must not be null");
 321  
         }
 322  
 
 323  21
         closeStartTagIfNecessary();
 324  21
         _currentWriter.write('<');
 325  
 
 326  21
         resetStartedElement();
 327  
 
 328  21
         _startElementName = name;
 329  21
         _startElementUIComponent = uiComponent;
 330  21
         _startTagOpen = true;
 331  21
         _passThroughAttributesMap = (_startElementUIComponent != null) ?
 332  
             _startElementUIComponent.getPassThroughAttributes(false) : null;
 333  
 
 334  21
         if (_passThroughAttributesMap != null)
 335  
         {
 336  0
             Object value = _passThroughAttributesMap.get(
 337  
                 Renderer.PASSTHROUGH_RENDERER_LOCALNAME_KEY);
 338  0
             if (value != null)
 339  
             {
 340  0
                 if (value instanceof ValueExpression)
 341  
                 {
 342  0
                     value = ((ValueExpression)value).getValue(
 343  
                         getFacesContext().getELContext());
 344  
                 }
 345  0
                 String elementName = value.toString().trim();
 346  
                 
 347  0
                 if (!name.equals(elementName))
 348  
                 {
 349  0
                     _startElementName = elementName;
 350  0
                     _startedChangedElements.add(elementName);
 351  0
                     _startedElementsCount.add(0);
 352  
                 }
 353  0
                 _currentWriter.write((String) elementName);
 354  0
             }
 355  
             else
 356  
             {
 357  0
                 _currentWriter.write(name);
 358  
             }
 359  0
         }
 360  
         else
 361  
         {
 362  21
             _currentWriter.write(name);
 363  
         }
 364  
 
 365  21
         if (!_startedElementsCount.isEmpty())
 366  
         {
 367  0
             int i = _startedElementsCount.size()-1;
 368  0
             _startedElementsCount.set(i, _startedElementsCount.get(i)+1);
 369  
         }
 370  
         
 371  
         // Each time we start a element, it is necessary to check <script> or <style>,
 372  
         // because we need to buffer all content to post process it later when it reach its end
 373  
         // according to the initialization properties used.
 374  21
         if(isScript(_startElementName))
 375  
         {
 376  
             // handle a <script> start
 377  7
             _isInsideScript = true;
 378  7
             _isStyle = false;
 379  7
             _isTextArea = Boolean.FALSE;
 380  
         }
 381  14
         else if (isStyle(_startElementName))
 382  
         {
 383  2
             _isInsideScript = false;
 384  2
             _isStyle = true;
 385  2
             _isTextArea = Boolean.FALSE;
 386  
         }
 387  21
     }
 388  
 
 389  
     @Override
 390  
     public void startCDATA() throws IOException
 391  
     {
 392  0
         if (!_cdataOpen)
 393  
         {
 394  0
             write(CDATA_START_NO_LINE_RETURN);
 395  0
             _cdataOpen = true;
 396  
         }
 397  0
     }
 398  
 
 399  
     @Override
 400  
     public void endCDATA() throws IOException
 401  
     {
 402  0
         if (_cdataOpen)
 403  
         {
 404  0
             write(CDATA_END_NO_LINE_RETURN);
 405  0
             _cdataOpen = false;
 406  
         }
 407  0
     }
 408  
 
 409  
     private void closeStartTagIfNecessary() throws IOException
 410  
     {
 411  34
         if (_startTagOpen)
 412  
         {
 413  21
             if (_passThroughAttributesMap != null)
 414  
             {
 415  0
                 for (Map.Entry<String, Object> entry : _passThroughAttributesMap.entrySet())
 416  
                 {
 417  0
                     String key = entry.getKey();
 418  0
                     Object value = entry.getValue();
 419  0
                     if (Renderer.PASSTHROUGH_RENDERER_LOCALNAME_KEY.equals(key))
 420  
                     {
 421  
                         // Special attribute stored in passthrough attribute map,
 422  
                         // skip rendering
 423  0
                         continue;
 424  
                     }
 425  0
                     if (value instanceof ValueExpression)
 426  
                     {
 427  0
                         value = ((ValueExpression)value).getValue(getFacesContext().getELContext());
 428  
                     }
 429  
                     // encodeAndWriteURIAttribute(key, value, key);
 430  
                     // JSF 2.2 In the renderkit javadoc of jsf 2.2 spec says this 
 431  
                     // (Rendering Pass Through Attributes):
 432  
                     // "... The ResponseWriter must ensure that any pass through attributes are 
 433  
                     // rendered on the outer-most markup element for the component. If there is 
 434  
                     // a pass through attribute with the same name as a renderer specific 
 435  
                     // attribute, the pass through attribute takes precedence. Pass through 
 436  
                     // attributes are rendered as if they were passed to 
 437  
                     // ResponseWriter.writeURIAttribute(). ..."
 438  
                     // Note here it says "as if they were passed", instead say "... attributes are
 439  
                     // encoded and rendered as if ...". Black box testing against RI shows that there
 440  
                     // is no URI encoding at all in this part, so in this case the best is do the
 441  
                     // same here. After all, it is resposibility of the one who set the passthrough
 442  
                     // attribute to do the proper encoding in cases when a URI is provided. However,
 443  
                     // that does not means the attribute should not be encoded as other attributes.
 444  
                     // According to tests done, if passthrough attribute is null, the attribute must not
 445  
                     // be rendered.
 446  0
                     if (value != null)
 447  
                     {
 448  0
                         encodeAndWriteAttribute(key, value);
 449  
                     }
 450  0
                 }
 451  
             }
 452  
 
 453  21
             if (!_useStraightXml && isEmptyElement(_startElementName))
 454  
             {
 455  2
                 _currentWriter.write(" />");
 456  
                 // make null, this will cause NullPointer in some invalid element nestings
 457  
                 // (better than doing nothing)
 458  2
                 resetStartedElement();
 459  
             }
 460  
             else
 461  
             {
 462  19
                 _currentWriter.write('>');
 463  
                 /*
 464  
                 if(isScript(_startElementName))
 465  
                 {
 466  
                     if(HtmlRendererUtils.isXHTMLContentType(_contentType))
 467  
                     {
 468  
                         if(HtmlRendererUtils.isAllowedCdataSection(FacesContext.getCurrentInstance()))
 469  
                         {
 470  
                             _currentWriter.write(CDATA_START);
 471  
                         }
 472  
                     }
 473  
                     else
 474  
                     {
 475  
                         _currentWriter.write(COMMENT_START);
 476  
                     }
 477  
                 }*/
 478  19
                 if (isScript(_startElementName) && (_isXhtmlContentType || _wrapScriptContentWithXmlCommentTag))
 479  
                 {
 480  
                     //_bufferedWriter.reset();
 481  
                     //_currentWriter = _bufferedWriter;
 482  5
                     getInternalBuffer(true);
 483  5
                     _currentWriter = getInternalBuffer().getWriter();
 484  
                 }                
 485  19
                 if (isStyle(_startElementName) && _isXhtmlContentType)
 486  
                 {
 487  
                     //_bufferedWriter.reset();
 488  
                     //_currentWriter = _bufferedWriter;
 489  2
                     getInternalBuffer(true);
 490  2
                     _currentWriter = getInternalBuffer().getWriter();
 491  
                 }
 492  
             }
 493  21
             _startTagOpen = false;
 494  
         }
 495  34
     }
 496  
     
 497  
     private boolean isEmptyElement(String elem)
 498  
     {
 499  
         // Code taken from trinidad
 500  
         // =-=AEW Performance?  Certainly slower to use a hashtable,
 501  
         // at least if we can't assume the input name is lowercased.
 502  
         // -= Leonardo Uribe =- elem.toLowerCase() internally creates an array,
 503  
         // and the contains() force a call to hashCode(). The array uses simple
 504  
         // char comparison, which at the end is faster and use less memory.
 505  
         // Note this call is very frequent, so at the end it is worth to do it.
 506  34
         String[] array = EMPTY_ELEMENT_ARR[elem.charAt(0)];
 507  34
         if (array != null)
 508  
         {
 509  32
             for (int i = array.length - 1; i >= 0; i--)
 510  
             {
 511  26
                 if (elem.equalsIgnoreCase(array[i]))
 512  
                 {
 513  4
                     return true;
 514  
                 }
 515  
             }
 516  
         }
 517  30
         return false;
 518  
     }
 519  
 
 520  
     private void resetStartedElement()
 521  
     {
 522  44
         _startElementName = null;
 523  44
         _startElementUIComponent = null;
 524  44
         _passThroughAttributesMap = null;
 525  44
         _isStyle = false;
 526  44
         _isTextArea = null;
 527  44
     }
 528  
 
 529  
     public void endElement(String name) throws IOException
 530  
     {
 531  21
         if (name == null)
 532  
         {
 533  0
             throw new NullPointerException("elementName name must not be null");
 534  
         }
 535  
 
 536  21
         String elementName = name;
 537  
 
 538  21
         if (!_startedElementsCount.isEmpty())
 539  
         {
 540  0
             int i = _startedElementsCount.size()-1;
 541  0
             _startedElementsCount.set(i, _startedElementsCount.get(i)-1);
 542  0
             if (_startedElementsCount.get(i) == 0)
 543  
             {
 544  0
                 elementName = _startedChangedElements.get(i);
 545  0
                 _startedChangedElements.remove(i);
 546  0
                 _startedElementsCount.remove(i);
 547  
             }
 548  
         }
 549  
 
 550  21
         if (log.isLoggable(Level.WARNING))
 551  
         {
 552  21
             if (_startElementName != null &&
 553  
                 !elementName.equals(_startElementName))
 554  
             {
 555  0
                 log.warning("HTML nesting warning on closing " + elementName + ": element " + _startElementName +
 556  
                         (_startElementUIComponent==null?"":(" rendered by component : "+
 557  
                         RendererUtils.getPathToComponent(_startElementUIComponent)))+" not explicitly closed");
 558  
             }
 559  
         }
 560  
 
 561  21
         if(_startTagOpen)
 562  
         {
 563  
 
 564  
             // we will get here only if no text or attribute was written after the start element was opened
 565  
             // now we close out the started tag - if it is an empty tag, this is then fully closed
 566  0
             closeStartTagIfNecessary();
 567  
 
 568  
             //tag was no empty tag - it has no accompanying end tag now.
 569  0
             if(_startElementName!=null)
 570  
             {                
 571  0
                 if (isScript() && (_isXhtmlContentType || _wrapScriptContentWithXmlCommentTag))
 572  
                 {
 573  0
                     writeScriptContent();
 574  0
                     _currentWriter = _outputWriter;
 575  
                 }
 576  0
                 else if (isStyle() && _isXhtmlContentType)
 577  
                 {
 578  0
                     writeStyleContent();
 579  0
                     _currentWriter = _outputWriter;
 580  
                 }
 581  
 
 582  
                 //write closing tag
 583  0
                 writeEndTag(elementName);
 584  
             }
 585  
         }
 586  
         else
 587  
         {
 588  21
             if (!_useStraightXml && isEmptyElement(elementName))
 589  
             {
 590  
            /*
 591  
            Should this be here?  It warns even when you have an x:htmlTag value="br", it should just close.
 592  
 
 593  
                 if (log.isWarnEnabled())
 594  
                     log.warn("HTML nesting warning on closing " + name + 
 595  
                         ": This element must not contain nested elements or text in HTML");
 596  
                     */
 597  
             }
 598  
             else
 599  
             {
 600  19
                 if (isScript() && (_isXhtmlContentType || _wrapScriptContentWithXmlCommentTag))
 601  
                 {
 602  8
                     writeScriptContent();
 603  8
                     _currentWriter = _outputWriter;
 604  
                 }
 605  11
                 else if (isStyle() && _isXhtmlContentType)
 606  
                 {
 607  2
                     writeStyleContent();
 608  2
                     _currentWriter = _outputWriter;
 609  
                 }
 610  19
                 writeEndTag(elementName);
 611  
             }
 612  
         }
 613  
 
 614  21
         resetStartedElement();
 615  21
     }
 616  
 
 617  
 
 618  
     
 619  
     private void writeStyleContent() throws IOException
 620  
     {
 621  2
         String content = getInternalBuffer().toString();
 622  
         
 623  2
         if(_isXhtmlContentType)
 624  
         {
 625  
             // In xhtml, the content inside <style> tag is PCDATA, but
 626  
             // in html the content is CDATA, so in order to preserve 
 627  
             // compatibility we need to wrap the content inside proper
 628  
             // CDATA tags.
 629  
             // Since the response content type is xhtml, we can use
 630  
             // simple CDATA without comments, but note we need to check
 631  
             // when we are using any valid notation (simple CDATA, commented CDATA, xml comment) 
 632  2
             String trimmedContent = content.trim();
 633  2
             if (trimmedContent.startsWith(CommentUtils.CDATA_SIMPLE_START) && trimmedContent.endsWith(
 634  
                     CommentUtils.CDATA_SIMPLE_END))
 635  
             {
 636  0
                 _outputWriter.write(content);
 637  0
                 return;
 638  
             }
 639  2
             else if (CommentUtils.isStartMatchWithCommentedCDATA(trimmedContent) && 
 640  
                     CommentUtils.isEndMatchWithCommentedCDATA(trimmedContent))
 641  
             {
 642  0
                 _outputWriter.write(content);
 643  0
                 return;
 644  
             }
 645  2
             else if (trimmedContent.startsWith(CommentUtils.COMMENT_SIMPLE_START) && 
 646  
                     trimmedContent.endsWith(CommentUtils.COMMENT_SIMPLE_END))
 647  
             {
 648  
                 //Use comment wrap is valid, but for xhtml it is preferred to use CDATA
 649  0
                 _outputWriter.write(CDATA_START);
 650  0
                 _outputWriter.write(trimmedContent.substring(4,trimmedContent.length()-3));
 651  0
                 _outputWriter.write(CDATA_END);
 652  0
                 return;
 653  
             }
 654  
             else
 655  
             {
 656  2
                 _outputWriter.write(CDATA_START);
 657  2
                 _outputWriter.write(content);
 658  2
                 _outputWriter.write(CDATA_END);
 659  2
                 return;                
 660  
             }
 661  
         }
 662  
         // If the response is handled as text/html, 
 663  
         // it is not necessary to wrap with xml comment tag,
 664  
         // so we can just write the content as is.
 665  0
         _outputWriter.write(content);
 666  0
     }
 667  
     
 668  
     private void writeScriptContent() throws IOException
 669  
     {
 670  8
         String content = getInternalBuffer().toString();
 671  8
         String trimmedContent = null;
 672  
         
 673  8
         if(_isXhtmlContentType)
 674  
         {
 675  2
             trimmedContent = content.trim();
 676  
             
 677  2
             if ( trimmedContent.startsWith(CommentUtils.COMMENT_SIMPLE_START) && 
 678  
                     CommentUtils.isEndMatchtWithInlineCommentedXmlCommentTag(trimmedContent))
 679  
             {
 680  
                 // In xhtml use xml comment to wrap is invalid, so it is only required to remove the <!--
 681  
                 // the ending //--> will be parsed as a comment, so it will not be a problem. Let it on the content.
 682  0
                 if (_cdataOpen)
 683  
                 {
 684  0
                     _outputWriter.write("//\n");
 685  
                 }
 686  
                 else
 687  
                 {
 688  0
                    _outputWriter.write(CDATA_COMMENT_START);
 689  
                 }
 690  
 
 691  0
                 _outputWriter.write(trimmedContent.substring(4));
 692  
 
 693  0
                 if (_cdataOpen)
 694  
                 {
 695  0
                     _outputWriter.write("\n");
 696  
                 }
 697  
                 else
 698  
                 {
 699  0
                     _outputWriter.write(CDATA_COMMENT_END);
 700  
                 }
 701  
                 
 702  0
                 return;
 703  
             }
 704  2
             else if (CommentUtils.isStartMatchWithCommentedCDATA(trimmedContent) && 
 705  
                     CommentUtils.isEndMatchWithCommentedCDATA(trimmedContent))
 706  
             {
 707  0
                 _outputWriter.write(content);
 708  0
                 return;
 709  
             }
 710  2
             else if (CommentUtils.isStartMatchWithInlineCommentedCDATA(trimmedContent) && 
 711  
                     CommentUtils.isEndMatchWithInlineCommentedCDATA(trimmedContent))
 712  
             {
 713  0
                 _outputWriter.write(content);
 714  0
                 return;
 715  
             }
 716  
             else
 717  
             {
 718  
                 // <script> in xhtml has as content type PCDATA, but in html it is CDATA,
 719  
                 // so we need to wrap here to prevent problems.
 720  2
                 if (_cdataOpen)
 721  
                 {
 722  0
                     _outputWriter.write("//\n");
 723  
                 }
 724  
                 else
 725  
                 {
 726  2
                    _outputWriter.write(CDATA_COMMENT_START);
 727  
                 }
 728  
 
 729  2
                 _outputWriter.write(content);
 730  
 
 731  2
                 if (_cdataOpen)
 732  
                 {
 733  0
                     _outputWriter.write("\n");
 734  
                 }
 735  
                 else
 736  
                 {
 737  2
                     _outputWriter.write(CDATA_COMMENT_END);
 738  
                 }
 739  
 
 740  2
                 return;
 741  
             }
 742  
         }
 743  
         else
 744  
         {
 745  6
             if (_wrapScriptContentWithXmlCommentTag)
 746  
             {
 747  6
                 trimmedContent = content.trim();
 748  
                 
 749  6
                 if ( trimmedContent.startsWith(CommentUtils.COMMENT_SIMPLE_START) && 
 750  
                         CommentUtils.isEndMatchtWithInlineCommentedXmlCommentTag(trimmedContent))
 751  
                 {
 752  0
                     _outputWriter.write(content);
 753  0
                     return;
 754  
                 }
 755  6
                 else if (CommentUtils.isStartMatchWithCommentedCDATA(trimmedContent) && 
 756  
                         CommentUtils.isEndMatchWithCommentedCDATA(trimmedContent))
 757  
                 {
 758  0
                     _outputWriter.write(content);
 759  0
                     return;
 760  
                 }
 761  6
                 else if (CommentUtils.isStartMatchWithInlineCommentedCDATA(trimmedContent) && 
 762  
                         CommentUtils.isEndMatchWithInlineCommentedCDATA(trimmedContent))
 763  
                 {
 764  0
                     _outputWriter.write(content);
 765  0
                     return;
 766  
                 }
 767  
                 else
 768  
                 {
 769  6
                     _outputWriter.write(COMMENT_START);
 770  6
                     _outputWriter.write(content);
 771  6
                     _outputWriter.write(COMMENT_COMMENT_END);
 772  6
                     return;
 773  
                 }
 774  
             }
 775  
         }
 776  
         
 777  
         //If no return, just write everything
 778  0
         _outputWriter.write(content);
 779  0
     }
 780  
     
 781  
 
 782  
     private void writeEndTag(String name)
 783  
         throws IOException
 784  
     {
 785  
         /*
 786  
         if(isScript(name)) 
 787  
         {
 788  
             if(HtmlRendererUtils.isXHTMLContentType(_contentType))
 789  
             {
 790  
                 if(HtmlRendererUtils.isAllowedCdataSection(FacesContext.getCurrentInstance()))
 791  
                 {
 792  
                     _currentWriter.write(CDATA_COMMENT_END);
 793  
                 }
 794  
             }
 795  
             else
 796  
             {
 797  
                 _currentWriter.write(COMMENT_COMMENT_END);
 798  
             }
 799  
             
 800  
             // reset _isInsideScript
 801  
             _isInsideScript = Boolean.FALSE;
 802  
         }*/
 803  
         
 804  19
         if (isScript(name))
 805  
         {
 806  
             // reset _isInsideScript
 807  7
             _isInsideScript = false;
 808  
         }
 809  12
         else if (isStyle(name))
 810  
         {
 811  2
             _isStyle = false;
 812  
         }
 813  
 
 814  19
         _currentWriter.write("</");
 815  19
         _currentWriter.write(name);
 816  19
         _currentWriter.write('>');
 817  19
     }
 818  
 
 819  
     public void writeAttribute(String name, Object value, String componentPropertyName) throws IOException
 820  
     {
 821  0
         if (name == null)
 822  
         {
 823  0
             throw new NullPointerException("attributeName name must not be null");
 824  
         }
 825  0
         if (!_startTagOpen)
 826  
         {
 827  0
             throw new IllegalStateException("Must be called before the start element is closed (attribute '"
 828  
                     + name + "')");
 829  
         }
 830  
         // From JSF 2.2 RenderKit javadoc: "... If there is a pass through attribute with the same 
 831  
         // name as a renderer specific attribute, the pass through attribute takes precedence. ..."
 832  0
         if (_passThroughAttributesMap != null && _passThroughAttributesMap.containsKey(name))
 833  
         {
 834  0
             return;
 835  
         }
 836  
 
 837  0
         if (value instanceof Boolean)
 838  
         {
 839  0
             if (((Boolean)value).booleanValue())
 840  
             {
 841  
                 // name as value for XHTML compatibility
 842  0
                 _currentWriter.write(' ');
 843  0
                 _currentWriter.write(name);
 844  0
                 _currentWriter.write("=\"");
 845  0
                 _currentWriter.write(name);
 846  0
                 _currentWriter.write('"');
 847  
             }
 848  
         }
 849  
         else
 850  
         {
 851  0
             String strValue = (value==null)?"":value.toString();
 852  0
             _currentWriter.write(' ');
 853  0
             _currentWriter.write(name);
 854  0
             _currentWriter.write("=\"");
 855  0
             org.apache.myfaces.shared.renderkit.html.util.HTMLEncoder.encode(_currentWriter,
 856  
                     strValue, false, false, !_isUTF8);
 857  0
             _currentWriter.write('"');
 858  
         }
 859  0
     }
 860  
     
 861  
     private void encodeAndWriteAttribute(String name, Object value) throws IOException
 862  
     {
 863  0
         String strValue = (value==null)?"":value.toString();
 864  0
         _currentWriter.write(' ');
 865  0
         _currentWriter.write(name);
 866  0
         _currentWriter.write("=\"");
 867  0
         org.apache.myfaces.shared.renderkit.html.util.HTMLEncoder.encode(_currentWriter,
 868  
                 strValue, false, false, !_isUTF8);
 869  0
         _currentWriter.write('"');
 870  0
     }
 871  
 
 872  
     public void writeURIAttribute(String name, Object value, String componentPropertyName) throws IOException
 873  
     {
 874  0
         if (name == null)
 875  
         {
 876  0
             throw new NullPointerException("attributeName name must not be null");
 877  
         }
 878  0
         if (!_startTagOpen)
 879  
         {
 880  0
             throw new IllegalStateException("Must be called before the start element is closed (attribute '"
 881  
                     + name + "')");
 882  
         }
 883  
         // From JSF 2.2 RenderKit javadoc: "... If there is a pass through attribute with the same 
 884  
         // name as a renderer specific attribute, the pass through attribute takes precedence. ..."
 885  0
         if (_passThroughAttributesMap != null && _passThroughAttributesMap.containsKey(name))
 886  
         {
 887  0
             return;
 888  
         }
 889  
         
 890  0
         encodeAndWriteURIAttribute(name, value);
 891  0
     }
 892  
     
 893  
     private void encodeAndWriteURIAttribute(String name, Object value) throws IOException
 894  
     {
 895  0
         String strValue = value.toString();
 896  0
         _currentWriter.write(' ');
 897  0
         _currentWriter.write(name);
 898  0
         _currentWriter.write("=\"");
 899  0
         if (strValue.toLowerCase().startsWith("javascript:"))
 900  
         {
 901  0
             org.apache.myfaces.shared.renderkit.html.util.HTMLEncoder.encode(_currentWriter,
 902  
                     strValue, false, false, !_isUTF8);
 903  
         }
 904  
         else
 905  
         {
 906  
             /*
 907  
             Todo: what is this section about? still needed?
 908  
             client side state saving is now done via javascript...
 909  
 
 910  
             if (_startElementName.equalsIgnoreCase(HTML.ANCHOR_ELEM) && //Also support image and button urls?
 911  
                 name.equalsIgnoreCase(HTML.HREF_ATTR) &&
 912  
                 !strValue.startsWith("#"))
 913  
             {
 914  
                 FacesContext facesContext = FacesContext.getCurrentInstance();
 915  
                 if (facesContext.getApplication().getStateManager().isSavingStateInClient(facesContext))
 916  
                 {
 917  
                     // saving state in url depends on the work together
 918  
                     // of 3 (theoretically) pluggable components:
 919  
                     // ViewHandler, ResponseWriter and ViewTag
 920  
                     // We should try to make this HtmlResponseWriterImpl able
 921  
                     // to handle this alone!
 922  
                     if (strValue.indexOf('?') < 0)
 923  
                     {
 924  
                         strValue = strValue + '?' + JspViewHandlerImpl.URL_STATE_MARKER;
 925  
                     }
 926  
                     else
 927  
                     {
 928  
                         strValue = strValue + '&' + JspViewHandlerImpl.URL_STATE_MARKER;
 929  
                     }
 930  
                 }
 931  
             }
 932  
             */
 933  
             //_writer.write(strValue);
 934  0
             org.apache.myfaces.shared.renderkit.html.util.HTMLEncoder.encodeURIAttribute(_currentWriter,
 935  
                             strValue, _characterEncoding);
 936  
         }
 937  0
         _currentWriter.write('"');
 938  0
     }
 939  
 
 940  
     public void writeComment(Object value) throws IOException
 941  
     {
 942  0
         if (value == null)
 943  
         {
 944  0
             throw new NullPointerException("comment name must not be null");
 945  
         }
 946  
 
 947  0
         closeStartTagIfNecessary();
 948  0
         _currentWriter.write("<!--");
 949  0
         _currentWriter.write(value.toString());    //TODO: Escaping: must not have "-->" inside!
 950  0
         _currentWriter.write("-->");
 951  0
     }
 952  
 
 953  
     public void writeText(Object value, String componentPropertyName) throws IOException
 954  
     {
 955  4
         if (value == null)
 956  
         {
 957  0
             throw new NullPointerException("Text must not be null.");
 958  
         }
 959  
 
 960  4
         closeStartTagIfNecessary();
 961  
 
 962  4
         String strValue = value.toString();
 963  
 
 964  4
         if (isScriptOrStyle())
 965  
         {
 966  
             // Don't bother encoding anything if chosen character encoding is UTF-8
 967  0
             if (_isUTF8)
 968  
             {
 969  0
                 _currentWriter.write(strValue);
 970  
             }
 971  
             else
 972  
             {
 973  0
                 UnicodeEncoder.encode(_currentWriter, strValue);
 974  
             }
 975  
         }
 976  
         else
 977  
         {
 978  4
             org.apache.myfaces.shared.renderkit.html.util.HTMLEncoder.encode(_currentWriter,
 979  
                       strValue, false, false, !_isUTF8);
 980  
         }
 981  4
     }
 982  
 
 983  
     public void writeText(char cbuf[], int off, int len) throws IOException
 984  
     {
 985  0
         if (cbuf == null)
 986  
         {
 987  0
             throw new NullPointerException("cbuf name must not be null");
 988  
         }
 989  0
         if (cbuf.length < off + len)
 990  
         {
 991  0
             throw new IndexOutOfBoundsException((off + len) + " > " + cbuf.length);
 992  
         }
 993  
 
 994  0
         closeStartTagIfNecessary();
 995  
 
 996  0
         if (isScriptOrStyle())
 997  
         {
 998  0
             String strValue = new String(cbuf, off, len);
 999  
             // Don't bother encoding anything if chosen character encoding is UTF-8
 1000  0
             if (_isUTF8)
 1001  
             {
 1002  0
                 _currentWriter.write(strValue);
 1003  
             }
 1004  
             else
 1005  
             {
 1006  0
                 UnicodeEncoder.encode(_currentWriter, strValue);
 1007  
             }
 1008  0
         }
 1009  0
         else if (isTextarea())
 1010  
         {
 1011  
             // For textareas we must *not* map successive spaces to &nbsp or Newlines to <br/>
 1012  0
             org.apache.myfaces.shared.renderkit.html.util.HTMLEncoder.encode(
 1013  
                     cbuf, off, len, false, false, !_isUTF8, _currentWriter);
 1014  
         }
 1015  
         else
 1016  
         {
 1017  
             // We map successive spaces to &nbsp; and Newlines to <br/>
 1018  0
             org.apache.myfaces.shared.renderkit.html.util.HTMLEncoder.encode(
 1019  
                     cbuf, off, len, true, true, !_isUTF8, _currentWriter);
 1020  
         }
 1021  0
     }
 1022  
 
 1023  
     private boolean isScriptOrStyle()
 1024  
     {
 1025  
         //initializeStartedTagInfo();
 1026  
 
 1027  4
         return _isStyle || _isInsideScript;
 1028  
     }
 1029  
     
 1030  
     /**
 1031  
      * Is the given element a script tag?
 1032  
      * @param element
 1033  
      * @return
 1034  
      */
 1035  
     private boolean isScript(String element)
 1036  
     {
 1037  59
         return (HTML.SCRIPT_ELEM.equalsIgnoreCase(element));
 1038  
     }
 1039  
     
 1040  
     private boolean isScript()
 1041  
     {
 1042  19
         return _isInsideScript;
 1043  
     }
 1044  
     
 1045  
     private boolean isStyle(String element)
 1046  
     {
 1047  45
         return (HTML.STYLE_ELEM.equalsIgnoreCase(element));
 1048  
     }
 1049  
     
 1050  
     private boolean isStyle()
 1051  
     {
 1052  11
         return _isStyle;
 1053  
     }
 1054  
 
 1055  
     private boolean isTextarea()
 1056  
     {
 1057  0
         initializeStartedTagInfo();
 1058  
 
 1059  0
         return _isTextArea != null && _isTextArea.booleanValue();
 1060  
     }
 1061  
 
 1062  
     private void initializeStartedTagInfo()
 1063  
     {
 1064  0
         if(_startElementName != null)
 1065  
         {
 1066  
             /*
 1067  
             if(_isStyle == null)
 1068  
             {
 1069  
                 if(_startElementName.equalsIgnoreCase(org.apache.myfaces.shared.renderkit.html.HTML.STYLE_ELEM))
 1070  
                 {
 1071  
                     _isStyle = Boolean.TRUE;
 1072  
                     _isTextArea = Boolean.FALSE;
 1073  
                 }
 1074  
                 else
 1075  
                 {
 1076  
                     _isStyle = Boolean.FALSE;
 1077  
                 }
 1078  
             }*/
 1079  
 
 1080  0
             if(_isTextArea == null)
 1081  
             {
 1082  0
                 if(_startElementName.equalsIgnoreCase(HTML.TEXTAREA_ELEM))
 1083  
                 {
 1084  0
                     _isTextArea = Boolean.TRUE;
 1085  
                 }
 1086  
                 else
 1087  
                 {
 1088  0
                     _isTextArea = Boolean.FALSE;
 1089  
                 }
 1090  
             }
 1091  
         }
 1092  0
     }
 1093  
 
 1094  
     public ResponseWriter cloneWithWriter(Writer writer)
 1095  
     {
 1096  0
         HtmlResponseWriterImpl newWriter
 1097  
                 = new HtmlResponseWriterImpl(writer, getContentType(), getCharacterEncoding(), 
 1098  
                         _wrapScriptContentWithXmlCommentTag, _writerContentTypeMode);
 1099  
         //newWriter._writeDummyForm = _writeDummyForm;
 1100  
         //newWriter._dummyFormParams = _dummyFormParams;
 1101  0
         return newWriter;
 1102  
     }
 1103  
 
 1104  
 
 1105  
     // Writer methods
 1106  
 
 1107  
     public void close() throws IOException
 1108  
     {
 1109  0
         closeStartTagIfNecessary();
 1110  0
         _currentWriter.close();
 1111  0
         _facesContext = null;
 1112  0
     }
 1113  
 
 1114  
     public void write(char cbuf[], int off, int len) throws IOException
 1115  
     {
 1116  0
         closeStartTagIfNecessary();
 1117  
         // Don't bother encoding anything if chosen character encoding is UTF-8
 1118  0
         if (_isUTF8)
 1119  
         {
 1120  0
             _currentWriter.write(cbuf, off, len);
 1121  
         }
 1122  
         else
 1123  
         {
 1124  0
             UnicodeEncoder.encode(_currentWriter, cbuf, off, len);
 1125  
         }
 1126  0
     }
 1127  
 
 1128  
     public void write(int c) throws IOException
 1129  
     {
 1130  0
         closeStartTagIfNecessary();
 1131  0
         _currentWriter.write(c);
 1132  0
     }
 1133  
 
 1134  
     public void write(char cbuf[]) throws IOException
 1135  
     {
 1136  0
         closeStartTagIfNecessary();
 1137  
         // Don't bother encoding anything if chosen character encoding is UTF-8
 1138  0
         if (_isUTF8)
 1139  
         {
 1140  0
             _currentWriter.write(cbuf);
 1141  
         }
 1142  
         else
 1143  
         {
 1144  0
             UnicodeEncoder.encode(_currentWriter, cbuf, 0, cbuf.length);
 1145  
         }
 1146  0
     }
 1147  
 
 1148  
     public void write(String str) throws IOException
 1149  
     {
 1150  9
         closeStartTagIfNecessary();
 1151  
         // empty string commonly used to force the start tag to be closed.
 1152  
         // in such case, do not call down the writer chain
 1153  9
         if (str != null && str.length() > 0)
 1154  
         {
 1155  
             // Don't bother encoding anything if chosen character encoding is UTF-8
 1156  9
             if (_isUTF8)
 1157  
             {
 1158  4
                 _currentWriter.write(str);
 1159  
             }
 1160  
             else
 1161  
             {
 1162  5
                 UnicodeEncoder.encode(_currentWriter, str);
 1163  
             }
 1164  
         }
 1165  9
     }
 1166  
 
 1167  
     public void write(String str, int off, int len) throws IOException
 1168  
     {
 1169  0
         closeStartTagIfNecessary();
 1170  
         // Don't bother encoding anything if chosen character encoding is UTF-8
 1171  0
         if (_isUTF8)
 1172  
         {
 1173  0
             _currentWriter.write(str, off, len);
 1174  
         }
 1175  
         else
 1176  
         {
 1177  0
             UnicodeEncoder.encode(_currentWriter, str, off, len);
 1178  
         }
 1179  0
     }
 1180  
     
 1181  
     /**
 1182  
      * This method ignores the <code>UIComponent</code> provided and simply calls
 1183  
      * <code>writeText(Object,String)</code>
 1184  
      * @since 1.2
 1185  
      */
 1186  
     public void writeText(Object object, UIComponent component, String string) throws IOException
 1187  
     {
 1188  0
         writeText(object,string);
 1189  0
     }
 1190  
     
 1191  
     protected StreamCharBuffer getInternalBuffer()
 1192  
     {
 1193  17
         return getInternalBuffer(false);
 1194  
     }
 1195  
     
 1196  
     protected StreamCharBuffer getInternalBuffer(boolean reset)
 1197  
     {
 1198  24
         if (_buffer == null)
 1199  
         {
 1200  7
             _buffer = new StreamCharBuffer(256, 100);
 1201  
         }
 1202  17
         else if (reset)
 1203  
         {
 1204  0
             _buffer.reset();
 1205  
         }
 1206  24
         return _buffer;
 1207  
     }
 1208  
     
 1209  
     protected FacesContext getFacesContext()
 1210  
     {
 1211  0
         if (_facesContext == null)
 1212  
         {
 1213  0
             _facesContext = FacesContext.getCurrentInstance();
 1214  
         }
 1215  0
         return _facesContext;
 1216  
     }
 1217  
     
 1218  
     protected boolean getWrapScriptContentWithXmlCommentTag()
 1219  
     {
 1220  0
         return _wrapScriptContentWithXmlCommentTag;
 1221  
     }
 1222  
     
 1223  
     protected void forceFlush() throws IOException
 1224  
     {
 1225  0
         _currentWriter.flush();
 1226  0
     }
 1227  
 }