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 2013/08/29 04:21:08 UTC

svn commit: r1518443 - in /myfaces/core/trunk/impl/src: main/java/org/apache/myfaces/application/ main/java/org/apache/myfaces/renderkit/ main/java/org/apache/myfaces/renderkit/html/ main/java/org/apache/myfaces/view/facelets/ test/java/org/apache/myfa...

Author: lu4242
Date: Thu Aug 29 02:21:08 2013
New Revision: 1518443

URL: http://svn.apache.org/r1518443
Log:
MYFACES-3714 Implement stateless mode using f:view "transient" attribute 

Added:
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/StateTokenProcessor.java   (with props)
Modified:
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/StateManagerImpl.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/html/HtmlResponseStateManager.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/FaceletViewDeclarationLanguage.java
    myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/StateManagerWithFaceletsTest.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=1518443&r1=1518442&r2=1518443&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 Thu Aug 29 02:21:08 2013
@@ -167,8 +167,14 @@ public class StateManagerImpl extends St
     @Override
     public Object saveView(FacesContext facesContext)
     {
-        Object serializedView = null;
         UIViewRoot uiViewRoot = facesContext.getViewRoot();
+        
+        if (uiViewRoot.isTransient())
+        {
+            return null;
+        }
+        
+        Object serializedView = null;
         ResponseStateManager responseStateManager = facesContext.getRenderKit().getResponseStateManager();
         
         String viewId = uiViewRoot.getViewId();

Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/StateTokenProcessor.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/StateTokenProcessor.java?rev=1518443&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/StateTokenProcessor.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/StateTokenProcessor.java Thu Aug 29 02:21:08 2013
@@ -0,0 +1,34 @@
+/*
+ * 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.renderkit;
+
+import javax.faces.context.FacesContext;
+
+/**
+ *
+ * @author Leonardo Uribe
+ */
+public abstract class StateTokenProcessor
+{
+    public abstract Object decode(FacesContext facesContext, String token);
+    
+    public abstract String encode(FacesContext facesContext, Object savedStateObject);
+    
+    public abstract boolean isStateless(FacesContext facesContext, String token);
+}

Propchange: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/StateTokenProcessor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/html/HtmlResponseStateManager.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/html/HtmlResponseStateManager.java?rev=1518443&r1=1518442&r2=1518443&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/html/HtmlResponseStateManager.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/html/HtmlResponseStateManager.java Thu Aug 29 02:21:08 2013
@@ -34,6 +34,7 @@ import org.apache.myfaces.application.St
 import org.apache.myfaces.application.viewstate.StateCacheFactoryImpl;
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
 import org.apache.myfaces.renderkit.MyfacesResponseStateManager;
+import org.apache.myfaces.renderkit.StateTokenProcessor;
 import org.apache.myfaces.shared.config.MyfacesConfig;
 import org.apache.myfaces.shared.renderkit.html.HTML;
 import org.apache.myfaces.shared.renderkit.html.HtmlRendererUtils;
@@ -75,9 +76,12 @@ public class HtmlResponseStateManager ex
     
     private StateCacheFactory _stateCacheFactory;
     
+    private StateTokenProcessor _stateTokenProcessor;
+    
     public HtmlResponseStateManager()
     {
         _stateCacheFactory = new StateCacheFactoryImpl();
+        _stateTokenProcessor = new DefaultStateTokenProcessor();
     }
     
     protected boolean isHandlingStateCachingMechanics(FacesContext facesContext)
@@ -97,42 +101,46 @@ public class HtmlResponseStateManager ex
 
         Object savedStateObject = null;
         
-        if (isHandlingStateCachingMechanics(facesContext))
-        {
-            savedStateObject = getStateCache(facesContext).encodeSerializedState(facesContext, state);
-        }
-        else
+        if (!facesContext.getViewRoot().isTransient())
         {
-            Object token = null;
-            Object[] savedState = new Object[2];
-            token = state;
-            
-            if (log.isLoggable(Level.FINEST))
+            // Only if the view is not transient needs to be saved
+            if (isHandlingStateCachingMechanics(facesContext))
             {
-                log.finest("Writing state in client");
-            }
-
-
-            if (token != null)
-            {
-                savedState[STATE_PARAM] = token;
+                savedStateObject = getStateCache(facesContext).encodeSerializedState(facesContext, state);
             }
             else
             {
+                Object token = null;
+                Object[] savedState = new Object[2];
+                token = state;
+
                 if (log.isLoggable(Level.FINEST))
                 {
-                    log.finest("No component states to be saved in client response!");
+                    log.finest("Writing state in client");
                 }
-            }
 
-            savedState[VIEWID_PARAM] = facesContext.getViewRoot().getViewId();
 
-            if (log.isLoggable(Level.FINEST))
-            {
-                log.finest("Writing view state and renderKit fields");
+                if (token != null)
+                {
+                    savedState[STATE_PARAM] = token;
+                }
+                else
+                {
+                    if (log.isLoggable(Level.FINEST))
+                    {
+                        log.finest("No component states to be saved in client response!");
+                    }
+                }
+
+                savedState[VIEWID_PARAM] = facesContext.getViewRoot().getViewId();
+
+                if (log.isLoggable(Level.FINEST))
+                {
+                    log.finest("Writing view state and renderKit fields");
+                }
+
+                savedStateObject = savedState;
             }
-            
-            savedStateObject = savedState;
         }
 
         // write the view state field
@@ -162,20 +170,23 @@ public class HtmlResponseStateManager ex
     @Override
     public void saveState(FacesContext facesContext, Object state)
     {
-        if (isHandlingStateCachingMechanics(facesContext))
+        if (!facesContext.getViewRoot().isTransient())
         {
-            getStateCache(facesContext).saveSerializedView(facesContext, state);
-        }
-        else
-        {
-            //This is done outside
+            if (isHandlingStateCachingMechanics(facesContext))
+            {
+                getStateCache(facesContext).saveSerializedView(facesContext, state);
+            }
+            else
+            {
+                //This is done outside
+            }
         }
     }
 
     private void writeViewStateField(FacesContext facesContext, ResponseWriter responseWriter, Object savedState)
         throws IOException
     {
-        String serializedState = StateUtils.construct(savedState, facesContext.getExternalContext());
+        String serializedState = _stateTokenProcessor.encode(facesContext, savedState);
         ExternalContext extContext = facesContext.getExternalContext();
         MyfacesConfig myfacesConfig = MyfacesConfig.getCurrentInstance(extContext);
         // Write Javascript viewstate if enabled and if javascript is allowed,
@@ -191,7 +202,12 @@ public class HtmlResponseStateManager ex
             responseWriter.writeAttribute(HTML.NAME_ATTR, STANDARD_STATE_SAVING_PARAM, null);
             if (myfacesConfig.isRenderViewStateId())
             {
-                responseWriter.writeAttribute(HTML.ID_ATTR, STANDARD_STATE_SAVING_PARAM, null);
+                // responseWriter.writeAttribute(HTML.ID_ATTR, STANDARD_STATE_SAVING_PARAM, null);
+                // JSF 2.2 if javax.faces.ViewState is used as the id, in portlet
+                // case it will be duplicate ids and that not xml friendly.
+                responseWriter.writeAttribute(HTML.ID_ATTR,
+                    HtmlResponseStateManager.generateUpdateViewStateId(
+                        facesContext), null);
             }
             responseWriter.writeAttribute(HTML.VALUE_ATTR, serializedState, null);
             responseWriter.endElement(HTML.INPUT_ELEM);
@@ -277,7 +293,7 @@ public class HtmlResponseStateManager ex
             return null;
         }
 
-        Object savedStateObject = StateUtils.reconstruct((String)encodedState, facesContext.getExternalContext());
+        Object savedStateObject = _stateTokenProcessor.decode(facesContext, (String)encodedState);
         
         if (isHandlingStateCachingMechanics(facesContext))
         {
@@ -327,10 +343,18 @@ public class HtmlResponseStateManager ex
     @Override
     public String getViewState(FacesContext facesContext, Object baseState)
     {
+        // If the view is transient, baseState is null, so it should return null.
+        // In this way, PartialViewContext will skip <update ...> section related
+        // to view state (stateless view does not have state, so it does not need
+        // to update the view state section). 
         if (baseState == null)
         {
             return null;
         }
+        if (facesContext.getViewRoot().isTransient())
+        {
+            return null;
+        }
         
         Object state = null;
         if (isHandlingStateCachingMechanics(facesContext))
@@ -348,10 +372,35 @@ public class HtmlResponseStateManager ex
             }
 
             savedState[VIEWID_PARAM] = facesContext.getViewRoot().getViewId();
-            
+
             state = savedState;
         }
-        return StateUtils.construct(state, facesContext.getExternalContext());
+        return _stateTokenProcessor.encode(facesContext, state);
+    }
+
+    @Override
+    public boolean isStateless(FacesContext context, String viewId)
+    {
+        if (context.isPostback())
+        {
+            String encodedState = 
+                context.getExternalContext().getRequestParameterMap().get(STANDARD_STATE_SAVING_PARAM);
+            if(encodedState==null || (((String) encodedState).length() == 0))
+            {
+                return false;
+            }
+
+            return _stateTokenProcessor.isStateless(context, encodedState);
+        }
+        else 
+        {
+            // "... java.lang.IllegalStateException - if this method is invoked 
+            // and the statefulness of the preceding call to writeState(
+            // javax.faces.context.FacesContext, java.lang.Object) cannot be determined.
+            throw new IllegalStateException(
+                "Cannot decide if the view is stateless or not, since the request is "
+                + "not postback (no preceding writeState(...)).");
+        }
     }
     
     @Override
@@ -421,4 +470,38 @@ public class HtmlResponseStateManager ex
         return id;
     }
 
+    private static class DefaultStateTokenProcessor extends StateTokenProcessor
+    {
+        private static final String STATELESS_TOKEN = "stateless";
+
+        @Override
+        public Object decode(FacesContext facesContext, String token)
+        {
+            if (STATELESS_TOKEN.equals(token))
+            {
+                // Should not happen, because ResponseStateManager.isStateless(context,viewId) should
+                // catch it first
+                return null;
+            }
+            Object savedStateObject = StateUtils.reconstruct((String)token, facesContext.getExternalContext());
+            return savedStateObject;
+        }
+
+        @Override
+        public String encode(FacesContext facesContext, Object savedStateObject)
+        {
+            if (facesContext.getViewRoot().isTransient())
+            {
+                return STATELESS_TOKEN;
+            }
+            String serializedState = StateUtils.construct(savedStateObject, facesContext.getExternalContext());
+            return serializedState;
+        }
+
+        @Override
+        public boolean isStateless(FacesContext facesContext, String token)
+        {
+            return STATELESS_TOKEN.equals(token);
+        }
+    }
 }

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=1518443&r1=1518442&r2=1518443&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 Aug 29 02:21:08 2013
@@ -329,7 +329,7 @@ public class DefaultFaceletsStateManagem
             }
 
             // Stateless mode only for transient views and non stateless mode for
-            // stateful views.
+            // stateful views. This check avoid apply state over a stateless view.
             boolean statelessMode = manager.isStateless(context, viewId);
             if (statelessMode && !view.isTransient())
             {

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java?rev=1518443&r1=1518442&r2=1518443&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java Thu Aug 29 02:21:08 2013
@@ -27,6 +27,7 @@ import java.io.Writer;
 import java.lang.reflect.Array;
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -43,6 +44,8 @@ import javax.el.ValueExpression;
 import javax.el.VariableMapper;
 import javax.faces.FacesException;
 import javax.faces.FacesWrapper;
+import javax.faces.FactoryFinder;
+import javax.faces.application.Application;
 import javax.faces.application.ProjectStage;
 import javax.faces.application.Resource;
 import javax.faces.application.StateManager;
@@ -52,6 +55,7 @@ import javax.faces.component.EditableVal
 import javax.faces.component.UIComponent;
 import javax.faces.component.UINamingContainer;
 import javax.faces.component.UIPanel;
+import javax.faces.component.UIViewParameter;
 import javax.faces.component.UIViewRoot;
 import javax.faces.context.ExternalContext;
 import javax.faces.context.FacesContext;
@@ -67,6 +71,8 @@ import javax.faces.event.PreRemoveFromVi
 import javax.faces.event.ValueChangeEvent;
 import javax.faces.event.ValueChangeListener;
 import javax.faces.render.RenderKit;
+import javax.faces.render.RenderKitFactory;
+import javax.faces.render.ResponseStateManager;
 import javax.faces.validator.MethodExpressionValidator;
 import javax.faces.validator.Validator;
 import javax.faces.view.ActionSource2AttachedObjectHandler;
@@ -300,6 +306,8 @@ public class FaceletViewDeclarationLangu
     private FaceletFactory _faceletFactory;
 
     private StateManagementStrategy _stateMgmtStrategy;
+    
+    private RenderKitFactory _renderKitFactory = null;
 
     private boolean _partialStateSaving;
 
@@ -516,7 +524,8 @@ public class FaceletViewDeclarationLangu
             // DefaultFaceletsStateManagement.restoreView after calling 
             // _publishPostBuildComponentTreeOnRestoreViewEvent(), to ensure 
             // relocated components are not retrieved later on getClientIdsRemoved().
-            if (!(refreshTransientBuild && PhaseId.RESTORE_VIEW.equals(context.getCurrentPhaseId())))
+            if (!(refreshTransientBuild && PhaseId.RESTORE_VIEW.equals(context.getCurrentPhaseId())) &&
+                !view.isTransient())
             {
                 ((DefaultFaceletsStateManagementStrategy) getStateManagementStrategy(context, view.getViewId())).
                         suscribeListeners(view);
@@ -2113,38 +2122,60 @@ public class FaceletViewDeclarationLangu
             context, viewId);
         context.setResourceLibraryContracts(contracts);
         
-        return super.restoreView(context, viewId);
-        //}
-        //else
-        //{
-        // TODO: VALIDATE - Is _buildBeforeRestore relevant at all for 2.0? -= SL =-
-        // ANS: buildBeforeRestore evolved to partial state saving, so this logic
-        // is now on StateManagerStrategy implementation -= Leo U =-
-        /*
-            UIViewRoot viewRoot = createView(context, viewId);
-
-            context.setViewRoot(viewRoot);
+        // JSF 2.2 stateless views
+        // We need to check if the incoming view is stateless or not and if that so rebuild it here
+        // note we cannot do this in DefaultFaceletsStateManagementStrategy because it is only used
+        // when PSS is enabled, but stateless views can be used without PSS. If the view is stateless,
+        // there is no need to ask to the StateManager.
+        Application application = context.getApplication();
+        ViewHandler applicationViewHandler = application.getViewHandler();
+        String renderKitId = applicationViewHandler.calculateRenderKitId(context);
 
+        ResponseStateManager manager = getRenderKitFactory().getRenderKit(
+            context, renderKitId).getResponseStateManager();
+        
+        if (manager.isStateless(context, viewId))
+        {
+            // Per the spec: build the view.
+            UIViewRoot view = null;
             try
             {
-                buildView(context, viewRoot);
+                ViewMetadata metadata = vdl.getViewMetadata (context, viewId);
+                Collection<UIViewParameter> viewParameters = null;
+                if (metadata != null)
+                {
+                    view = metadata.createMetadataView(context);
+                    if (view != null)
+                    {
+                        viewParameters = metadata.getViewParameters(view);
+                    }
+                }
+                if (view == null)
+                {
+                    view = context.getApplication().getViewHandler().createView(context, viewId);
+                }
+                context.setViewRoot (view); 
+                boolean oldContextEventState = context.isProcessingEvents();
+                try 
+                {
+                    context.setProcessingEvents (true);
+                    vdl.buildView (context, view);
+                }
+                finally
+                {
+                    context.setProcessingEvents (oldContextEventState);
+                } 
             }
-            catch (IOException ioe)
+            catch (Throwable e)
             {
-                log.severe("Error Building View", ioe);
+                throw new FacesException ("unable to create view \"" + viewId + "\"", e);
             }
-
-            Application application = context.getApplication();
-
-            ViewHandler applicationViewHandler = application.getViewHandler();
-
-            String renderKitId = applicationViewHandler.calculateRenderKitId(context);
-
-            application.getStateManager().restoreView(context, viewId, renderKitId);
-
-            return viewRoot;
+            return view;
+        }
+        else
+        {
+            return super.restoreView(context, viewId);
         }
-        */
     }
 
     /**
@@ -2215,12 +2246,21 @@ public class FaceletViewDeclarationLangu
 
         // resource resolver
         ResourceResolver resolver = new DefaultResourceResolver();
+        ArrayList<String> classNames = new ArrayList<String>();
         String faceletsResourceResolverClassName = WebConfigParamUtils.getStringInitParameter(eContext,
                 PARAMS_RESOURCE_RESOLVER, null);
+        List<String> resourceResolversFromAnnotations = RuntimeConfig.getCurrentInstance(
+            context.getExternalContext()).getResourceResolvers();
         if (faceletsResourceResolverClassName != null)
         {
-            ArrayList<String> classNames = new ArrayList<String>(1);
             classNames.add(faceletsResourceResolverClassName);
+        }
+        if (!resourceResolversFromAnnotations.isEmpty())
+        {
+            classNames.addAll(resourceResolversFromAnnotations);
+        }
+        if (!classNames.isEmpty())
+        {
             resolver = ClassUtils.buildApplicationObject(ResourceResolver.class, classNames, resolver);
         }
 
@@ -2947,4 +2987,13 @@ public class FaceletViewDeclarationLangu
         }
         return createdComponent;
     }
-}
+    
+    protected RenderKitFactory getRenderKitFactory()
+    {
+        if (_renderKitFactory == null)
+        {
+            _renderKitFactory = (RenderKitFactory)FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
+        }
+        return _renderKitFactory;
+    }
+}
\ No newline at end of file

Modified: myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/StateManagerWithFaceletsTest.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/StateManagerWithFaceletsTest.java?rev=1518443&r1=1518442&r2=1518443&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/StateManagerWithFaceletsTest.java (original)
+++ myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/StateManagerWithFaceletsTest.java Thu Aug 29 02:21:08 2013
@@ -27,6 +27,7 @@ import org.apache.myfaces.application.St
 import org.apache.myfaces.renderkit.html.HtmlResponseStateManager;
 import org.apache.myfaces.shared.util.StateUtils;
 import org.apache.myfaces.shared_impl.util.serial.DefaultSerialFactory;
+import org.apache.myfaces.test.mock.MockFacesContext20;
 import org.apache.myfaces.test.mock.MockRenderKit;
 import org.junit.Test;
 import org.testng.Assert;
@@ -78,6 +79,7 @@ public class StateManagerWithFaceletsTes
             setupRequest();
             
             request.addParameter(ResponseStateManager.VIEW_STATE_PARAM, viewStateParam);
+            ((MockFacesContext20)facesContext).setPostback(true);
     
             UIViewRoot restoredViewRoot = application.getStateManager().restoreView(facesContext, "/simpleTree.xhtml", RenderKitFactory.HTML_BASIC_RENDER_KIT);
             
@@ -121,6 +123,7 @@ public class StateManagerWithFaceletsTes
             setupRequest();
             
             request.addParameter(ResponseStateManager.VIEW_STATE_PARAM, viewStateParam);
+            ((MockFacesContext20)facesContext).setPostback(true);
     
             UIViewRoot restoredViewRoot = application.getStateManager().restoreView(facesContext, "/simpleTree.xhtml", RenderKitFactory.HTML_BASIC_RENDER_KIT);