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);