You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by sv...@apache.org on 2005/02/01 17:51:48 UTC

cvs commit: incubator-myfaces/src/share/org/apache/myfaces/renderkit/html HtmlResponseWriterImpl.java

svieujot    2005/02/01 08:51:48

  Modified:    src/components/org/apache/myfaces/custom/buffer
                        BufferRenderer.java
  Added:       src/share/org/apache/myfaces/renderkit/html
                        HtmlResponseWriterImpl.java
  Removed:     src/myfaces/org/apache/myfaces/renderkit/html
                        HtmlResponseWriterImpl.java
               src/components/org/apache/myfaces/custom/buffer
                        HtmlResponseWriterImpl.java
  Log:
  Move the HtmlResponseWriterImpl to the shared sources directory.
  
  Revision  Changes    Path
  1.2       +6 -2      incubator-myfaces/src/components/org/apache/myfaces/custom/buffer/BufferRenderer.java
  
  Index: BufferRenderer.java
  ===================================================================
  RCS file: /home/cvs/incubator-myfaces/src/components/org/apache/myfaces/custom/buffer/BufferRenderer.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- BufferRenderer.java	4 Jan 2005 15:41:06 -0000	1.1
  +++ BufferRenderer.java	1 Feb 2005 16:51:48 -0000	1.2
  @@ -30,11 +30,15 @@
   import org.apache.commons.logging.Log;
   import org.apache.commons.logging.LogFactory;
   import org.apache.myfaces.renderkit.RendererUtils;
  +import org.apache.myfaces.renderkit.html.HtmlResponseWriterImpl;
   
   /**
    * @author Sylvain Vieujot (latest modification by $Author$)
    * @version $Revision$ $Date$
    * $Log$
  + * Revision 1.2  2005/02/01 16:51:48  svieujot
  + * Move the HtmlResponseWriterImpl to the shared sources directory.
  + *
    * Revision 1.1  2005/01/04 15:41:06  svieujot
    * new x:buffer component.
    *
  
  
  
  1.1                  incubator-myfaces/src/share/org/apache/myfaces/renderkit/html/HtmlResponseWriterImpl.java
  
  Index: HtmlResponseWriterImpl.java
  ===================================================================
  /*
   * Copyright 2004 The Apache Software Foundation.
   *
   * Licensed 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.renderkit.html;
  
  import org.apache.myfaces.config.MyfacesConfig;
  import org.apache.myfaces.renderkit.html.util.DummyFormResponseWriter;
  import org.apache.myfaces.renderkit.html.util.DummyFormUtils;
  import org.apache.myfaces.renderkit.html.util.HTMLEncoder;
  import org.apache.myfaces.renderkit.html.util.JavascriptUtils;
  import org.apache.myfaces.renderkit.html.util.UnicodeEncoder;
  import org.apache.myfaces.renderkit.RendererUtils;
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  
  import javax.faces.component.UIComponent;
  import javax.faces.context.FacesContext;
  import javax.faces.context.ResponseWriter;
  import java.io.IOException;
  import java.io.Writer;
  import java.util.HashSet;
  import java.util.Set;
  
  /**
   * @author Manfred Geiler (latest modification by $Author: svieujot $)
   * @author Anton Koinov
   * @version $Revision: 1.1 $ $Date: 2005/02/01 16:51:48 $
   * $Log: HtmlResponseWriterImpl.java,v $
   * Revision 1.1  2005/02/01 16:51:48  svieujot
   * Move the HtmlResponseWriterImpl to the shared sources directory.
   *
   * Revision 1.36  2005/01/31 17:43:11  svieujot
   * Bugfix for HtmlResponseWriterImpl.write(str, offset, length).
   *
   * Revision 1.35  2005/01/31 17:03:54  svieujot
   * Resynchronize the HtmlResponseWriterImpl from the renderkit, and from the x:buffer component.
   *
   * Revision 1.34  2005/01/29 10:04:25  matzew
   * MYFACES-91 patch by Jason Hoo. Thanks
   *
   * Revision 1.33  2005/01/19 13:18:04  mmarinschek
   * better logging of component information
   *
   * Revision 1.32  2005/01/04 15:41:06  svieujot
   * new x:buffer component.
   *
   * Revision 1.31  2004/12/27 04:11:11  mmarinschek
   * Data Table stores the state of facets of children; script tag is rendered with type attribute instead of language attribute, popup works better as a column in a data table
   *
   * Revision 1.30  2004/12/17 22:06:32  grantsmith
   * Jira MYFACES-57: Changed logging levels to DEBUG from INFO
   *
   * Revision 1.29  2004/10/24 23:30:35  oros
   * do not convert newline to <br> and space to &nbps; as this is not required by the spec
   *
   * Revision 1.28  2004/10/13 11:51:00  matze
   * renamed packages to org.apache
   *
   * Revision 1.27  2004/10/05 08:49:15  manolito
   * #1038697 h:selectOneRadio generates malformed XHTML
   *
   * Revision 1.26  2004/10/05 08:32:23  manolito
   * #1038716 Empty h:selectManyCheckbox generates malformed HTML
   *
   * Revision 1.25  2004/09/09 13:15:44  manolito
   * For textareas we must *not* map successive spaces to nbsp
   *
   * Revision 1.24  2004/09/08 15:23:10  manolito
   * Autoscroll feature
   *
   * Revision 1.23  2004/09/08 09:30:01  manolito
   * moved javascript detection to ResponseWriter
   *
   * Revision 1.22  2004/08/20 00:13:55  dave0000
   * remove unused constant
   *
   * Revision 1.21  2004/08/18 17:56:58  manolito
   * no newline to <br/> mapping for TEXTAREA elements
   *
   * Revision 1.20  2004/08/18 16:13:06  manolito
   * writeText method in HtmlResponseWriterImpl now encodes Newlines and successive spaces
   *
   * Revision 1.19  2004/07/01 22:05:06  mwessendorf
   * ASF switch
   *
   * Revision 1.18  2004/04/29 14:59:42  manolito
   * writeURIAttribute no longer adds state saving url parameters
   *
   */
  public class HtmlResponseWriterImpl
          extends ResponseWriter
          implements DummyFormResponseWriter
  {
      private static final Log log = LogFactory.getLog(HtmlResponseWriterImpl.class);
  
      private static final String DEFAULT_CONTENT_TYPE = "text/html";
      private static final String DEFAULT_CHARACTER_ENCODING = "ISO-8859-1";
  
      private boolean _writeDummyForm = false;
      private Set _dummyFormParams = null;
  
      private Writer _writer;
      private String _contentType;
      private String _characterEncoding;
      private String _startElementName;
      private UIComponent _startElementUIComponent;
      private boolean _startTagOpen;
  
      private static final Set s_emptyHtmlElements = new HashSet();
  
      static
      {
          s_emptyHtmlElements.add("area");
          s_emptyHtmlElements.add("br");
          s_emptyHtmlElements.add("base");
          s_emptyHtmlElements.add("basefont");
          s_emptyHtmlElements.add("col");
          s_emptyHtmlElements.add("frame");
          s_emptyHtmlElements.add("hr");
          s_emptyHtmlElements.add("img");
          s_emptyHtmlElements.add("input");
          s_emptyHtmlElements.add("isindex");
          s_emptyHtmlElements.add("link");
          s_emptyHtmlElements.add("meta");
          s_emptyHtmlElements.add("param");
      }
  
      public HtmlResponseWriterImpl(Writer writer, String contentType, String characterEncoding)
      {
          _writer = writer;
          _contentType = contentType;
          if (_contentType == null)
          {
              if (log.isInfoEnabled()) log.debug("No content type given, using default content type " + DEFAULT_CONTENT_TYPE);
              _contentType = DEFAULT_CONTENT_TYPE;
          }
          _characterEncoding = characterEncoding;
          if (_characterEncoding == null)
          {
              if (log.isInfoEnabled()) log.debug("No character encoding given, using default character encoding " + DEFAULT_CHARACTER_ENCODING);
              _characterEncoding = DEFAULT_CHARACTER_ENCODING;
          }
      }
  
      public static boolean supportsContentType(String contentType)
      {
          //return SUPPORTED_CONTENT_TYPES.contains(contentType);   //TODO: Match according to Section 14.1 of RFC 2616
          return true;
      }
  
      public String getContentType()
      {
          return _contentType;
      }
  
      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
      {
          flush();
          if (_writeDummyForm)
          {
              DummyFormUtils.writeDummyForm(this, _dummyFormParams);
          }
  
          FacesContext facesContext = FacesContext.getCurrentInstance();
          MyfacesConfig myfacesConfig = MyfacesConfig.getCurrentInstance(facesContext.getExternalContext());
          if (myfacesConfig.isDetectJavascript())
          {
              if (! JavascriptUtils.isJavascriptDetected(facesContext.getExternalContext()))
              {
                  write("<script type=\"text/javascript\">\n<!--\ndocument.location.replace('" + facesContext.getApplication().getViewHandler().getResourceURL(facesContext, "/_javascriptDetector_")  + "?goto=" + facesContext.getApplication().getViewHandler().getActionURL(facesContext, facesContext.getViewRoot().getViewId()) +"');\n//-->\n</script>");
              }
          }
  
          if (myfacesConfig.isAutoScroll())
          {
              JavascriptUtils.renderAutoScrollFunction(facesContext, this);
          }
  
          _writer.flush();
      }
  
      public void startElement(String name, UIComponent uiComponent) throws IOException
      {
          if (name == null)
          {
              throw new NullPointerException("elementName name must not be null");
          }
  
          closeStartTagIfNecessary();
          _writer.write('<');
          _writer.write(name);
          _startElementName = name;
          _startElementUIComponent = uiComponent;
          _startTagOpen = true;
      }
  
      private void closeStartTagIfNecessary() throws IOException
      {
          if (_startTagOpen)
          {
              if (s_emptyHtmlElements.contains(_startElementName.toLowerCase()))
              {
                  _writer.write("/>");
                  // make null, this will cause NullPointer in some invalid element nestings
                  // (better than doing nothing)
                  _startElementName = null;
              }
              else
              {
                  _writer.write('>');
              }
              _startTagOpen = false;
          }
      }
  
      public void endElement(String name) throws IOException
      {
          if (name == null)
          {
              throw new NullPointerException("elementName name must not be null");
          }
  
          if (log.isWarnEnabled())
          {
              if (_startElementName != null &&
                  !name.equals(_startElementName))
              {
                  if (log.isWarnEnabled())
                      log.warn("HTML nesting warning on closing " + name + ": element " + _startElementName +
                              (_startElementUIComponent==null?"":(" rendered by component : "+
                              RendererUtils.getPathToComponent(_startElementUIComponent)))+" not explicitly closed");
              }
          }
  
          if(_startTagOpen)
          {
              // we will get here only if no text or attribute was written after the start element was opened
              if (s_emptyHtmlElements.contains(name.toLowerCase()))
              {
                  _writer.write("/>");
              }
              else
              {
                  _writer.write("></");
                  _writer.write(name);
                  _writer.write('>');
              }
              _startTagOpen = false;
          }
          else
          {
              if (s_emptyHtmlElements.contains(name.toLowerCase()))
              {
                  if (log.isWarnEnabled())
                      log.warn("HTML nesting warning on closing " + name + ": This element must not contain nested elements or text in HTML");
              }
              else
              {
                  _writer.write("</");
                  _writer.write(name);
                  _writer.write('>');
              }
          }
  
          _startElementName = null;
          _startElementUIComponent = null;
      }
  
      public void writeAttribute(String name, Object value, String componentPropertyName) throws IOException
      {
          if (name == null)
          {
              throw new NullPointerException("attributeName name must not be null");
          }
          if (!_startTagOpen)
          {
              throw new IllegalStateException("Must be called before the start element is closed (attribute '" + name + "')");
          }
  
          if (value instanceof Boolean)
          {
              if (((Boolean)value).booleanValue())
              {
                  // name as value for XHTML compatibility
                  _writer.write(' ');
                  _writer.write(name);
                  _writer.write("=\"");
                  _writer.write(name);
                  _writer.write('"');
              }
          }
          else
          {
              String strValue = value.toString(); //TODO: Use converter for value
              _writer.write(' ');
              _writer.write(name);
              _writer.write("=\"");
              _writer.write(HTMLEncoder.encode(strValue, false, false));
              _writer.write('"');
          }
      }
  
      public void writeURIAttribute(String name, Object value, String componentPropertyName) throws IOException
      {
          if (name == null)
          {
              throw new NullPointerException("attributeName name must not be null");
          }
          if (!_startTagOpen)
          {
              throw new IllegalStateException("Must be called before the start element is closed (attribute '" + name + "')");
          }
  
          String strValue = value.toString(); //TODO: Use converter for value?
          _writer.write(' ');
          _writer.write(name);
          _writer.write("=\"");
          if (strValue.toLowerCase().startsWith("javascript:"))
          {
              _writer.write(HTMLEncoder.encode(strValue, false, false));
          }
          else
          {
              /*
              if (_startElementName.equalsIgnoreCase(HTML.ANCHOR_ELEM) && //TODO: Also support image and button urls ?
                  name.equalsIgnoreCase(HTML.HREF_ATTR) &&
                  !strValue.startsWith("#"))
              {
                  FacesContext facesContext = FacesContext.getCurrentInstance();
                  if (facesContext.getApplication().getStateManager().isSavingStateInClient(facesContext))
                  {
                      //TODO/HACK: saving state in url depends on the work together
                      // of 3 (theoretically) pluggable components:
                      // ViewHandler, ResponseWriter and ViewTag
                      // We should try to make this HtmlResponseWriterImpl able
                      // to handle this alone!
                      if (strValue.indexOf('?') < 0)
                      {
                          strValue = strValue + '?' + JspViewHandlerImpl.URL_STATE_MARKER;
                      }
                      else
                      {
                          strValue = strValue + '&' + JspViewHandlerImpl.URL_STATE_MARKER;
                      }
                  }
              }
              */
              _writer.write(strValue);
          }
          _writer.write('"');
      }
  
      public void writeComment(Object value) throws IOException
      {
          if (value == null)
          {
              throw new NullPointerException("comment name must not be null");
          }
  
          closeStartTagIfNecessary();
          _writer.write("<!--");
          _writer.write(value.toString());    //TODO: Escaping: must not have "-->" inside!
          _writer.write("-->");
      }
  
      public void writeText(Object value, String componentPropertyName) throws IOException
      {
          if (value == null)
          {
              throw new NullPointerException("text name must not be null");
          }
  
          closeStartTagIfNecessary();
          if(value == null)
              return;
  
          String strValue = value.toString(); //TODO: Use converter for value?
  
          if (isScriptOrStyle())
          {
              _writer.write(UnicodeEncoder.encode(strValue, false, false));
          }
          else
          {
              _writer.write(HTMLEncoder.encode(strValue, false, false));
          }
      }
  
      public void writeText(char cbuf[], int off, int len) throws IOException
      {
          if (cbuf == null)
          {
              throw new NullPointerException("cbuf name must not be null");
          }
          if (cbuf.length < off + len)
          {
              throw new IndexOutOfBoundsException((off + len) + " > " + cbuf.length);
          }
  
          closeStartTagIfNecessary();
  
          if (isScriptOrStyle())
          {
              String strValue = new String(cbuf, off, len);
              _writer.write(UnicodeEncoder.encode(strValue, false, false));
          }
          else if (isTextarea())
          {
              // For textareas we must *not* map successive spaces to &nbsp or Newlines to <br/>
              // TODO: Make HTMLEncoder support char arrays directly
              String strValue = new String(cbuf, off, len);
              _writer.write(HTMLEncoder.encode(strValue, false, false));
          }
          else
          {
              // We map successive spaces to &nbsp; and Newlines to <br/>
              // TODO: Make HTMLEncoder support char arrays directly
              String strValue = new String(cbuf, off, len);
              _writer.write(HTMLEncoder.encode(strValue, true, true));
          }
      }
  
      private boolean isScriptOrStyle()
      {
          return _startElementName != null &&
                 (_startElementName.equalsIgnoreCase(HTML.SCRIPT_ELEM) ||
                  _startElementName.equalsIgnoreCase(HTML.STYLE_ELEM));
      }
  
      private boolean isTextarea()
      {
          return _startElementName != null &&
                 (_startElementName.equalsIgnoreCase(HTML.TEXTAREA_ELEM));
      }
  
  
      public ResponseWriter cloneWithWriter(Writer writer)
      {
          HtmlResponseWriterImpl newWriter
                  = new HtmlResponseWriterImpl(writer, getContentType(), getCharacterEncoding());
          newWriter._writeDummyForm = _writeDummyForm;
          newWriter._dummyFormParams = _dummyFormParams;
          return newWriter;
      }
  
  
      // Writer methods
  
      public void close() throws IOException
      {
          if (_startTagOpen)
          {
              // we will get here only if no text was written after the start element was opened
              _writer.write(" />");
          }
          _writer.close();
      }
  
      public void write(char cbuf[], int off, int len) throws IOException
      {
          closeStartTagIfNecessary();
          String strValue = new String(cbuf, off, len);
          _writer.write(UnicodeEncoder.encode(strValue, false, false));
      }
  
      public void write(int c) throws IOException
      {
          closeStartTagIfNecessary();
          _writer.write(c);
      }
  
      public void write(char cbuf[]) throws IOException
      {
          closeStartTagIfNecessary();
          String strValue = new String(cbuf);
          _writer.write(UnicodeEncoder.encode(strValue, false, false));
      }
  
      public void write(String str) throws IOException
      {
          closeStartTagIfNecessary();
          // empty string commonly used to force the start tag to be closed.
          // in such case, do not call down the writer chain
          if (str.length() > 0)
          {
              _writer.write(UnicodeEncoder.encode(str, false, false));
          }
      }
  
      public void write(String str, int off, int len) throws IOException
      {
          closeStartTagIfNecessary();
          String strValue = str.substring(off, off+len);
          _writer.write(UnicodeEncoder.encode(strValue, false, false));
      }
  
      // DummyFormResponseWriter support
  
      public void setWriteDummyForm(boolean writeDummyForm)
      {
          _writeDummyForm = writeDummyForm;
      }
  
      public String getDummyFormName()
      {
          return DummyFormUtils.DUMMY_FORM_NAME;
      }
  
      public void addDummyFormParameter(String paramName)
      {
          if (_dummyFormParams == null)
          {
              _dummyFormParams = new HashSet();
          }
          _dummyFormParams.add(paramName);
      }
      
      public Set getDummyFormParams()
      {
          return _dummyFormParams;
      }
  }