You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lu...@apache.org on 2012/12/06 01:57:21 UTC

svn commit: r1417719 - in /myfaces/core/trunk: api/src/main/java/javax/faces/component/ impl/src/main/java/org/apache/myfaces/application/ impl/src/main/java/org/apache/myfaces/view/facelets/ impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/...

Author: lu4242
Date: Thu Dec  6 00:57:19 2012
New Revision: 1417719

URL: http://svn.apache.org/viewvc?rev=1417719&view=rev
Log:
MYFACES-3660 Component resource added using @ResourceDependency annotation from a facelet component should have an id defined by facelets 

Added:
    myfaces/core/trunk/api/src/main/java/javax/faces/component/_ViewAttributeMap.java   (with props)
    myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/component/UIRDComponent.java   (with props)
    myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/managed/ComponentBindingBean.java   (with props)
    myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/managed/ResourceDependencyBean.java   (with props)
    myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/componentBinding1.xhtml
      - copied, changed from r1416728, myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/index.xhtml
    myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/resourceDependency1.xhtml
      - copied, changed from r1416728, myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/index.xhtml
    myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/resources/   (with props)
    myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/resources/custom.css   (with props)
Modified:
    myfaces/core/trunk/api/src/main/java/javax/faces/component/UIViewRoot.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/DefaultFaceletsStateManagementStrategy.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ComponentTagHandlerDelegate.java
    myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/mc/test/core/AbstractMyFacesTestCase.java
    myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/AcidMyFacesRequestTestCase.java
    myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/WEB-INF/testcomponent.taglib.xml

Modified: myfaces/core/trunk/api/src/main/java/javax/faces/component/UIViewRoot.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/api/src/main/java/javax/faces/component/UIViewRoot.java?rev=1417719&r1=1417718&r2=1417719&view=diff
==============================================================================
--- myfaces/core/trunk/api/src/main/java/javax/faces/component/UIViewRoot.java (original)
+++ myfaces/core/trunk/api/src/main/java/javax/faces/component/UIViewRoot.java Thu Dec  6 00:57:19 2012
@@ -116,6 +116,9 @@ public class UIViewRoot extends UICompon
     private static final String JAVAX_FACES_LOCATION_BODY = "javax_faces_location_body";
     private static final String JAVAX_FACES_LOCATION_FORM = "javax_faces_location_form";
     
+    private transient boolean _resourceDependencyUniqueId;
+    private transient Map<String,Object> _attributesMap;
+    
     /**
      * Construct an instance of the UIViewRoot.
      */
@@ -343,10 +346,20 @@ public class UIViewRoot extends UICompon
         // UNIQUE_ID_PREFIX, and will be unique within this UIViewRoot.
         if(seed==null)
         {
-            Long uniqueIdCounter = (Long) getStateHelper().get(PropertyKeys.uniqueIdCounter);
-            uniqueIdCounter = (uniqueIdCounter == null) ? 0 : uniqueIdCounter;
-            getStateHelper().put(PropertyKeys.uniqueIdCounter, (uniqueIdCounter+1L));
-            return bld.append(UNIQUE_ID_PREFIX).append(uniqueIdCounter).toString();    
+            if (isResourceDependencyUniqueId())
+            {
+                Long uniqueIdCounter = (Long) getStateHelper().get(PropertyKeys.resourceDependencyUniqueIdCounter);
+                uniqueIdCounter = (uniqueIdCounter == null) ? 0 : uniqueIdCounter;
+                getStateHelper().put(PropertyKeys.resourceDependencyUniqueIdCounter, (uniqueIdCounter+1L));
+                return bld.append(UNIQUE_ID_PREFIX).append("__rd_").append(uniqueIdCounter).toString();
+            }
+            else
+            {
+                Long uniqueIdCounter = (Long) getStateHelper().get(PropertyKeys.uniqueIdCounter);
+                uniqueIdCounter = (uniqueIdCounter == null) ? 0 : uniqueIdCounter;
+                getStateHelper().put(PropertyKeys.uniqueIdCounter, (uniqueIdCounter+1L));
+                return bld.append(UNIQUE_ID_PREFIX).append(uniqueIdCounter).toString();
+            }
         }
         // Optionally, a unique seed value can be supplied by component creators which
         // should be included in the generated unique id.
@@ -1234,6 +1247,32 @@ public class UIViewRoot extends UICompon
         getStateHelper().put(PropertyKeys.afterPhaseListener, afterPhaseListener);
     }
     
+    @Override
+    public Map<String, Object> getAttributes()
+    {
+        if (_attributesMap == null)
+        {
+            _attributesMap = new _ViewAttributeMap(this, super.getAttributes());
+        }
+        return _attributesMap;
+    }
+
+    /**
+     * Indicates if the component is created when facelets builds the view and
+     * is caused by the presence of a ResourceDependency annotation.
+     * 
+     * @return the _resourceDependencyUniqueId
+     */
+    boolean isResourceDependencyUniqueId()
+    {
+        return _resourceDependencyUniqueId;
+    }
+
+    void setResourceDependencyUniqueId(boolean resourceDependencyUniqueId)
+    {
+        this._resourceDependencyUniqueId = resourceDependencyUniqueId;
+    }
+    
     enum PropertyKeys
     {
          afterPhaseListener
@@ -1243,6 +1282,7 @@ public class UIViewRoot extends UICompon
         , renderKitId
         , viewId
         , uniqueIdCounter
+        , resourceDependencyUniqueIdCounter
     }
     
     @Override

Added: myfaces/core/trunk/api/src/main/java/javax/faces/component/_ViewAttributeMap.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/api/src/main/java/javax/faces/component/_ViewAttributeMap.java?rev=1417719&view=auto
==============================================================================
--- myfaces/core/trunk/api/src/main/java/javax/faces/component/_ViewAttributeMap.java (added)
+++ myfaces/core/trunk/api/src/main/java/javax/faces/component/_ViewAttributeMap.java Thu Dec  6 00:57:19 2012
@@ -0,0 +1,181 @@
+/*
+ * 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 javax.faces.component;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ *
+ * @author Leonardo Uribe
+ */
+class _ViewAttributeMap implements Map<String, Object>
+{
+    //private static final String RESET_SAVE_STATE_MODE_KEY = 
+    //        "oam.view.resetSaveStateMode";
+
+    /**
+     * Key under UIViewRoot to generated unique ids for components added 
+     * by @ResourceDependency effect.
+     */
+    private static final String RESOURCE_DEPENDENCY_UNIQUE_ID_KEY =
+              "oam.view.resourceDependencyUniqueId";
+    private static final String UNIQUE_ID_COUNTER_KEY =
+              "oam.view.uniqueIdCounter";
+    
+    private Map<String, Object> _delegate;
+    private UIViewRoot _root;
+
+    public _ViewAttributeMap(UIViewRoot root, Map<String, Object> delegate)
+    {
+        this._delegate = delegate;
+        this._root = root;
+    }
+
+    public int size()
+    {
+        return _delegate.size();
+    }
+
+    public boolean isEmpty()
+    {
+        return _delegate.isEmpty();
+    }
+
+    public boolean containsKey(Object key)
+    {
+        return _delegate.containsKey(key);
+    }
+
+    public boolean containsValue(Object value)
+    {
+        return _delegate.containsValue(value);
+    }
+
+    public Object get(Object key)
+    {
+        checkKey(key);
+        int keyLength = ((String)key).length();
+        /*
+        if (RESET_SAVE_STATE_MODE_KEY.length() == keyLength
+            && RESET_SAVE_STATE_MODE_KEY.equals(key))
+        {
+            return _root.getResetSaveStateMode();
+        }*/
+        if (RESOURCE_DEPENDENCY_UNIQUE_ID_KEY.length() == keyLength
+            && RESOURCE_DEPENDENCY_UNIQUE_ID_KEY.equals(key))
+        {
+            return _root.isResourceDependencyUniqueId();
+        }
+        if (UNIQUE_ID_COUNTER_KEY.length() == keyLength
+            && UNIQUE_ID_COUNTER_KEY.equals(key))
+        {
+            return _root.getStateHelper().get(UIViewRoot.PropertyKeys.uniqueIdCounter);
+        }
+        return _delegate.get(key);
+    }
+
+    public Object put(String key, Object value)
+    {
+        int keyLength = ((String)key).length();
+
+        /*
+        if (RESET_SAVE_STATE_MODE_KEY.length() == keyLength
+            && RESET_SAVE_STATE_MODE_KEY.equals(key))
+        {
+            Integer b = _root.getResetSaveStateMode();
+            _root.setResetSaveStateMode(value == null ? 0 : (Integer) value);
+            return b;
+        }*/
+        if (RESOURCE_DEPENDENCY_UNIQUE_ID_KEY.length() == keyLength
+            && RESOURCE_DEPENDENCY_UNIQUE_ID_KEY.equals(key))
+        {
+            boolean b = _root.isResourceDependencyUniqueId();
+            _root.setResourceDependencyUniqueId(value == null ? false : (Boolean) value);
+            return b;
+        }
+        if (UNIQUE_ID_COUNTER_KEY.length() == keyLength
+            && UNIQUE_ID_COUNTER_KEY.equals(key))
+        {
+            Long v = (Long) _root.getStateHelper().get(UIViewRoot.PropertyKeys.uniqueIdCounter);
+            _root.getStateHelper().put(UIViewRoot.PropertyKeys.uniqueIdCounter, value);
+            return v;
+        }
+        return _delegate.put(key, value);
+    }
+
+    public Object remove(Object key)
+    {
+        return _delegate.remove(key);
+    }
+
+    public void putAll(Map<? extends String, ? extends Object> m)
+    {
+        _delegate.putAll(m);
+    }
+
+    public void clear()
+    {
+        _delegate.clear();
+    }
+
+    public Set<String> keySet()
+    {
+        return _delegate.keySet();
+    }
+
+    public Collection<Object> values()
+    {
+        return _delegate.values();
+    }
+
+    public Set<Entry<String, Object>> entrySet()
+    {
+        return _delegate.entrySet();
+    }
+
+    public boolean equals(Object o)
+    {
+        return _delegate.equals(o);
+    }
+
+    public int hashCode()
+    {
+        return _delegate.hashCode();
+    }
+
+    public String toString()
+    {
+        return _delegate.toString();
+    }
+    
+    private void checkKey(Object key)
+    {
+        if (key == null)
+        {
+            throw new NullPointerException("key");
+        }
+        if (!(key instanceof String))
+        {
+            throw new ClassCastException("key is not a String");
+        }
+    }
+}

Propchange: myfaces/core/trunk/api/src/main/java/javax/faces/component/_ViewAttributeMap.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java?rev=1417719&r1=1417718&r2=1417719&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java Thu Dec  6 00:57:19 2012
@@ -104,6 +104,7 @@ import org.apache.myfaces.el.unified.res
 import org.apache.myfaces.lifecycle.LifecycleImpl;
 import org.apache.myfaces.shared.config.MyfacesConfig;
 import org.apache.myfaces.shared.util.ClassUtils;
+import org.apache.myfaces.view.facelets.FaceletCompositionContext;
 import org.apache.myfaces.view.facelets.el.ELText;
 
 /**
@@ -157,6 +158,14 @@ public class ApplicationImpl extends App
     private static final boolean LAZY_LOAD_CONFIG_OBJECTS_DEFAULT_VALUE = true;
     private Boolean _lazyLoadConfigObjects = null;
     
+    
+    /**
+     * Key under UIViewRoot to generated unique ids for components added 
+     * by @ResourceDependency effect.
+     */
+    private static final String RESOURCE_DEPENDENCY_UNIQUE_ID_KEY =
+              "oam.view.resourceDependencyUniqueId";
+
     // ~ Instance fields
     // --------------------------------------------------------------------------
     // --
@@ -1798,6 +1807,50 @@ public class ApplicationImpl extends App
             rvc.setClassProcessed(inspectedClass);
         }
     }
+
+    /**
+     * If the ResourceDependency component is created under facelets processing, it should receive
+     * an special unique component id. This method check if there is a FaceletCompositionContext
+     * and if that so, set the id. Components added by the effect of ResourceDependency are special,
+     * because they do not have state, but they depends on the view structure, so with PSS, 
+     * each time the view is built they are "recalculated", so they work as if they were transient
+     * components that needs to be created at each request, but there are some cases were the 
+     * components needs to be saved and restored fully. If a component is created outside facelets 
+     * control (render response phase) it is expected to use the default implementation of 
+     * createUniqueId(), but in that case, note that this happens after markInitialState() is 
+     * called, and the component in this case is saved and restored fully, as expected.
+     * 
+     * This code cannot be called from facelets component tag handler, because in cases where a
+     * component subtree is created using binding property, facelets lost control over component
+     * creation and delegates it to the user, but since the binding code is executed each time the
+     * view is created, the effect over ResourceDependency persists and the binding code takes into
+     * account in the recalculation step, even if later the node related to the binding property
+     * is dropped and recreated from the state fully. 
+     * 
+     * @param facesContext
+     * @param component 
+     */
+    private void setResourceIdOnFaceletsMode(FacesContext facesContext, UIComponent component)
+    {
+        if (component.getId() == null)
+        {
+            FaceletCompositionContext mctx = FaceletCompositionContext.getCurrentInstance(facesContext);
+            if (mctx != null)
+            {
+                UIViewRoot root = facesContext.getViewRoot();
+                root.getAttributes().put(RESOURCE_DEPENDENCY_UNIQUE_ID_KEY, Boolean.TRUE);
+                try
+                {
+                    String uid = root.createUniqueId(facesContext, null);
+                    component.setId(uid);
+                }
+                finally
+                {
+                    root.getAttributes().put(RESOURCE_DEPENDENCY_UNIQUE_ID_KEY, Boolean.FALSE);
+                }
+            }
+        }
+    }
     
     private void _handleAttachedResourceDependency(FacesContext context, ResourceDependency annotation)
     {
@@ -1826,6 +1879,10 @@ public class ApplicationImpl extends App
             // Call setRendererType on the UIOutput instance, passing the renderer-type.
             output.setRendererType(rendererType);
             
+            // If the @ResourceDependency was done inside facelets processing,
+            // call setId() and set a proper id from facelets
+            setResourceIdOnFaceletsMode(context, output);
+            
             // Obtain the Map of attributes from the UIOutput component by calling UIComponent.getAttributes().
             Map<String, Object> attributes = output.getAttributes();
             
@@ -2301,6 +2358,10 @@ public class ApplicationImpl extends App
 
             // Call setRendererType on the UIOutput instance, passing the renderer-type.
             output.setRendererType(rendererType);
+            
+            // If the @ResourceDependency was done inside facelets processing,
+            // call setId() and set a proper id from facelets
+            setResourceIdOnFaceletsMode(context, output);
 
             // Obtain the Map of attributes from the UIOutput component by calling UIComponent.getAttributes().
             Map<String, Object> attributes = output.getAttributes();

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/DefaultFaceletsStateManagementStrategy.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/DefaultFaceletsStateManagementStrategy.java?rev=1417719&r1=1417718&r2=1417719&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/DefaultFaceletsStateManagementStrategy.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/DefaultFaceletsStateManagementStrategy.java Thu Dec  6 00:57:19 2012
@@ -171,6 +171,9 @@ public class DefaultFaceletsStateManagem
     private static final Set<VisitHint> VISIT_HINTS = Collections.unmodifiableSet( 
             EnumSet.of(VisitHint.SKIP_ITERATION));
     
+    private static final String UNIQUE_ID_COUNTER_KEY =
+              "oam.view.uniqueIdCounter";
+    
     private ViewDeclarationLanguageFactory _vdlFactory;
     
     private RenderKitFactory _renderKitFactory = null;
@@ -259,8 +262,16 @@ public class DefaultFaceletsStateManagem
                     {
                         view.getAttributes().put(ComponentSupport.FACELET_STATE_INSTANCE,  faceletViewState);
                     }
+                    if (state.length == 3)
+                    {
+                        if (view.getId() == null)
+                        {
+                            view.setId(view.createUniqueId(context, null));
+                        }
+                        //Jump to where the count is
+                        view.getAttributes().put(UNIQUE_ID_COUNTER_KEY, state[2]);
+                    }
                 }
-
                 // TODO: Why is necessary enable event processing?
                 // ANS: On RestoreViewExecutor, setProcessingEvents is called first to false
                 // and then to true when postback. Since we need listeners registered to PostAddToViewEvent
@@ -291,7 +302,6 @@ public class DefaultFaceletsStateManagem
             if (state != null && state[1] != null)
             {
                 states = (Map<String, Object>) state[1];
-                
                 // Visit the children and restore their state.
                 boolean emptyState = false;
                 boolean containsFaceletState = states.containsKey(
@@ -391,7 +401,6 @@ public class DefaultFaceletsStateManagem
                         context.getAttributes().remove(FaceletViewDeclarationLanguage.REMOVING_COMPONENTS_BUILD);
                     }
                 }
-                
                 List<String> clientIdsAdded = getClientIdsAdded(view);
                 if (clientIdsAdded != null)
                 {
@@ -464,7 +473,6 @@ public class DefaultFaceletsStateManagem
                 }
             }
         }
-        
         // Restore binding, because UIViewRoot.processRestoreState() is never called
         //the event processing has to be enabled because of the restore view event triggers
         //TODO ask the EG the this is a spec violation if we do it that way
@@ -578,8 +586,12 @@ public class DefaultFaceletsStateManagem
             
             // As required by ResponseStateManager, the return value is an Object array.  First
             // element is the structure object, second is the state map.
-
-            if (states == null)
+            Long uniqueIdCount = (Long) view.getAttributes().get(UNIQUE_ID_COUNTER_KEY);
+            if (uniqueIdCount != null && !uniqueIdCount.equals(1L))
+            {
+                serializedView = new Object[] { null, states, uniqueIdCount };
+            }
+            else if (states == null)
             {
                 serializedView = EMPTY_STATES;
             }

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ComponentTagHandlerDelegate.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ComponentTagHandlerDelegate.java?rev=1417719&r1=1417718&r2=1417719&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ComponentTagHandlerDelegate.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ComponentTagHandlerDelegate.java Thu Dec  6 00:57:19 2012
@@ -50,6 +50,8 @@ import javax.faces.view.facelets.Validat
 
 import org.apache.myfaces.util.ExternalSpecifications;
 import org.apache.myfaces.view.facelets.AbstractFaceletContext;
+import org.apache.myfaces.view.facelets.ComponentState;
+import org.apache.myfaces.view.facelets.DefaultFaceletsStateManagementStrategy;
 import org.apache.myfaces.view.facelets.FaceletCompositionContext;
 import org.apache.myfaces.view.facelets.tag.MetaRulesetImpl;
 import org.apache.myfaces.view.facelets.tag.jsf.core.AjaxHandler;
@@ -435,6 +437,18 @@ public class ComponentTagHandlerDelegate
                     ComponentSupport.getViewRoot(ctx, c).getAttributes().put("oam.CALL_PRE_DISPOSE_VIEW", Boolean.TRUE);
                     c.subscribeToEvent(PreDisposeViewEvent.class, new ClearBindingValueExpressionListener());
                 }
+                
+                if (c.getChildCount() > 0 || c.getFacetCount() > 0)
+                {
+                    // In this case, this component is used to hold a subtree that is generated
+                    // dynamically. In this case, the best is mark this component to be restored
+                    // fully, because this ensures the state is correctly preserved. Note this
+                    // is only necessary when the component has additional children or facets,
+                    // because those components requires an unique id provided by createUniqueId(),
+                    // and this ensures stability of the generated ids.
+                    c.getAttributes().put(DefaultFaceletsStateManagementStrategy.COMPONENT_ADDED_AFTER_BUILD_VIEW,
+                                          ComponentState.REMOVE_ADD);
+                }
             }
         }
         else

Modified: myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/mc/test/core/AbstractMyFacesTestCase.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/mc/test/core/AbstractMyFacesTestCase.java?rev=1417719&r1=1417718&r2=1417719&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/mc/test/core/AbstractMyFacesTestCase.java (original)
+++ myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/mc/test/core/AbstractMyFacesTestCase.java Thu Dec  6 00:57:19 2012
@@ -34,13 +34,23 @@ import java.util.logging.Logger;
 import javax.el.ExpressionFactory;
 import javax.faces.FacesException;
 import javax.faces.FactoryFinder;
+import javax.faces.application.Application;
+import javax.faces.application.FacesMessage;
+import javax.faces.application.ProjectStage;
+import javax.faces.application.ViewHandler;
+import javax.faces.component.UIViewRoot;
 import javax.faces.context.ExternalContext;
 import javax.faces.context.FacesContext;
 import javax.faces.context.FacesContextFactory;
+import javax.faces.context.Flash;
+import javax.faces.event.ExceptionQueuedEvent;
+import javax.faces.event.ExceptionQueuedEventContext;
 import javax.faces.event.PhaseId;
 import javax.faces.event.PhaseListener;
+import javax.faces.event.PreRenderViewEvent;
 import javax.faces.lifecycle.Lifecycle;
 import javax.faces.lifecycle.LifecycleFactory;
+import javax.faces.view.ViewDeclarationLanguage;
 import javax.faces.webapp.FacesServlet;
 import javax.servlet.ServletContext;
 import javax.servlet.ServletContextEvent;
@@ -52,6 +62,7 @@ import org.apache.myfaces.config.Runtime
 import org.apache.myfaces.config.element.FacesConfig;
 import org.apache.myfaces.config.impl.digester.elements.Factory;
 import org.apache.myfaces.lifecycle.LifecycleImpl;
+import org.apache.myfaces.lifecycle.ViewNotFoundException;
 import org.apache.myfaces.mc.test.core.annotation.DeclareFacesConfig;
 import org.apache.myfaces.mc.test.core.annotation.ManagedBeans;
 import org.apache.myfaces.mc.test.core.annotation.PageBean;
@@ -62,6 +73,7 @@ import org.apache.myfaces.test.el.MockEx
 import org.apache.myfaces.test.mock.MockPrintWriter;
 import org.apache.myfaces.test.mock.MockServletConfig;
 import org.apache.myfaces.test.mock.MockServletContext;
+import org.apache.myfaces.util.DebugUtils;
 import org.apache.myfaces.view.facelets.FaceletViewDeclarationLanguage;
 import org.apache.myfaces.webapp.AbstractFacesInitializer;
 import org.apache.myfaces.webapp.StartupServletContextListener;
@@ -99,6 +111,13 @@ public abstract class AbstractMyFacesTes
     
     public static final String LAST_PHASE_PROCESSED = "oam.LAST_PHASE_PROCESSED";
     
+    public static final String LAST_RENDER_PHASE_STEP = "oam.LAST_RENDER_PHASE_STEP";
+    
+    public static final int BEFORE_RENDER_STEP = 1;
+    public static final int BUILD_VIEW_CYCLE_STEP = 2;
+    public static final int VIEWHANDLER_RENDER_STEP = 3;
+    public static final int AFTER_RENDER_STEP = 4;
+    
     // ------------------------------------------------------------ Constructors
 
     /**
@@ -446,6 +465,7 @@ public abstract class AbstractMyFacesTes
         processRemainingExecutePhases(facesContext);
         lifecycle.render(facesContext);
         facesContext.getAttributes().put(LAST_PHASE_PROCESSED, PhaseId.RENDER_RESPONSE);
+        facesContext.getAttributes().put(LAST_RENDER_PHASE_STEP, AFTER_RENDER_STEP);
     }
     
     protected void processRemainingExecutePhases(FacesContext facesContext) throws Exception
@@ -516,7 +536,29 @@ public abstract class AbstractMyFacesTes
             }
             if (continueProcess || PhaseId.INVOKE_APPLICATION.equals(lastPhaseId))
             {
-                processRender(facesContext);
+                Integer step = (Integer) facesContext.getAttributes().get(LAST_RENDER_PHASE_STEP);
+                if (step == null)
+                {
+                    processRender(facesContext);
+                }
+                else
+                {
+                    if (BEFORE_RENDER_STEP == step.intValue())
+                    {
+                        executeBuildViewCycle(facesContext);
+                        executeViewHandlerRender(facesContext);
+                        executeAfterRender(facesContext);
+                    }
+                    else if (BUILD_VIEW_CYCLE_STEP == step.intValue())
+                    {
+                        executeViewHandlerRender(facesContext);
+                        executeAfterRender(facesContext);
+                    }
+                    else if (VIEWHANDLER_RENDER_STEP == step.intValue())
+                    {
+                        executeAfterRender(facesContext);
+                    }
+                }
             }
         }
     }
@@ -532,6 +574,291 @@ public abstract class AbstractMyFacesTes
         return false;
     }
     
+    protected void executeBeforeRender(FacesContext facesContext) throws Exception
+    {
+        if (lifecycle instanceof LifecycleImpl)
+        {
+            LifecycleImpl lifecycleImpl = (LifecycleImpl) lifecycle;
+            
+            Object phaseExecutor = null;
+            Field renderExecutorField = lifecycleImpl.getClass().getDeclaredField("renderExecutor");
+            if (!renderExecutorField.isAccessible())
+            {
+                renderExecutorField.setAccessible(true);
+            }
+            phaseExecutor = renderExecutorField.get(lifecycleImpl);
+            
+            if (facesContext.getResponseComplete())
+            {
+                return;
+            }
+            
+            Object phaseManager = facesContext.getAttributes().get(PHASE_MANAGER_INSTANCE);
+            if (phaseManager == null)
+            {
+                Method getPhaseListenersMethod = lifecycleImpl.getClass().getDeclaredMethod("getPhaseListeners");
+                if (!getPhaseListenersMethod.isAccessible())
+                {
+                    getPhaseListenersMethod.setAccessible(true);
+                }
+                
+                Constructor<?> plmc = PHASE_MANAGER_CLASS.getDeclaredConstructor(new Class[]{Lifecycle.class, FacesContext.class, PhaseListener[].class});
+                if (!plmc.isAccessible())
+                {
+                    plmc.setAccessible(true);
+                }
+                phaseManager = plmc.newInstance(lifecycle, facesContext, getPhaseListenersMethod.invoke(lifecycleImpl, null));
+                facesContext.getAttributes().put(PHASE_MANAGER_INSTANCE, phaseManager);
+            }
+            
+            Flash flash = facesContext.getExternalContext().getFlash();
+            
+            try
+            {
+                facesContext.setCurrentPhaseId(PhaseId.RENDER_RESPONSE);
+                
+                flash.doPrePhaseActions(facesContext);
+                
+                // let the PhaseExecutor do some pre-phase actions
+                
+                //renderExecutor.doPrePhaseActions(facesContext);
+                Method doPrePhaseActionsMethod = phaseExecutor.getClass().getMethod("doPrePhaseActions", FacesContext.class);
+                if(!(doPrePhaseActionsMethod.isAccessible()))
+                {
+                    doPrePhaseActionsMethod.setAccessible(true);
+                }
+                doPrePhaseActionsMethod.invoke(phaseExecutor, facesContext);
+                
+                //phaseListenerMgr.informPhaseListenersBefore(PhaseId.RENDER_RESPONSE);
+                Method informPhaseListenersBeforeMethod = phaseManager.getClass().getDeclaredMethod("informPhaseListenersBefore", PhaseId.class);
+                if(!(informPhaseListenersBeforeMethod.isAccessible()))
+                {
+                    informPhaseListenersBeforeMethod.setAccessible(true);
+                }
+                informPhaseListenersBeforeMethod.invoke(phaseManager, PhaseId.RENDER_RESPONSE);
+                
+                // also possible that one of the listeners completed the response
+                if (facesContext.getResponseComplete())
+                {
+                    return;
+                }
+                
+                //renderExecutor.execute(facesContext);
+            }
+            
+            catch (Throwable e)
+            {
+                // JSF 2.0: publish the executor's exception (if any).
+                ExceptionQueuedEventContext context = new ExceptionQueuedEventContext (facesContext, e, null, PhaseId.RENDER_RESPONSE);
+                facesContext.getApplication().publishEvent (facesContext, ExceptionQueuedEvent.class, context);
+            }
+            
+            finally
+            {
+                /*
+                phaseListenerMgr.informPhaseListenersAfter(renderExecutor.getPhase());
+                flash.doPostPhaseActions(facesContext);
+                
+                // publish a field in the application map to indicate
+                // that the first request has been processed
+                requestProcessed(facesContext);
+                */
+            }
+            
+            facesContext.getExceptionHandler().handle();
+            
+
+            facesContext.getAttributes().remove(PHASE_MANAGER_INSTANCE);
+            
+            facesContext.getAttributes().put(LAST_RENDER_PHASE_STEP, BEFORE_RENDER_STEP);
+        }
+        else
+        {
+            throw new UnsupportedOperationException("Cannot execute phase on custom lifecycle instances");
+        }
+    }
+    
+    public void executeBuildViewCycle(FacesContext facesContext) throws Exception
+    {
+        Application application = facesContext.getApplication();
+        ViewHandler viewHandler = application.getViewHandler();
+        UIViewRoot root;
+        UIViewRoot previousRoot;
+        String viewId;
+        String newViewId;
+        boolean isNotSameRoot;
+        int loops = 0;
+        int maxLoops = 15;
+        
+        if (facesContext.getViewRoot() == null)
+        {
+            throw new ViewNotFoundException("A view is required to execute "+facesContext.getCurrentPhaseId());
+        }
+        
+        try
+        {
+            // do-while, because the view might change in PreRenderViewEvent-listeners
+            do
+            {
+                root = facesContext.getViewRoot();
+                previousRoot = root;
+                viewId = root.getViewId();
+                
+                ViewDeclarationLanguage vdl = viewHandler.getViewDeclarationLanguage(
+                        facesContext, viewId);
+                if (vdl != null)
+                {
+                    vdl.buildView(facesContext, root);
+                }
+                
+                // publish a PreRenderViewEvent: note that the event listeners
+                // of this event can change the view, so we have to perform the algorithm 
+                // until the viewId does not change when publishing this event.
+                application.publishEvent(facesContext, PreRenderViewEvent.class, root);
+                
+                // was the response marked as complete by an event listener?
+                if (facesContext.getResponseComplete())
+                {
+                    return;
+                }
+
+                root = facesContext.getViewRoot();
+                
+                newViewId = root.getViewId();
+                
+                isNotSameRoot = !( (newViewId == null ? newViewId == viewId : newViewId.equals(viewId) ) && 
+                        previousRoot.equals(root) ); 
+                
+                loops++;
+            }
+            while ((newViewId == null && viewId != null) 
+                    || (newViewId != null && (!newViewId.equals(viewId) || isNotSameRoot ) ) && loops < maxLoops);
+            
+            if (loops == maxLoops)
+            {
+                // PreRenderView reach maxLoops - probably a infinitive recursion:
+                boolean production = facesContext.isProjectStage(ProjectStage.Production);
+                /*
+                Level level = production ? Level.FINE : Level.WARNING;
+                if (log.isLoggable(level))
+                {
+                    log.log(level, "Cicle over buildView-PreRenderViewEvent on RENDER_RESPONSE phase "
+                                   + "reaches maximal limit, please check listeners for infinite recursion.");
+                }*/
+            }
+            
+            facesContext.getAttributes().put(LAST_RENDER_PHASE_STEP, BUILD_VIEW_CYCLE_STEP);
+        }
+        catch (IOException e)
+        {
+            throw new FacesException(e.getMessage(), e);
+        }
+    }
+    
+    public void executeViewHandlerRender(FacesContext facesContext)
+    {
+        Application application = facesContext.getApplication();
+        ViewHandler viewHandler = application.getViewHandler();
+
+        try
+        {
+            viewHandler.renderView(facesContext, facesContext.getViewRoot());
+            
+            // log all unhandled FacesMessages, don't swallow them
+            // perf: org.apache.myfaces.context.servlet.FacesContextImpl.getMessageList() creates
+            // new Collections.unmodifiableList with every invocation->  call it only once
+            // and messageList is RandomAccess -> use index based loop
+            List<FacesMessage> messageList = facesContext.getMessageList();
+            if (!messageList.isEmpty())
+            {
+                StringBuilder builder = new StringBuilder();
+                //boolean shouldLog = false;
+                for (int i = 0, size = messageList.size(); i < size; i++)
+                {
+                    FacesMessage message = messageList.get(i);
+                    if (!message.isRendered())
+                    {
+                        builder.append("\n- ");
+                        builder.append(message.getDetail());
+                        
+                        //shouldLog = true;
+                    }
+                }
+                /*
+                if (shouldLog)
+                {
+                    log.log(Level.WARNING, "There are some unhandled FacesMessages, " +
+                            "this means not every FacesMessage had a chance to be rendered.\n" +
+                            "These unhandled FacesMessages are: " + builder.toString());
+                }*/
+            }
+            facesContext.getAttributes().put(LAST_RENDER_PHASE_STEP, VIEWHANDLER_RENDER_STEP);
+        }
+        catch (IOException e)
+        {
+            throw new FacesException(e.getMessage(), e);
+        }
+    }
+    
+    public void executeAfterRender(FacesContext facesContext) throws Exception
+    {
+        if (lifecycle instanceof LifecycleImpl)
+        {
+            LifecycleImpl lifecycleImpl = (LifecycleImpl) lifecycle;
+            
+            Object phaseExecutor = null;
+            Field renderExecutorField = lifecycleImpl.getClass().getDeclaredField("renderExecutor");
+            if (!renderExecutorField.isAccessible())
+            {
+                renderExecutorField.setAccessible(true);
+            }
+            phaseExecutor = renderExecutorField.get(lifecycleImpl);
+            
+            Object phaseManager = facesContext.getAttributes().get(PHASE_MANAGER_INSTANCE);
+            if (phaseManager == null)
+            {
+                Method getPhaseListenersMethod = lifecycleImpl.getClass().getDeclaredMethod("getPhaseListeners");
+                if (!getPhaseListenersMethod.isAccessible())
+                {
+                    getPhaseListenersMethod.setAccessible(true);
+                }
+                
+                Constructor<?> plmc = PHASE_MANAGER_CLASS.getDeclaredConstructor(new Class[]{Lifecycle.class, FacesContext.class, PhaseListener[].class});
+                if (!plmc.isAccessible())
+                {
+                    plmc.setAccessible(true);
+                }
+                phaseManager = plmc.newInstance(lifecycle, facesContext, getPhaseListenersMethod.invoke(lifecycleImpl, null));
+                facesContext.getAttributes().put(PHASE_MANAGER_INSTANCE, phaseManager);
+            }
+            
+            
+            Flash flash = facesContext.getExternalContext().getFlash();
+            
+            //phaseListenerMgr.informPhaseListenersAfter(renderExecutor.getPhase());
+            Method informPhaseListenersAfterMethod = phaseManager.getClass().getDeclaredMethod("informPhaseListenersAfter", PhaseId.class);
+            if(!(informPhaseListenersAfterMethod.isAccessible()))
+            {
+                informPhaseListenersAfterMethod.setAccessible(true);
+            }
+            informPhaseListenersAfterMethod.invoke(phaseManager, PhaseId.RENDER_RESPONSE);
+            
+            flash.doPostPhaseActions(facesContext);
+            
+            facesContext.getExceptionHandler().handle();
+
+            facesContext.getAttributes().remove(PHASE_MANAGER_INSTANCE);
+            
+            facesContext.getAttributes().put(LAST_RENDER_PHASE_STEP, AFTER_RENDER_STEP);
+            //End render response phase
+            facesContext.getAttributes().put(LAST_PHASE_PROCESSED, PhaseId.RENDER_RESPONSE);
+        }
+        else
+        {
+            throw new UnsupportedOperationException("Cannot execute phase on custom lifecycle instances");
+        }
+    }
+    
     /**
      * Execute an specified phase, doing some reflection over LifecycleImpl.
      * 

Modified: myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/AcidMyFacesRequestTestCase.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/AcidMyFacesRequestTestCase.java?rev=1417719&r1=1417718&r2=1417719&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/AcidMyFacesRequestTestCase.java (original)
+++ myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/AcidMyFacesRequestTestCase.java Thu Dec  6 00:57:19 2012
@@ -22,12 +22,14 @@ import javax.faces.application.StateMana
 import javax.faces.component.UICommand;
 import javax.faces.component.UIComponent;
 import javax.faces.component.UIInput;
+import javax.faces.component.UIPanel;
 import javax.faces.component.html.HtmlDataTable;
 
 import junit.framework.Assert;
 
 import org.apache.myfaces.mc.test.core.AbstractMyFacesRequestTestCase;
 import org.apache.myfaces.shared.config.MyfacesConfig;
+import org.apache.myfaces.view.facelets.pss.acid.managed.ResourceDependencyBean;
 import org.junit.Test;
 
 public class AcidMyFacesRequestTestCase extends AbstractMyFacesRequestTestCase
@@ -418,4 +420,92 @@ public class AcidMyFacesRequestTestCase 
         //Check it is restored
         Assert.assertNotNull(component);
     }
+    
+    /**
+     * Check if a dynamic subtree can be created from a binding property, and if it
+     * will be preserved across request. 
+     * 
+     * The idea is just inject a subtree using some code like this:
+     * <code>&lt;h:panelGroup id="panel" binding="#{componentBindingBean.panel}"&gt;</code>
+     * 
+     * The solution is if a binding returns a component that has children or facets
+     * attached, it is not elegible for PSS algorithm because the additional components
+     * are created outside facelets control, and there is no warrant that the same structure
+     * will be generated across requests, violating PSS base principle (it is possible to
+     * restore to the initial state calling vdl.buildView).
+     * 
+     * This test is here because all state saving modes should support this method.
+     * 
+     * @throws Exception 
+     */
+    @Test
+    public void testComponentBinding() throws Exception
+    {
+        setupRequest("/componentBinding1.xhtml");
+        processLifecycleExecuteAndRender();
+        
+        UIComponent comp = facesContext.getViewRoot().findComponent("panel");
+        Assert.assertNotNull(comp);
+        Assert.assertEquals(1, comp.getChildCount());
+        
+        UICommand button = (UICommand) facesContext.getViewRoot().findComponent("mainForm:postback");
+        submit(button);
+        processLifecycleExecuteAndRender();
+        
+        comp = facesContext.getViewRoot().findComponent("panel");
+        
+        Assert.assertEquals("value1", comp.getAttributes().get("attr1"));
+        Assert.assertEquals("value2", comp.getChildren().get(0).getAttributes().get("attr2"));
+        
+        button = (UICommand) facesContext.getViewRoot().findComponent("mainForm:postback");
+        submit(button);
+        processLifecycleExecuteAndRender();
+
+        comp = facesContext.getViewRoot().findComponent("panel");
+        
+        Assert.assertEquals("value1", comp.getAttributes().get("attr1"));
+        Assert.assertEquals("value2", comp.getChildren().get(0).getAttributes().get("attr2"));
+        
+        tearDownRequest();
+    }
+    
+    @Test
+    public void testResourceDependency() throws Exception
+    {
+        setupRequest("/resourceDependency1.xhtml");
+        processLifecycleExecute();
+
+        executeBeforeRender(facesContext);
+        executeBuildViewCycle(facesContext);
+
+        UIPanel headPanel = (UIPanel) facesContext.getViewRoot().getFacet("head");
+        Assert.assertNotNull(headPanel);
+        Assert.assertEquals(1, headPanel.getChildCount());
+        
+        String nextUniqueId = facesContext.getViewRoot().createUniqueId(facesContext, null);
+        
+        executeViewHandlerRender(facesContext);
+        executeAfterRender(facesContext);
+        
+        UICommand button = (UICommand) facesContext.getViewRoot().findComponent("mainForm:postback");
+        submit(button);
+        
+        processLifecycleExecute();
+        
+        ResourceDependencyBean bean = facesContext.getApplication().evaluateExpressionGet(
+            facesContext, "#{resourceDependencyBean}", ResourceDependencyBean.class);
+        bean.setIncludeContent(true);
+        
+        executeBeforeRender(facesContext);
+        executeBuildViewCycle(facesContext);
+        
+        headPanel = (UIPanel) facesContext.getViewRoot().getFacet("head");
+        Assert.assertNotNull(headPanel);
+        Assert.assertEquals(1, headPanel.getChildCount());
+        Assert.assertNotSame(nextUniqueId, headPanel.getChildren().get(0).getId());
+        
+        executeViewHandlerRender(facesContext);
+        executeAfterRender(facesContext);
+    }
+
 }

Added: myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/component/UIRDComponent.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/component/UIRDComponent.java?rev=1417719&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/component/UIRDComponent.java (added)
+++ myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/component/UIRDComponent.java Thu Dec  6 00:57:19 2012
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2012 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.view.facelets.pss.acid.component;
+
+import javax.faces.application.ResourceDependency;
+import javax.faces.component.FacesComponent;
+import javax.faces.component.UIOutput;
+
+/**
+ *
+ * @author lu4242
+ */
+@FacesComponent(value = "com.myapp.UIRDComponent")
+@ResourceDependency(name = "custom.css", target="head")
+public class UIRDComponent extends UIOutput
+{
+    public UIRDComponent()
+    {
+        super();
+    }
+    
+}

Propchange: myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/component/UIRDComponent.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/managed/ComponentBindingBean.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/managed/ComponentBindingBean.java?rev=1417719&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/managed/ComponentBindingBean.java (added)
+++ myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/managed/ComponentBindingBean.java Thu Dec  6 00:57:19 2012
@@ -0,0 +1,75 @@
+/*
+ * 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.view.facelets.pss.acid.managed;
+
+import javax.faces.bean.ManagedBean;
+import javax.faces.bean.RequestScoped;
+import javax.faces.component.UIOutput;
+import javax.faces.component.UIPanel;
+import javax.faces.component.html.HtmlPanelGroup;
+import javax.faces.context.FacesContext;
+
+/**
+ *
+ * @author Leonardo Uribe
+ */
+@ManagedBean(name="componentBindingBean")
+@RequestScoped
+public class ComponentBindingBean
+{
+    private UIPanel panel;
+    
+    public UIPanel getPanel()
+    {
+        if (panel == null)
+        {
+            panel = new HtmlPanelGroup();
+            if (FacesContext.getCurrentInstance().isPostback())
+            {
+                // Just try to mess the binding. In theory this does
+                // not have effect, because the binding with children
+                // or facets should be restored fully.
+                UIOutput out2 = new UIOutput();
+                out2.setValue("hello2");
+                panel.getChildren().add(out2);
+            }
+            UIOutput out = new UIOutput();
+            out.setValue("hello1");
+            panel.getChildren().add(out);
+            if (!FacesContext.getCurrentInstance().isPostback())
+            {
+                // Store something into the state
+                panel.getAttributes().put("attr1", "value1");
+                panel.getChildren().get(0).getAttributes().put("attr2", "value2");
+            }
+            else
+            {
+                //Try to mess the state, in theory it should not have effect
+                panel.getAttributes().remove("attr1");
+                panel.getChildren().get(0).getAttributes().remove("attr2");
+            }
+        }
+        return panel;
+    }
+    
+    public void setPanel(UIPanel panel)
+    {
+        this.panel = panel;
+    }
+}

Propchange: myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/managed/ComponentBindingBean.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/managed/ResourceDependencyBean.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/managed/ResourceDependencyBean.java?rev=1417719&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/managed/ResourceDependencyBean.java (added)
+++ myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/managed/ResourceDependencyBean.java Thu Dec  6 00:57:19 2012
@@ -0,0 +1,49 @@
+/*
+ * 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.view.facelets.pss.acid.managed;
+
+import javax.faces.bean.ManagedBean;
+import javax.faces.bean.SessionScoped;
+
+/**
+ *
+ * @author Leonardo Uribe
+ */
+@ManagedBean(name="resourceDependencyBean")
+@SessionScoped
+public class ResourceDependencyBean
+{
+    private boolean includeContent;
+    
+    /**
+     * @return the includeContent
+     */
+    public boolean isIncludeContent()
+    {
+        return includeContent;
+    }
+
+    /**
+     * @param includeContent the includeContent to set
+     */
+    public void setIncludeContent(boolean includeContent)
+    {
+        this.includeContent = includeContent;
+    }
+}

Propchange: myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/pss/acid/managed/ResourceDependencyBean.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/WEB-INF/testcomponent.taglib.xml
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/WEB-INF/testcomponent.taglib.xml?rev=1417719&r1=1417718&r2=1417719&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/WEB-INF/testcomponent.taglib.xml (original)
+++ myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/WEB-INF/testcomponent.taglib.xml Thu Dec  6 00:57:19 2012
@@ -64,5 +64,12 @@
 			<component-type>com.myapp.UISelfRenderComponent</component-type>
 		</component>
 	</tag>
+    
+    <tag>
+		<tag-name>rdcomponent</tag-name>
+		<component>
+			<component-type>com.myapp.UIRDComponent</component-type>
+		</component>
+	</tag>
 
 </facelet-taglib>
\ No newline at end of file

Copied: myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/componentBinding1.xhtml (from r1416728, myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/index.xhtml)
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/componentBinding1.xhtml?p2=myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/componentBinding1.xhtml&p1=myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/index.xhtml&r1=1416728&r2=1417719&rev=1417719&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/index.xhtml (original)
+++ myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/componentBinding1.xhtml Thu Dec  6 00:57:19 2012
@@ -12,31 +12,17 @@
  See the License for the specific language governing permissions and
  limitations under the License.
 -->
-<ui:composition xmlns="http://www.w3.org/1999/xhtml"
-				xmlns:h="http://java.sun.com/jsf/html"
-				xmlns:f="http://java.sun.com/jsf/core"
-				xmlns:ui="http://java.sun.com/jsf/facelets"
-				xmlns:test="http://testcomponent"
-				template="common.xhtml">
-
-	<h2>Add Test Instructions</h2>
-	
-	<ol>
-		<li>The component should have dynamically modified the tree so that 'Dynamically added child' appears inside the red box</li>
-		<li>Click 'POSTback'. The 'Dynamically added child' should not disappear (because it should have been serialized in the ViewState)</li>
-	</ol>
-		
-	<h:messages/>
-		
-	<h:form id="mainForm">
-	
-		<test:addcomponent id="component"/>
-		
-		<br/>
-		
-		<h:commandButton id="postback" value="POSTback" action="#{testManagedBean.save}"/>
-		
-	</h:form>			
-	
-</ui:composition>
+<html xmlns="http://www.w3.org/1999/xhtml"
+    xmlns:h="http://java.sun.com/jsf/html"
+    xmlns:f="http://java.sun.com/jsf/core"
+    xmlns:ui="http://java.sun.com/jsf/facelets">
+<h:head>
+</h:head>
+<h:body>
+  <h:panelGroup id="panel" binding="#{componentBindingBean.panel}"/>
+  <h:form id="mainForm">
+     <h:commandButton id="postback" value="POSTBACK"/>
+  </h:form>
+</h:body>
+</html>
 

Copied: myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/resourceDependency1.xhtml (from r1416728, myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/index.xhtml)
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/resourceDependency1.xhtml?p2=myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/resourceDependency1.xhtml&p1=myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/index.xhtml&r1=1416728&r2=1417719&rev=1417719&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/index.xhtml (original)
+++ myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/resourceDependency1.xhtml Thu Dec  6 00:57:19 2012
@@ -12,31 +12,20 @@
  See the License for the specific language governing permissions and
  limitations under the License.
 -->
-<ui:composition xmlns="http://www.w3.org/1999/xhtml"
-				xmlns:h="http://java.sun.com/jsf/html"
-				xmlns:f="http://java.sun.com/jsf/core"
-				xmlns:ui="http://java.sun.com/jsf/facelets"
-				xmlns:test="http://testcomponent"
-				template="common.xhtml">
-
-	<h2>Add Test Instructions</h2>
-	
-	<ol>
-		<li>The component should have dynamically modified the tree so that 'Dynamically added child' appears inside the red box</li>
-		<li>Click 'POSTback'. The 'Dynamically added child' should not disappear (because it should have been serialized in the ViewState)</li>
-	</ol>
-		
-	<h:messages/>
-		
-	<h:form id="mainForm">
-	
-		<test:addcomponent id="component"/>
-		
-		<br/>
-		
-		<h:commandButton id="postback" value="POSTback" action="#{testManagedBean.save}"/>
-		
-	</h:form>			
-	
-</ui:composition>
+<html xmlns="http://www.w3.org/1999/xhtml"
+    xmlns:h="http://java.sun.com/jsf/html"
+    xmlns:f="http://java.sun.com/jsf/core"
+    xmlns:ui="http://java.sun.com/jsf/facelets"
+    xmlns:c="http://java.sun.com/jsp/jstl/core"
+    xmlns:test="http://testcomponent">
+<h:head>
+</h:head>
+<h:body>
+  
+  <test:rdcomponent value="test1"/>
+  <h:form id="mainForm">
+     <h:commandButton id="postback" value="POSTBACK"/>
+  </h:form>
+</h:body>
+</html>
 

Propchange: myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/resources/
------------------------------------------------------------------------------
    bugtraq:number = true

Added: myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/resources/custom.css
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/resources/custom.css?rev=1417719&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/resources/custom.css (added)
+++ myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/resources/custom.css Thu Dec  6 00:57:19 2012
@@ -0,0 +1,15 @@
+/*
+ * Copyright 2012 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.
+ */
\ No newline at end of file

Propchange: myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/pss/acid/resources/custom.css
------------------------------------------------------------------------------
    svn:eol-style = native