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 2011/08/21 03:23:59 UTC

svn commit: r1159932 - in /myfaces/core/trunk/impl/src/main/java/org/apache/myfaces: application/StateManagerImpl.java view/facelets/DefaultFaceletsStateManagementStrategy.java

Author: lu4242
Date: Sun Aug 21 01:23:58 2011
New Revision: 1159932

URL: http://svn.apache.org/viewvc?rev=1159932&view=rev
Log:
MYFACES-3257 Clarify partial state save/restore traversal requirements

Modified:
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/StateManagerImpl.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/DefaultFaceletsStateManagementStrategy.java

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/StateManagerImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/StateManagerImpl.java?rev=1159932&r1=1159931&r2=1159932&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/StateManagerImpl.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/StateManagerImpl.java Sun Aug 21 01:23:58 2011
@@ -149,70 +149,79 @@ public class StateManagerImpl extends St
         String viewId = uiViewRoot.getViewId();
         ViewDeclarationLanguage vdl = facesContext.getApplication().
             getViewHandler().getViewDeclarationLanguage(facesContext,viewId);
-        if (vdl != null)
+        
+        try
         {
-            StateManagementStrategy sms = vdl.getStateManagementStrategy(facesContext, viewId);
-            
-            if (sms != null)
+            facesContext.getAttributes().put(StateManager.IS_SAVING_STATE, Boolean.TRUE);
+            if (vdl != null)
             {
-                if (log.isLoggable(Level.FINEST)) log.finest("Calling saveView of StateManagementStrategy: "+sms.getClass().getName());
+                StateManagementStrategy sms = vdl.getStateManagementStrategy(facesContext, viewId);
                 
-                serializedView = sms.saveView(facesContext);
-                
-                // If MyfacesResponseStateManager is used, give the option to do
-                // additional operations for save the state if is necessary.
-                if (StateCacheUtils.isMyFacesResponseStateManager(responseStateManager))
+                if (sms != null)
                 {
-                    StateCacheUtils.getMyFacesResponseStateManager(responseStateManager).saveState(facesContext, serializedView);
+                    if (log.isLoggable(Level.FINEST)) log.finest("Calling saveView of StateManagementStrategy: "+sms.getClass().getName());
+                    
+                    serializedView = sms.saveView(facesContext);
+                    
+                    // If MyfacesResponseStateManager is used, give the option to do
+                    // additional operations for save the state if is necessary.
+                    if (StateCacheUtils.isMyFacesResponseStateManager(responseStateManager))
+                    {
+                        StateCacheUtils.getMyFacesResponseStateManager(responseStateManager).saveState(facesContext, serializedView);
+                    }
+                    
+                    return serializedView; 
                 }
-                
-                return serializedView; 
             }
+    
+            // In StateManagementStrategy.saveView there is a check for transient at
+            // start, but the same applies for VDL without StateManagementStrategy,
+            // so this should be checked before call parent (note that parent method
+            // does not do this check).
+            if (uiViewRoot.isTransient())
+            {
+                return null;
+            }
+    
+            if (log.isLoggable(Level.FINEST)) log.finest("Entering saveSerializedView");
+    
+            checkForDuplicateIds(facesContext, facesContext.getViewRoot(), new HashSet<String>());
+    
+            if (log.isLoggable(Level.FINEST)) log.finest("Processing saveSerializedView - Checked for duplicate Ids");
+    
+            ExternalContext externalContext = facesContext.getExternalContext();
+    
+            // SerializedView already created before within this request?
+            serializedView = externalContext.getRequestMap()
+                                                                .get(SERIALIZED_VIEW_REQUEST_ATTR);
+            if (serializedView == null)
+            {
+                if (log.isLoggable(Level.FINEST)) log.finest("Processing saveSerializedView - create new serialized view");
+    
+                // first call to saveSerializedView --> create SerializedView
+                Object treeStruct = getTreeStructureToSave(facesContext);
+                Object compStates = getComponentStateToSave(facesContext);
+                serializedView = new Object[] {treeStruct, compStates};
+                externalContext.getRequestMap().put(SERIALIZED_VIEW_REQUEST_ATTR,
+                                                    serializedView);
+    
+                if (log.isLoggable(Level.FINEST)) log.finest("Processing saveSerializedView - new serialized view created");
+            }
+            
+            // If MyfacesResponseStateManager is used, give the option to do
+            // additional operations for save the state if is necessary.
+            if (StateCacheUtils.isMyFacesResponseStateManager(responseStateManager))
+            {
+                StateCacheUtils.getMyFacesResponseStateManager(responseStateManager).saveState(facesContext, serializedView);
+            }
+    
+            if (log.isLoggable(Level.FINEST)) log.finest("Exiting saveView");
         }
-
-        // In StateManagementStrategy.saveView there is a check for transient at
-        // start, but the same applies for VDL without StateManagementStrategy,
-        // so this should be checked before call parent (note that parent method
-        // does not do this check).
-        if (uiViewRoot.isTransient())
-        {
-            return null;
-        }
-
-        if (log.isLoggable(Level.FINEST)) log.finest("Entering saveSerializedView");
-
-        checkForDuplicateIds(facesContext, facesContext.getViewRoot(), new HashSet<String>());
-
-        if (log.isLoggable(Level.FINEST)) log.finest("Processing saveSerializedView - Checked for duplicate Ids");
-
-        ExternalContext externalContext = facesContext.getExternalContext();
-
-        // SerializedView already created before within this request?
-        serializedView = externalContext.getRequestMap()
-                                                            .get(SERIALIZED_VIEW_REQUEST_ATTR);
-        if (serializedView == null)
-        {
-            if (log.isLoggable(Level.FINEST)) log.finest("Processing saveSerializedView - create new serialized view");
-
-            // first call to saveSerializedView --> create SerializedView
-            Object treeStruct = getTreeStructureToSave(facesContext);
-            Object compStates = getComponentStateToSave(facesContext);
-            serializedView = new Object[] {treeStruct, compStates};
-            externalContext.getRequestMap().put(SERIALIZED_VIEW_REQUEST_ATTR,
-                                                serializedView);
-
-            if (log.isLoggable(Level.FINEST)) log.finest("Processing saveSerializedView - new serialized view created");
-        }
-        
-        // If MyfacesResponseStateManager is used, give the option to do
-        // additional operations for save the state if is necessary.
-        if (StateCacheUtils.isMyFacesResponseStateManager(responseStateManager))
+        finally
         {
-            StateCacheUtils.getMyFacesResponseStateManager(responseStateManager).saveState(facesContext, serializedView);
+            facesContext.getAttributes().remove(StateManager.IS_SAVING_STATE);
         }
 
-        if (log.isLoggable(Level.FINEST)) log.finest("Exiting saveView");
-
         return serializedView;
     }
 

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=1159932&r1=1159931&r2=1159932&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 Sun Aug 21 01:23:58 2011
@@ -21,6 +21,7 @@ package org.apache.myfaces.view.facelets
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -34,13 +35,16 @@ import javax.faces.component.ContextCall
 import javax.faces.component.UIComponent;
 import javax.faces.component.UIViewParameter;
 import javax.faces.component.UIViewRoot;
+import javax.faces.component.visit.VisitCallback;
+import javax.faces.component.visit.VisitContext;
+import javax.faces.component.visit.VisitHint;
+import javax.faces.component.visit.VisitResult;
 import javax.faces.context.ExternalContext;
 import javax.faces.context.FacesContext;
 import javax.faces.event.PostAddToViewEvent;
 import javax.faces.event.PreRemoveFromViewEvent;
 import javax.faces.event.SystemEvent;
 import javax.faces.event.SystemEventListener;
-import javax.faces.render.RenderKit;
 import javax.faces.render.RenderKitFactory;
 import javax.faces.render.ResponseStateManager;
 import javax.faces.view.StateManagementStrategy;
@@ -49,9 +53,10 @@ import javax.faces.view.ViewDeclarationL
 import javax.faces.view.ViewMetadata;
 
 import org.apache.myfaces.application.StateManagerImpl;
-import org.apache.myfaces.shared.renderkit.RendererUtils;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
 import org.apache.myfaces.shared.util.ClassUtils;
 import org.apache.myfaces.shared.util.HashMapUtils;
+import org.apache.myfaces.shared.util.WebConfigParamUtils;
 
 /**
  * This class implements partial state saving feature when facelets
@@ -112,6 +117,17 @@ public class DefaultFaceletsStateManagem
      */
     public  static final String COMPONENT_ADDED_AFTER_BUILD_VIEW = "oam.COMPONENT_ADDED_AFTER_BUILD_VIEW"; 
     
+    /**
+     * If this param is set to true (by default), when pss algorithm is executed to save state, a visit tree
+     * traversal is done, instead a plain traversal like previous versions (2.0.7/2.1.1 and earlier) of MyFaces Core.
+     * 
+     * This param is just provided to preserve backwards behavior. 
+     */
+    @JSFWebConfigParam(since="2.0.8, 2.1.2", defaultValue="true", expectedValues="true, false")
+    public static final String SAVE_STATE_WITH_VISIT_TREE_ON_PSS = "org.apache.myfaces.SAVE_STATE_WITH_VISIT_TREE_ON_PSS";
+    
+    private static final String SKIP_ITERATION_HINT = "javax.faces.visit.SKIP_ITERATION";
+    
     private static final String SERIALIZED_VIEW_REQUEST_ATTR = 
         StateManagerImpl.class.getName() + ".SERIALIZED_VIEW";
     
@@ -119,6 +135,8 @@ public class DefaultFaceletsStateManagem
     
     private RenderKitFactory _renderKitFactory = null;
     
+    private Boolean _saveStateWithVisitTreeOnPSS;
+    
     public DefaultFaceletsStateManagementStrategy ()
     {
         _vdlFactory = (ViewDeclarationLanguageFactory)FactoryFinder.getFactory(FactoryFinder.VIEW_DECLARATION_LANGUAGE_FACTORY);
@@ -449,7 +467,14 @@ public class DefaultFaceletsStateManagem
             {
                 states = new HashMap<String, Object>();
 
-                saveStateOnMap(context,(Map<String,Object>) states, view);
+                if (isSaveStateWithVisitTreeOnPSS(context))
+                {
+                    saveStateOnMapVisitTree(context,(Map<String,Object>) states, view);
+                }
+                else
+                {
+                    saveStateOnMap(context,(Map<String,Object>) states, view);
+                }
                 
                 if ( ((Map<String,Object>)states).isEmpty())
                 {
@@ -626,7 +651,124 @@ public class DefaultFaceletsStateManagem
 
         setClientsIdsAdded(uiViewRoot, clientIdsAdded);
     }
+
+    public boolean isSaveStateWithVisitTreeOnPSS(FacesContext facesContext)
+    {
+        if (_saveStateWithVisitTreeOnPSS == null)
+        {
+            _saveStateWithVisitTreeOnPSS = WebConfigParamUtils.getBooleanInitParameter(facesContext.getExternalContext(),
+                    SAVE_STATE_WITH_VISIT_TREE_ON_PSS, Boolean.TRUE);
+        }
+        return Boolean.TRUE.equals(_saveStateWithVisitTreeOnPSS);
+    }
+
+    private void saveStateOnMapVisitTree(final FacesContext facesContext, final Map<String,Object> states,
+            final UIViewRoot uiViewRoot)
+    {
+        facesContext.getAttributes().put(SKIP_ITERATION_HINT, Boolean.TRUE);
+        try
+        {
+            EnumSet<VisitHint> visitHints = EnumSet.of(VisitHint.SKIP_ITERATION);
+            uiViewRoot.visitTree( VisitContext.createVisitContext (facesContext, null, visitHints), new VisitCallback()
+            {
+                public VisitResult visit(VisitContext context, UIComponent target)
+                {
+                    FacesContext facesContext = context.getFacesContext();
+                    Object state;
+                    
+                    if ((target == null) || target.isTransient()) {
+                        // No need to bother with these components or their children.
+                        
+                        return VisitResult.REJECT;
+                    }
+                    
+                    ComponentState componentAddedAfterBuildView = (ComponentState) target.getAttributes().get(COMPONENT_ADDED_AFTER_BUILD_VIEW);
+                    
+                    //Note if UIViewRoot has this marker, JSF 1.2 like state saving is used.
+                    if (componentAddedAfterBuildView != null && (target.getParent() != null))
+                    {
+                        if (ComponentState.REMOVE_ADD.equals(componentAddedAfterBuildView))
+                        {
+                            registerOnAddRemoveList(target.getClientId());
+                            target.getAttributes().put(COMPONENT_ADDED_AFTER_BUILD_VIEW, ComponentState.ADDED);
+                        }
+                        else if (ComponentState.ADD.equals(componentAddedAfterBuildView))
+                        {
+                            registerOnAddList(target.getClientId());
+                            target.getAttributes().put(COMPONENT_ADDED_AFTER_BUILD_VIEW, ComponentState.ADDED);
+                        }
+                        else if (ComponentState.ADDED.equals(componentAddedAfterBuildView))
+                        {
+                            registerOnAddList(target.getClientId());
+                        }
+                        ensureClearInitialState(target);
+                        //Save all required info to restore the subtree.
+                        //This includes position, structure and state of subtree
+                        
+                        int childIndex = target.getParent().getChildren().indexOf(target);
+                        if (childIndex >= 0)
+                        {
+                            states.put(target.getClientId(facesContext), new AttachedFullStateWrapper( 
+                                    new Object[]{
+                                        target.getParent().getClientId(facesContext),
+                                        null,
+                                        childIndex,
+                                        internalBuildTreeStructureToSave(target),
+                                        target.processSaveState(facesContext)}));
+                        }
+                        else
+                        {
+                            String facetName = null;
+                            for (Map.Entry<String, UIComponent> entry : target.getParent().getFacets().entrySet()) 
+                            {
+                                if (target.equals(entry.getValue()))
+                                {
+                                    facetName = entry.getKey();
+                                    break;
+                                }
+                            }
+                            states.put(target.getClientId(facesContext),new AttachedFullStateWrapper(new Object[]{
+                                    target.getParent().getClientId(facesContext),
+                                    facetName,
+                                    null,
+                                    internalBuildTreeStructureToSave(target),
+                                    target.processSaveState(facesContext)}));
+                        }
+                        return VisitResult.REJECT;
+                    }
+                    else if (uiViewRoot.getParent() != null)
+                    {
+                        state = target.saveState (facesContext);
+                        
+                        if (state != null) {
+                            // Save by client ID into our map.
+                            
+                            states.put (target.getClientId (facesContext), state);
+                        }
+                        
+                        return VisitResult.ACCEPT;
+                    }
+                    else
+                    {
+                        //Only UIViewRoot has no parent in a component tree.
+                        return VisitResult.ACCEPT;
+                    }
+                }
+            });
+        }
+        finally
+        {
+            facesContext.getAttributes().remove(SKIP_ITERATION_HINT);
+        }
+        
+        Object state = uiViewRoot.saveState (facesContext);
+        if (state != null) {
+            // Save by client ID into our map.
             
+            states.put (uiViewRoot.getClientId (facesContext), state);
+        }
+    }
+
     private void saveStateOnMap(final FacesContext context, final Map<String,Object> states,
             final UIComponent component)
     {