All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlResponseWriterImpl Maven / Gradle / Ivy

Go to download

JSF components and utilities that can be used with any JSF implementation. This library is based on the JSF1.1 version of Tomahawk, but with minor source code and build changes to take advantage of JSF2.1 features. A JSF2.1 implementation is required to use this version of the Tomahawk library.

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.myfaces.shared_tomahawk.renderkit.html;

import java.io.IOException;
import java.io.Writer;
import java.nio.charset.Charset;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.faces.FacesException;
import javax.faces.component.UIComponent;
import javax.faces.context.ResponseWriter;

import org.apache.myfaces.shared_tomahawk.renderkit.ContentTypeUtils;
import org.apache.myfaces.shared_tomahawk.renderkit.RendererUtils;
import org.apache.myfaces.shared_tomahawk.renderkit.html.util.UnicodeEncoder;
import org.apache.myfaces.shared_tomahawk.util.CommentUtils;
import org.apache.myfaces.shared_tomahawk.util.StreamCharBuffer;

/**
 * @author Manfred Geiler (latest modification by $Author: lu4242 $)
 * @author Anton Koinov
 * @version $Revision: 1401386 $ $Date: 2012-10-23 13:59:22 -0500 (Tue, 23 Oct 2012) $
 */
public class HtmlResponseWriterImpl
        extends ResponseWriter
{
    //private static final Log log = LogFactory.getLog(HtmlResponseWriterImpl.class);
    private static final Logger log = Logger.getLogger(HtmlResponseWriterImpl.class.getName());

    private static final String DEFAULT_CONTENT_TYPE = "text/html";
    private static final String DEFAULT_CHARACTER_ENCODING = "ISO-8859-1";
    private static final String UTF8 = "UTF-8";

    private static final String APPLICATION_XML_CONTENT_TYPE = "application/xml";
    private static final String TEXT_XML_CONTENT_TYPE = "text/xml";
    
    //private boolean _writeDummyForm = false;
    //private Set _dummyFormParams = null;

    /**
     * The writer used as output, or in other words, the one passed on the constructor
     */
    private Writer _outputWriter;
    
    /**
     * The writer we are using to store data.
     */
    private Writer _currentWriter;
    
    /**
     * The writer used to buffer script and style content
     */
    private StreamCharBuffer _buffer;
    
    private String _contentType;
    
    private String _writerContentTypeMode;
    
    /**
     * This var prevents check if the contentType is for xhtml multiple times.
     */
    private boolean _isXhtmlContentType;
    
    /**
     * Indicate the current response writer should not close automatically html elements
     * and let the writer close them.
     */
    private boolean _useStraightXml;
    
    private String _characterEncoding;
    private boolean _wrapScriptContentWithXmlCommentTag;
    private boolean _isUTF8;
    
    private String _startElementName;
    private Boolean _isInsideScript;
    private Boolean _isStyle;
    private Boolean _isTextArea;
    private UIComponent _startElementUIComponent;
    private boolean _startTagOpen;

    private boolean _cdataOpen;

    private static final String CDATA_START = "";
    private static final String CDATA_END = "\n]]>";
    private static final String CDATA_END_NO_LINE_RETURN = "]]>";
    private static final String COMMENT_COMMENT_END = "\n//-->";
    private static final String COMMENT_END = "\n-->";

    static private final String[][] EMPTY_ELEMENT_ARR = new String[256][];

    static private final String[] A_NAMES = new String[]
    {
      "area",
    };

    static private final String[] B_NAMES = new String[]
    {
      "br",
      "base",
      "basefont",
    };

    static private final String[] C_NAMES = new String[]
    {
      "col",
    };

    static private final String[] E_NAMES = new String[]
    {
      "embed",
    };

    static private final String[] F_NAMES = new String[]
    {
      "frame",
    };

    static private final String[] H_NAMES = new String[]
    {
      "hr",
    };

    static private final String[] I_NAMES = new String[]
    {
      "img",
      "input",
      "isindex",
    };

    static private final String[] L_NAMES = new String[]
    {
      "link",
    };

    static private final String[] M_NAMES = new String[]
    {
      "meta",
    };

    static private final String[] P_NAMES = new String[]
    {
      "param",
    };

    static
    {
      EMPTY_ELEMENT_ARR['a'] = A_NAMES;
      EMPTY_ELEMENT_ARR['A'] = A_NAMES;
      EMPTY_ELEMENT_ARR['b'] = B_NAMES;
      EMPTY_ELEMENT_ARR['B'] = B_NAMES;
      EMPTY_ELEMENT_ARR['c'] = C_NAMES;
      EMPTY_ELEMENT_ARR['C'] = C_NAMES;
      EMPTY_ELEMENT_ARR['e'] = E_NAMES;
      EMPTY_ELEMENT_ARR['E'] = E_NAMES;
      EMPTY_ELEMENT_ARR['f'] = F_NAMES;
      EMPTY_ELEMENT_ARR['F'] = F_NAMES;
      EMPTY_ELEMENT_ARR['h'] = H_NAMES;
      EMPTY_ELEMENT_ARR['H'] = H_NAMES;
      EMPTY_ELEMENT_ARR['i'] = I_NAMES;
      EMPTY_ELEMENT_ARR['I'] = I_NAMES;
      EMPTY_ELEMENT_ARR['l'] = L_NAMES;
      EMPTY_ELEMENT_ARR['L'] = L_NAMES;
      EMPTY_ELEMENT_ARR['m'] = M_NAMES;
      EMPTY_ELEMENT_ARR['M'] = M_NAMES;
      EMPTY_ELEMENT_ARR['p'] = P_NAMES;
      EMPTY_ELEMENT_ARR['P'] = P_NAMES;
    }    
    
    public HtmlResponseWriterImpl(Writer writer, String contentType, String characterEncoding)
    {
        this(writer,contentType,characterEncoding,true);
    }

    public HtmlResponseWriterImpl(Writer writer, String contentType, String characterEncoding,
            boolean wrapScriptContentWithXmlCommentTag)
    {
        this(writer,contentType, characterEncoding, wrapScriptContentWithXmlCommentTag, 
                contentType != null && HtmlRendererUtils.isXHTMLContentType(contentType) ? 
                    ContentTypeUtils.XHTML_CONTENT_TYPE : ContentTypeUtils.HTML_CONTENT_TYPE);
    }
    
    public HtmlResponseWriterImpl(Writer writer, String contentType, String characterEncoding,
             boolean wrapScriptContentWithXmlCommentTag, String writerContentTypeMode)
    throws FacesException
    {
        _outputWriter = writer;
        //The current writer to be used is the one used as output 
        _currentWriter = _outputWriter;
        _wrapScriptContentWithXmlCommentTag = wrapScriptContentWithXmlCommentTag;
        
        _contentType = contentType;
        if (_contentType == null)
        {
            if (log.isLoggable(Level.FINE))
            {
                log.fine("No content type given, using default content type " + DEFAULT_CONTENT_TYPE);
            }
            _contentType = DEFAULT_CONTENT_TYPE;
        }
        _writerContentTypeMode = writerContentTypeMode;
        _isXhtmlContentType = writerContentTypeMode.indexOf(ContentTypeUtils.XHTML_CONTENT_TYPE) != -1;
        
        _useStraightXml = _isXhtmlContentType && (_contentType.indexOf(APPLICATION_XML_CONTENT_TYPE) != -1 ||
                          _contentType.indexOf(TEXT_XML_CONTENT_TYPE) != -1);

        if (characterEncoding == null)
        {
            if (log.isLoggable(Level.FINE))
            {
                log.fine("No character encoding given, using default character encoding " +
                        DEFAULT_CHARACTER_ENCODING);
            }
            _characterEncoding = DEFAULT_CHARACTER_ENCODING;
        }
        else
        {
            // canonize to uppercase, that's the standard format
            _characterEncoding = characterEncoding.toUpperCase();
            
            // Check if encoding is valid by javadoc of RenderKit.createResponseWriter()
            if (!Charset.isSupported(_characterEncoding))
            {
                throw new IllegalArgumentException("Encoding "+_characterEncoding
                        +" not supported by HtmlResponseWriterImpl");
            }
        }
        _isUTF8 = UTF8.equals(_characterEncoding);
    }

    public static boolean supportsContentType(String contentType)
    {
        String[] supportedContentTypes = HtmlRendererUtils.getSupportedContentTypes();

        for (int i = 0; i < supportedContentTypes.length; i++)
        {
            String supportedContentType = supportedContentTypes[i];

            if(supportedContentType.indexOf(contentType)!=-1)
            {
                return true;
            }
        }
        return false;
    }

    public String getContentType()
    {
        return _contentType;
    }
    
    public String getWriterContentTypeMode()
    {
        return _writerContentTypeMode;
    }

    public String getCharacterEncoding()
    {
        return _characterEncoding;
    }

    public void flush() throws IOException
    {
        // API doc says we should not flush the underlying writer
        //_writer.flush();
        // but rather clear any values buffered by this ResponseWriter:
        closeStartTagIfNecessary();
    }

    public void startDocument()
    {
        // do nothing
    }

    public void endDocument() throws IOException
    {
        _currentWriter.flush();
    }

    public void startElement(String name, UIComponent uiComponent) throws IOException
    {
        if (name == null)
        {
            throw new NullPointerException("elementName name must not be null");
        }

        closeStartTagIfNecessary();
        _currentWriter.write('<');
        _currentWriter.write(name);

        resetStartedElement();

        _startElementName = name;
        _startElementUIComponent = uiComponent;
        _startTagOpen = true;
        
        // Each time we start a element, it is necessary to check