You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by mm...@apache.org on 2007/02/25 09:10:55 UTC

svn commit: r511461 [1/3] - in /myfaces: core/trunk/api/src/main/java/javax/faces/webapp/ core/trunk/impl/src/main/java/org/apache/myfaces/application/ core/trunk/impl/src/main/java/org/apache/myfaces/application/pss/ core/trunk/impl/src/main/java/org/...

Author: mmarinschek
Date: Sun Feb 25 00:10:54 2007
New Revision: 511461

URL: http://svn.apache.org/viewvc?view=rev&rev=511461
Log:
partial state saving improvement

Added:
    myfaces/core/trunk/api/src/main/java/javax/faces/webapp/_DummyPageContextOutWriter.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/pss/
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/pss/BufferedStringWriter.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/pss/EncodeAllComponentUtil.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/pss/FastStringWriter.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/pss/PartialTreeStructureManager.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/pss/PssJspStateManagerImpl.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/pss/PssJspViewHandlerImpl.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/pss/TempServletOutputStream.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/pss/TreeStructComponent.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/pss/UIViewRootWrapper.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/pss/ViewHandlerResponseWrapperHelperImpl.java
Modified:
    myfaces/core/trunk/api/src/main/java/javax/faces/webapp/UIComponentTag.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/NavigationHandlerImpl.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/context/portlet/PortletExternalContextImpl.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/context/servlet/ServletExternalContextImpl.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/taglib/core/ViewTag.java
    myfaces/shared/trunk/core/src/main/java/org/apache/myfaces/shared/renderkit/html/HtmlResponseWriterImpl.java
    myfaces/tomahawk/trunk/examples/simple/src/main/webapp/WEB-INF/web.xml

Modified: myfaces/core/trunk/api/src/main/java/javax/faces/webapp/UIComponentTag.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/api/src/main/java/javax/faces/webapp/UIComponentTag.java?view=diff&rev=511461&r1=511460&r2=511461
==============================================================================
--- myfaces/core/trunk/api/src/main/java/javax/faces/webapp/UIComponentTag.java (original)
+++ myfaces/core/trunk/api/src/main/java/javax/faces/webapp/UIComponentTag.java Sun Feb 25 00:10:54 2007
@@ -26,6 +26,7 @@
 import javax.faces.application.Application;
 import javax.faces.component.UIComponent;
 import javax.faces.component.UIViewRoot;
+import javax.faces.component.UIOutput;
 import javax.faces.context.FacesContext;
 import javax.faces.context.ResponseWriter;
 import javax.faces.context.ExternalContext;
@@ -35,8 +36,11 @@
 
 import javax.servlet.jsp.JspException;
 import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.JspWriter;
 import javax.servlet.jsp.tagext.Tag;
+import javax.servlet.jsp.tagext.BodyContent;
 import java.io.IOException;
+import java.io.Reader;
 import java.util.*;
 
 /**
@@ -63,6 +67,12 @@
 
     private static final String UNIQUE_ID_COUNTER_ATTR = UIComponentTag.class.getName() + ".UNIQUE_ID_COUNTER";
 
+    private static final String PARTIAL_STATE_SAVING_METHOD_PARAM_NAME = "javax.faces.PARTIAL_STATE_SAVING_METHOD";
+    private static final String PARTIAL_STATE_SAVING_METHOD_ON = "true";
+    private static final String PARTIAL_STATE_SAVING_METHOD_OFF = "false";
+
+    private static final String BEFORE_VIEW_CONTEXT = "org.apache.myfaces.BEFORE_VIEW_CONTEXT";
+
     protected PageContext pageContext = null;
     private Tag _parent = null;
 
@@ -78,8 +88,36 @@
     private ResponseWriter _writer = null;
     private Set _childrenAdded = null;
     private Set _facetsAdded = null;
+    private Boolean _partialStateSaving = null;
 
     private static Log log = LogFactory.getLog(UIComponentTag.class);
+    private static final int READ_LENGTH = 8000;
+
+    private boolean isPartialStateSavingOn(javax.faces.context.FacesContext context)
+    {
+        if(context == null) throw new NullPointerException("context");
+        if (_partialStateSaving != null) return _partialStateSaving.booleanValue();
+        String stateSavingMethod = context.getExternalContext().getInitParameter(PARTIAL_STATE_SAVING_METHOD_PARAM_NAME);
+        if (stateSavingMethod == null)
+        {
+            _partialStateSaving = Boolean.FALSE; //Specs 10.1.3: default server saving
+            context.getExternalContext().log("No partial state saving method defined, assuming default partial state saving methode off.");
+        }
+        else if (stateSavingMethod.equals(PARTIAL_STATE_SAVING_METHOD_ON))
+        {
+            _partialStateSaving = Boolean.TRUE;
+        }
+        else if (stateSavingMethod.equals(PARTIAL_STATE_SAVING_METHOD_OFF))
+        {
+            _partialStateSaving = Boolean.FALSE;
+        }
+        else
+        {
+            _partialStateSaving = Boolean.FALSE; //Specs 10.1.3: default server saving
+            context.getExternalContext().log("Illegal partial state saving method '" + stateSavingMethod + "', default partial state saving will be used (partial state saving off).");
+        }
+        return _partialStateSaving.booleanValue();
+    }
 
 
     public UIComponentTag()
@@ -297,6 +335,116 @@
     }
 
     /**
+     * Flushes the Writer and adds the content of the Writer ( which is only the direct output
+     * of the JSP if the component uses a dummyWriter wich does not render the Component itself) as
+     * UIOutput component after the current component to the myfaces component tree.
+     * @param writerToFlush
+     * @throws JspException
+     * @throws IOException
+     */
+
+    private void flushWriter( JspWriter writerToFlush ) throws JspException,IOException {
+
+      if (getFacesContext() == null)
+            return;
+      BodyContent tempwriter;
+      _componentInstance = findComponent(_facesContext);
+      if (writerToFlush instanceof BodyContent)
+        {
+            int count = 0;
+            char [] readChars = new char[READ_LENGTH];
+            tempwriter = (BodyContent) writerToFlush;
+            Reader read =tempwriter.getReader();
+            count = read.read(readChars,0,READ_LENGTH);
+            String readString = new String(readChars,0,count);
+            if(!readString.trim().equals(""))
+            {
+                //_componentInstance = findComponent(_facesContext);
+                UIComponentTag parentTag = getParentUIComponentTag(pageContext);
+                addOutputComponentAfterComponent(parentTag,createUIOutputComponentFromString(readString),_componentInstance);
+                tempwriter.clearBody();
+            }
+
+        }
+        else
+      {
+          if (_componentInstance.getParent() == null) {
+            writerToFlush.flush();
+            String beforeViewContent = _facesContext.getExternalContext().getResponse().toString();
+            if((beforeViewContent != null)&&(!beforeViewContent.trim().equals("")))
+            {   // BEFORE BODY CONTENT
+                _facesContext.getExternalContext().getRequestMap().put(BEFORE_VIEW_CONTEXT,beforeViewContent);
+            }
+          }
+      }
+
+    }
+
+    /**
+     * Adds an Output Component afert a given component.
+     * @param parentTag the parent tag of the component.
+     * @param outputComponent the component which should be added after this component.
+     * @param component the component after witch the outputComponent should be added.
+     */
+    private void addOutputComponentAfterComponent(UIComponentTag parentTag,
+                                                  UIComponent outputComponent,
+                                                  UIComponent component) {
+	int indexOfComponentInParent = 0;
+	UIComponent parent = component.getParent();
+
+	if (null == parent) {
+	    return;
+	}
+	List children = parent.getChildren();
+	indexOfComponentInParent = children.indexOf(component);
+	if (children.size() - 1 == indexOfComponentInParent) {
+	    children.add(outputComponent);
+	}
+	else {
+	    children.add(indexOfComponentInParent + 1, outputComponent);
+	}
+    parentTag.addChildIdToParentTag(parentTag,outputComponent.getId());
+
+    }
+
+
+    /**
+     * Creates a UIOutput component and fill in the content. The attribute
+     * escape will be set to false. The content will be renderd as it is.
+     * @param content the content of the UIOutput component.
+     * @return A UIOutput component with the content an the attribute escape
+     *         set to false.
+     */
+     private UIComponent createUIOutputComponentFromString( String content) {
+         UIOutput outputComponent = null;
+
+         outputComponent = createUIOutputComponent(getFacesContext());
+         outputComponent.setValue(content);
+
+         return outputComponent;
+     }
+
+
+    /**
+     * Creates a UIOutput component with the attribute escape = false. The Value
+     * of the Component will be rendert as it is, which is useful if there are html tags
+     * which should be injectet into the component tree.
+     * @param context the Myfaces Context.
+     * @return A UIOutput Component with escape = false. The String of this Component
+     *         will be rendert as it is.
+     */
+     private UIOutput createUIOutputComponent(FacesContext context) {
+         if (context == null) return null;
+         UIOutput outputComponent = null;
+         Application application = context.getApplication();
+         outputComponent = (UIOutput) application.createComponent("javax.faces.HtmlOutputText");
+         outputComponent.setTransient(true);
+         outputComponent.getAttributes().put("escape", Boolean.FALSE);
+         outputComponent.setId(context.getViewRoot().createUniqueId());
+         return outputComponent;
+     }
+
+    /**
      * Invoked by the standard jsp processing mechanism when the opening
      * tag of a JSF component element is found.
      * <p>
@@ -312,6 +460,15 @@
     {
         setupResponseWriter();
         FacesContext facesContext = getFacesContext();
+        if ( isPartialStateSavingOn(facesContext) )
+        {
+            JspWriter writer = pageContext.getOut();
+            try {
+                flushWriter(writer);
+            } catch (IOException e) {
+                log.error(e.toString());
+            }
+        }
         UIComponent component = findComponent(facesContext);
         if (!component.getRendersChildren() && !isSuppressed())
         {
@@ -349,6 +506,21 @@
     public int doEndTag()
             throws JspException
     {
+        if (isPartialStateSavingOn(getFacesContext()))
+        {
+            JspWriter writerToFlush =   pageContext.getOut();
+            if (_componentInstance == null) {
+                findComponent(getFacesContext());
+            }
+            if ((!(writerToFlush instanceof BodyContent)) && _componentInstance.getParent() == null) {
+                //add the before view content to the UIViewRoot
+                _componentInstance.getChildren().add(0,
+                        createUIOutputComponentFromString((String)
+                                _facesContext.getExternalContext().getRequestMap().get(BEFORE_VIEW_CONTEXT)));
+                _facesContext.getExternalContext().getRequestMap().remove(BEFORE_VIEW_CONTEXT);
+            }
+        }
+
         popTag();
         UIComponent component = getComponentInstance();
         removeFormerChildren(component);
@@ -937,9 +1109,16 @@
             RenderKit renderKit = renderFactory.getRenderKit(facesContext,
                                                              facesContext.getViewRoot().getRenderKitId());
 
-            _writer = renderKit.createResponseWriter(new _PageContextOutWriter(pageContext),
-                                                     null /*Default: get the allowed content-types from the accept-header*/,
-                                                     pageContext.getRequest().getCharacterEncoding());
+            if (isPartialStateSavingOn(facesContext)) {
+                    _writer = renderKit.createResponseWriter(new _DummyPageContextOutWriter(pageContext),
+                                                             null /*Default: get the allowed content-types from the accept-header*/,
+                                                             pageContext.getRequest().getCharacterEncoding());
+            } else {
+                    _writer = renderKit.createResponseWriter(new _PageContextOutWriter(pageContext),
+                                                             null /*Default: get the allowed content-types from the accept-header*/,
+                                                             pageContext.getRequest().getCharacterEncoding());
+
+            }
             facesContext.setResponseWriter(_writer);
         }
     }

Added: myfaces/core/trunk/api/src/main/java/javax/faces/webapp/_DummyPageContextOutWriter.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/api/src/main/java/javax/faces/webapp/_DummyPageContextOutWriter.java?view=auto&rev=511461
==============================================================================
--- myfaces/core/trunk/api/src/main/java/javax/faces/webapp/_DummyPageContextOutWriter.java (added)
+++ myfaces/core/trunk/api/src/main/java/javax/faces/webapp/_DummyPageContextOutWriter.java Sun Feb 25 00:10:54 2007
@@ -0,0 +1,73 @@
+/*
+ * 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 javax.faces.webapp;
+
+import javax.servlet.jsp.PageContext;
+import java.io.Writer;
+import java.io.IOException;
+
+/**
+ * This Writer is a dummy Writer.
+ *
+ * @author Martin Haimberger
+ */
+class _DummyPageContextOutWriter
+        extends Writer
+{
+    private PageContext _pageContext;
+
+    public _DummyPageContextOutWriter(PageContext pageContext)
+    {
+        _pageContext = pageContext;
+    }
+
+    public void close() throws IOException
+    {
+
+    }
+
+    public void flush() throws IOException
+    {
+
+    }
+
+    public void write(char cbuf[], int off, int len) throws IOException
+    {
+
+    }
+
+    public void write(int c) throws IOException
+    {
+
+    }
+
+    public void write(char cbuf[]) throws IOException
+    {
+
+    }
+
+    public void write(String str) throws IOException
+    {
+
+    }
+
+    public void write(String str, int off, int len) throws IOException
+    {
+        
+    }
+
+}

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/NavigationHandlerImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/NavigationHandlerImpl.java?view=diff&rev=511461&r1=511460&r2=511461
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/NavigationHandlerImpl.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/NavigationHandlerImpl.java Sun Feb 25 00:10:54 2007
@@ -52,8 +52,39 @@
     extends NavigationHandler
 {
     private static final Log log = LogFactory.getLog(NavigationHandlerImpl.class);
+    private static final String PARTIAL_STATE_SAVING_METHOD_PARAM_NAME = "javax.faces.PARTIAL_STATE_SAVING_METHOD";
+    private static final String PARTIAL_STATE_SAVING_METHOD_ON = "true";
+    private static final String PARTIAL_STATE_SAVING_METHOD_OFF = "false";
 
     private static final String ASTERISK = "*";
+    private Boolean _partialStateSaving = null;
+
+    private boolean isPartialStateSavingOn(javax.faces.context.FacesContext context)
+    {
+        if(context == null) throw new NullPointerException("context");
+        if (_partialStateSaving != null) return _partialStateSaving.booleanValue();
+        String stateSavingMethod = context.getExternalContext().getInitParameter(PARTIAL_STATE_SAVING_METHOD_PARAM_NAME);
+        if (stateSavingMethod == null)
+        {
+            _partialStateSaving = Boolean.FALSE; //Specs 10.1.3: default server saving
+            context.getExternalContext().log("No partial state saving method defined, assuming default partial state saving methode off.");
+        }
+        else if (stateSavingMethod.equals(PARTIAL_STATE_SAVING_METHOD_ON))
+        {
+            _partialStateSaving = Boolean.TRUE;
+        }
+        else if (stateSavingMethod.equals(PARTIAL_STATE_SAVING_METHOD_OFF))
+        {
+            _partialStateSaving = Boolean.FALSE;
+        }
+        else
+        {
+            _partialStateSaving = Boolean.FALSE; //Specs 10.1.3: default server saving
+            context.getExternalContext().log("Illegal partial state saving method '" + stateSavingMethod + "', default partial state saving will be used (partial state saving off).");
+        }
+        return _partialStateSaving.booleanValue();
+    }
+
 
     private Map _navigationCases = null;
     private List _wildcardKeys = new ArrayList();
@@ -102,7 +133,12 @@
                 ViewHandler viewHandler = facesContext.getApplication().getViewHandler();
                 //create new view
                 String newViewId = navigationCase.getToViewId();
-                UIViewRoot viewRoot = viewHandler.createView(facesContext, newViewId);
+                UIViewRoot viewRoot = null;
+                if (isPartialStateSavingOn(facesContext)) {
+                    viewRoot = viewHandler.restoreView(facesContext,newViewId);
+                } else {
+                    viewRoot = viewHandler.createView(facesContext, newViewId);
+                }
                 facesContext.setViewRoot(viewRoot);
                 facesContext.renderResponse();
             }

Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/pss/BufferedStringWriter.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/pss/BufferedStringWriter.java?view=auto&rev=511461
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/pss/BufferedStringWriter.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/pss/BufferedStringWriter.java Sun Feb 25 00:10:54 2007
@@ -0,0 +1,123 @@
+/*
+ * 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.application.pss;
+
+import org.apache.myfaces.application.jsp.JspViewHandlerImpl;
+import org.apache.myfaces.application.MyfacesStateManager;
+import org.apache.myfaces.shared_impl.renderkit.html.HtmlLinkRendererBase;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import javax.faces.context.FacesContext;
+import javax.faces.context.ResponseWriter;
+import javax.faces.application.StateManager;
+import java.io.Writer;
+import java.io.IOException;
+
+/**
+ * @author Martin Haimberger
+ */
+public class BufferedStringWriter extends FastStringWriter {
+
+        private static final Log log = LogFactory.getLog(BufferedStringWriter.class);
+
+        public BufferedStringWriter(FacesContext context, int initialCapcity) {
+            super(initialCapcity);
+        }
+
+        /**
+         * flushes the content of this writer to the given writer.
+         * @param writer the content of this writer is written to the given writer
+         * @throws IOException IOException
+         */
+        public void flushToWriter(Writer writer) throws IOException {
+
+
+                FacesContext facesContext = FacesContext.getCurrentInstance();
+                StateManager stateManager = facesContext.getApplication().getStateManager();
+                StateManager.SerializedView serializedView
+                        = stateManager.saveSerializedView(facesContext);
+                if (serializedView != null)
+                {
+                    //until now we have written to a buffer
+                    ResponseWriter bufferWriter = facesContext.getResponseWriter();
+                    bufferWriter.flush();
+                    //now we switch to real output
+                    ResponseWriter realWriter = bufferWriter.cloneWithWriter(writer);
+                    facesContext.setResponseWriter(realWriter);
+
+                    String bodyStr = _buffer.toString();
+                    //if ( stateManager.isSavingStateInClient(facesContext) )
+                    //{
+                        int form_marker = bodyStr.indexOf(JspViewHandlerImpl.FORM_STATE_MARKER);
+                        int url_marker = bodyStr.indexOf(HtmlLinkRendererBase.URL_STATE_MARKER);
+                        int lastMarkerEnd = 0;
+                        while (form_marker != -1 || url_marker != -1)
+                        {
+                            if (url_marker == -1 || (form_marker != -1 && form_marker < url_marker))
+                            {
+                                //replace form_marker
+                                realWriter.write(bodyStr, lastMarkerEnd, form_marker - lastMarkerEnd);
+                                stateManager.writeState(facesContext, serializedView);
+                                lastMarkerEnd = form_marker + JspViewHandlerImpl.FORM_STATE_MARKER_LEN;
+                                form_marker = bodyStr.indexOf(JspViewHandlerImpl.FORM_STATE_MARKER, lastMarkerEnd);
+                            }
+                            else
+                            {
+                                //replace url_marker
+                                realWriter.write(bodyStr, lastMarkerEnd, url_marker - lastMarkerEnd);
+                                if (stateManager instanceof MyfacesStateManager)
+                                {
+                                    ((MyfacesStateManager)stateManager).writeStateAsUrlParams(facesContext,
+                                                                                              serializedView);
+                                }
+                                else
+                                {
+                                    log.error("Current StateManager is no MyfacesStateManager and does not support saving state in url parameters.");
+                                }
+                                lastMarkerEnd = url_marker + HtmlLinkRendererBase.URL_STATE_MARKER_LEN;
+                                url_marker = bodyStr.indexOf(HtmlLinkRendererBase.URL_STATE_MARKER, lastMarkerEnd);
+                            }
+                        }
+                        realWriter.write(bodyStr, lastMarkerEnd, bodyStr.length() - lastMarkerEnd);
+                    /*}
+                    else
+                    {
+                        realWriter.write( bodyStr );
+                    } */
+                }
+                else
+                {
+                     // Save state in Server Session ... only write out the content
+                    ResponseWriter bufferWriter = facesContext.getResponseWriter();
+                    bufferWriter.flush();
+                    //now we switch to real output
+                    ResponseWriter realWriter = bufferWriter.cloneWithWriter(writer);
+                    facesContext.setResponseWriter(realWriter);
+
+                    String bodyStr = _buffer.toString();
+
+                    realWriter.write( bodyStr );
+                }
+        }
+
+        public int length() {
+            return _buffer.length();
+        }
+
+
+    }
\ No newline at end of file

Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/pss/EncodeAllComponentUtil.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/pss/EncodeAllComponentUtil.java?view=auto&rev=511461
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/pss/EncodeAllComponentUtil.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/pss/EncodeAllComponentUtil.java Sun Feb 25 00:10:54 2007
@@ -0,0 +1,45 @@
+package org.apache.myfaces.application.pss;
+
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import java.io.IOException;
+import java.util.Iterator;
+
+/**
+ * @author Martin Haimberger
+ */
+public class EncodeAllComponentUtil {
+    /**
+     * ensure that this util class can not be instanciated
+     */
+    private EncodeAllComponentUtil(){}
+
+    /**
+     * Encodes a whole UI-Component Tree or a part of the tree.
+     * @param context The facescontext
+     * @param component The base of the tree or the part or the tree
+     * @throws IOException thrown Exception
+     */
+
+    public static void encodeAll(FacesContext context, UIComponent component)
+    throws IOException
+    {
+        if (!component.isRendered()) {
+            return;
+        }
+
+        component.encodeBegin(context);
+        if (component.getRendersChildren()) {
+            component.encodeChildren(context);
+        }
+        else if (component.getChildCount() > 0) {
+                Iterator kids = component.getChildren().iterator();
+                while (kids.hasNext()) {
+                    UIComponent kid = (UIComponent) kids.next();
+                    encodeAll(context,kid);
+                }
+            }
+
+        component.encodeEnd(context);
+    }
+}

Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/pss/FastStringWriter.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/pss/FastStringWriter.java?view=auto&rev=511461
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/pss/FastStringWriter.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/pss/FastStringWriter.java Sun Feb 25 00:10:54 2007
@@ -0,0 +1,98 @@
+/*
+ * 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.application.pss;
+
+/**
+ * @author Martin Haimberger
+ */
+import java.io.IOException;
+import java.io.Writer;
+
+public class FastStringWriter extends Writer {
+
+    protected StringBuffer _buffer;
+
+    // ------------------------------------------------------------ Constructors
+
+    /**
+     * <p>Constructs a new <code>FastStringWriter</code> instance
+     * using the default capacity of <code>16</code>.</p>
+     */
+    public FastStringWriter() {
+        _buffer = new StringBuffer();
+    }
+
+    /**
+     * <p>Constructs a new <code>FastStringWriter</code> instance
+     * using the specified <code>initialCapacity</code>.</p>
+     *
+     * @param initialCapacity specifies the initial capacity of the buffer
+     *
+     * @throws IllegalArgumentException if initialCapacity is less than zero
+     */
+    public FastStringWriter(int initialCapacity) {
+        if (initialCapacity < 0) {
+            throw new IllegalArgumentException();
+        }
+        _buffer = new StringBuffer(initialCapacity);
+    }
+
+    // ----------------------------------------------------- Methods from Writer
+
+    public void write(char cbuf[], int off, int len) throws IOException {
+        if ((off < 0) || (off > cbuf.length) || (len < 0) ||
+            ((off + len) > cbuf.length) || ((off + len) < 0)) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return;
+        }
+        _buffer.append(cbuf, off, len);
+    }
+
+     /**
+      * noop
+      * @throws IOException
+      */
+    public void flush() throws IOException {
+    }
+
+    /**
+     * noop
+     * @throws IOException
+     */
+    public void close() throws IOException {
+    }
+
+    // ---------------------------------------------------------- Public Methods
+
+    public void write(String str) {
+        write(str, 0, str.length());
+    }
+
+    public void write(String str, int off, int len) {
+        _buffer.append(str.substring(off, off + len));
+    }
+
+    public StringBuffer getBuffer() {
+        return _buffer;
+    }
+
+    public String toString() {
+        return _buffer.toString();
+    }
+
+}
\ No newline at end of file

Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/pss/PartialTreeStructureManager.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/pss/PartialTreeStructureManager.java?view=auto&rev=511461
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/pss/PartialTreeStructureManager.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/pss/PartialTreeStructureManager.java Sun Feb 25 00:10:54 2007
@@ -0,0 +1,300 @@
+/*
+ * 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.application.pss;
+
+import org.apache.myfaces.shared_impl.util.ClassUtils;
+
+import javax.faces.component.UIViewRoot;
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import java.util.*;
+
+/**
+ * @author Martin Haimberger
+ */
+public class PartialTreeStructureManager
+{
+    public static final String PARTIAL_STATE_CLASS_IDS = PartialTreeStructureManager.class.getName() + ".PARTIAL_STATE_MANAGER_COMPONENT_IDS";
+
+    private FacesContext _facesContext;
+
+    public PartialTreeStructureManager(FacesContext facesContext)
+    {
+        _facesContext = facesContext;
+    }
+
+    public Object buildTreeStructureToSave(UIViewRoot viewRoot, FacesContext facesContext)
+    {
+        Object savedStateTree = viewRoot.processSaveState(facesContext);
+        if (viewRoot instanceof UIViewRootWrapper) {
+            // the first call ... all components have to be saved in the template
+           return internalBuildInitalTreeStructureToSave(viewRoot,facesContext, savedStateTree,0);
+        }
+        else return internalBuildTreeStructureToSave(viewRoot,facesContext, savedStateTree,0);
+    }
+
+    private TreeStructComponent internalBuildInitalTreeStructureToSave(UIComponent component,FacesContext facesContext, Object state, int childIndex)
+    {
+
+        Object myState = null;
+        Map facetStateMap = null;
+        List childrenStateList = null;
+
+
+        if (state != null)
+        {
+            myState = ((Object[])state)[0];
+            facetStateMap = (Map)((Object[])state)[1];
+            childrenStateList = (List)((Object[])state)[2];
+        }
+        else
+        {
+
+        }
+        TreeStructComponent structComp = new TreeStructComponent(convertStringToComponentClassId(facesContext,component.getClass().getName()),
+                                                                      component.getId(),myState,component.isTransient());
+
+        //children
+        if (component.getChildCount() > 0)
+        {
+            List childList = component.getChildren();
+            List structChildList = new ArrayList();
+            for (int i = 0, len = childList.size(); i < len; i++)
+            {
+                UIComponent child = (UIComponent)childList.get(i);
+               if (!child.isTransient())
+               {
+
+                    TreeStructComponent structChild = internalBuildInitalTreeStructureToSave(child,facesContext,childrenStateList != null ? childrenStateList.get(childIndex++):null,0);
+                    structChildList.add(structChild);
+                }
+                else
+               {
+
+                   child.setTransient(false);
+                   TreeStructComponent structChild = internalBuildInitalTreeStructureToSave(child,facesContext,child.processSaveState(facesContext),0);
+                   structChildList.add(structChild);
+                   child.setTransient(true);
+
+               }
+            }
+            TreeStructComponent[] childArray = (TreeStructComponent[])structChildList.toArray(new TreeStructComponent[structChildList.size()]);
+            structComp.setChildren(childArray);
+        }
+
+        //facets
+        Map facetMap = component.getFacets();
+        if (!facetMap.isEmpty())
+        {
+            List structFacetList = new ArrayList();
+            for (Iterator it = facetMap.entrySet().iterator(); it.hasNext(); )
+            {
+                Map.Entry entry = (Map.Entry)it.next();
+                UIComponent child = (UIComponent)entry.getValue();
+                String facetName = (String)entry.getKey();
+                if (!child.isTransient())
+                {
+
+                    TreeStructComponent structChild = internalBuildInitalTreeStructureToSave(child,facesContext,facetStateMap.get(facetName),0);
+                    structFacetList.add(new Object[] {facetName, structChild});
+                }
+                else
+               {
+                   // this is a transient Component ... save it anyway
+                   child.setTransient(false);
+                   TreeStructComponent structChild = internalBuildInitalTreeStructureToSave(child,facesContext,child.processSaveState(facesContext),0);
+                   structFacetList.add(new Object[] {facetName, structChild});
+                   child.setTransient(true);
+               }
+            }
+            Object[] facetArray = structFacetList.toArray(new Object[structFacetList.size()]);
+            structComp.setFacets(facetArray);
+        }
+
+        return structComp;
+    }
+
+    private TreeStructComponent internalBuildTreeStructureToSave(UIComponent component,FacesContext facesContext, Object state, int childIndex)
+    {
+
+        Object myState = null;
+        Map facetStateMap = null;
+        List childrenStateList = null;
+
+
+        if (state != null)
+        {
+            myState = ((Object[])state)[0];
+            facetStateMap = (Map)((Object[])state)[1];
+            childrenStateList = (List)((Object[])state)[2];
+        }
+        else
+        {
+
+        }
+        TreeStructComponent structComp = new TreeStructComponent(convertStringToComponentClassId(facesContext,component.getClass().getName()),
+                                                                      component.getId(),myState,component.isTransient());
+
+        //children
+        if (component.getChildCount() > 0)
+        {
+            List childList = component.getChildren();
+            List structChildList = new ArrayList();
+            for (int i = 0, len = childList.size(); i < len; i++)
+            {
+                UIComponent child = (UIComponent)childList.get(i);
+               if (!child.isTransient())
+               {
+
+                    TreeStructComponent structChild = internalBuildTreeStructureToSave(child,facesContext,childrenStateList != null ? childrenStateList.get(childIndex++):null,0);
+                    structChildList.add(structChild);
+                }
+            }
+            TreeStructComponent[] childArray = (TreeStructComponent[])structChildList.toArray(new TreeStructComponent[structChildList.size()]);
+            structComp.setChildren(childArray);
+        }
+
+        //facets
+        Map facetMap = component.getFacets();
+        if (!facetMap.isEmpty())
+        {
+            List structFacetList = new ArrayList();
+            for (Iterator it = facetMap.entrySet().iterator(); it.hasNext(); )
+            {
+                Map.Entry entry = (Map.Entry)it.next();
+                UIComponent child = (UIComponent)entry.getValue();
+                String facetName = (String)entry.getKey();
+                if (!child.isTransient())
+                {
+
+                    TreeStructComponent structChild = internalBuildTreeStructureToSave(child,facesContext,facetStateMap.get(facetName),0);
+                    structFacetList.add(new Object[] {facetName, structChild});
+                }
+
+            }
+            Object[] facetArray = structFacetList.toArray(new Object[structFacetList.size()]);
+            structComp.setFacets(facetArray);
+        }
+
+        return structComp;
+    }
+
+
+
+    public UIViewRoot restoreTreeStructure(FacesContext facesContext,Object treeStructRoot)
+    {
+        if (treeStructRoot instanceof TreeStructComponent)
+        {
+            return (UIViewRoot)internalRestoreTreeStructure((TreeStructComponent)treeStructRoot,facesContext);
+        }
+        else
+        {
+            throw new IllegalArgumentException("TreeStructure of type " + treeStructRoot.getClass().getName() + " is not supported.");
+        }
+    }
+
+    private UIComponent internalRestoreTreeStructure(TreeStructComponent treeStructComp,FacesContext facesContext)
+    {
+        String compClass = convertComponentClassIdToString(facesContext,treeStructComp.getComponentClass());
+        String compId = treeStructComp.getComponentId();
+        UIComponent component = (UIComponent) ClassUtils.newInstance(compClass);
+        component.setId(compId);
+        component.setTransient(treeStructComp.isTransient());
+
+        //children
+        TreeStructComponent[] childArray = treeStructComp.getChildren();
+        if (childArray != null)
+        {
+            List childList = component.getChildren();
+            for (int i = 0, len = childArray.length; i < len; i++)
+            {
+                UIComponent child = internalRestoreTreeStructure(childArray[i],facesContext);
+                childList.add(child);
+            }
+        }
+
+        //facets
+        Object[] facetArray = treeStructComp.getFacets();
+        if (facetArray != null)
+        {
+            Map facetMap = component.getFacets();
+            for (int i = 0, len = facetArray.length; i < len; i++)
+            {
+                TreeStructComponent structChild = (TreeStructComponent)((Object[])facetArray[i])[1];
+                String facetName = (String)((Object[])facetArray[i])[0];
+                UIComponent child = internalRestoreTreeStructure(structChild,facesContext);
+                facetMap.put(facetName, child);
+            }
+        }
+
+
+        return component;
+    }
+
+
+
+    private String convertComponentClassIdToString(FacesContext facesContext,Integer classId){
+        Object[] idmaps = (Object[])facesContext.getExternalContext().getApplicationMap().get(PARTIAL_STATE_CLASS_IDS);
+
+        if ( idmaps== null)
+        {
+            // create on
+            idmaps = new Object[2];
+            // contains the Classid as Map
+            idmaps[0] = new HashMap();
+            idmaps[1] = new HashMap();
+            facesContext.getExternalContext().getApplicationMap().put(PARTIAL_STATE_CLASS_IDS,idmaps);
+        }
+        return (String)((HashMap)idmaps[0]).get(classId);
+    }
+
+    private Integer convertStringToComponentClassId(FacesContext facesContext,String stringToConvert){
+
+        // if it was the first time and the wrapper was use ... use the original UIViewRoot
+
+        if (stringToConvert.equalsIgnoreCase("org.apache.myfaces.application.pss.UIViewRootWrapper")) {
+            stringToConvert = "javax.faces.component.UIViewRoot";
+        }
+
+        Object[] idmaps = (Object[])facesContext.getExternalContext().getApplicationMap().get(PARTIAL_STATE_CLASS_IDS);
+
+        if ( idmaps== null)
+        {
+            // create on
+            idmaps = new Object[2];
+            // contains the Classid as Map
+            idmaps[0] = new HashMap();
+            idmaps[1] = new HashMap();
+        }
+        Integer idInMap = (Integer)((HashMap)idmaps[1]).get(stringToConvert);
+        HashMap idToStringMap=((HashMap)idmaps[0]);
+        HashMap stringToIdMap=((HashMap)idmaps[1]);
+
+        if (idInMap == null )
+        {
+            // this type is not jet registerd ... register now
+            Integer id = new Integer(stringToIdMap.size());
+
+            stringToIdMap.put(stringToConvert,id);
+            idToStringMap.put(id,stringToConvert);
+        }
+        facesContext.getExternalContext().getApplicationMap().put(PARTIAL_STATE_CLASS_IDS,idmaps);
+        return (Integer)stringToIdMap.get(stringToConvert);
+    }
+
+
+}