diff --git a/spring-faces/.classpath b/spring-faces/.classpath
index 271552c4..b59bd22d 100644
--- a/spring-faces/.classpath
+++ b/spring-faces/.classpath
@@ -8,8 +8,8 @@
-
-
+
+
diff --git a/spring-faces/ivy.xml b/spring-faces/ivy.xml
index 28f3082f..89b9d96f 100644
--- a/spring-faces/ivy.xml
+++ b/spring-faces/ivy.xml
@@ -42,8 +42,8 @@
-
-
+
+
diff --git a/spring-faces/pom.xml b/spring-faces/pom.xml
index 3e3b75c9..caa8d05a 100644
--- a/spring-faces/pom.xml
+++ b/spring-faces/pom.xml
@@ -57,12 +57,6 @@
spring-webflow${project.version}
-
- com.sun.facelets
- jsf-facelets
- 1.1.14
- true
- org.richfaces.frameworkrichfaces-api
@@ -82,15 +76,15 @@
provided
- javax.faces
+ com.sun.facesjsf-api
- 2.0
+ 2.0.3provided
- javax.faces
+ com.sun.facesjsf-impl
- 2.0.2
+ 2.0.3provided
diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowFacesContext.java b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowFacesContext.java
index 96df2c61..1c8bbd74 100644
--- a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowFacesContext.java
+++ b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowFacesContext.java
@@ -58,6 +58,8 @@ public class FlowFacesContext extends FacesContext {
private FlowFacesContextMessageDelegate messageDelegate;
+ private ExternalContext externalContext;
+
/**
* The base FacesContext delegate
*/
@@ -77,6 +79,7 @@ public class FlowFacesContext extends FacesContext {
this.context = context;
this.delegate = delegate;
this.messageDelegate = new FlowFacesContextMessageDelegate(context);
+ this.externalContext = new FlowExternalContext(delegate.getExternalContext());
setCurrentInstance(this);
}
@@ -160,7 +163,7 @@ public class FlowFacesContext extends FacesContext {
}
public ExternalContext getExternalContext() {
- return new FlowExternalContext(delegate.getExternalContext());
+ return externalContext;
}
public RenderKit getRenderKit() {
diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowFacesContextLifecycleListener.java b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowFacesContextLifecycleListener.java
new file mode 100644
index 00000000..8932832f
--- /dev/null
+++ b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowFacesContextLifecycleListener.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2004-2010 the original author or authors.
+ *
+ * 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.springframework.faces.webflow;
+
+import javax.faces.context.FacesContext;
+
+import org.springframework.webflow.execution.FlowExecutionListener;
+import org.springframework.webflow.execution.FlowExecutionListenerAdapter;
+import org.springframework.webflow.execution.RequestContext;
+
+/**
+ * A {@link FlowExecutionListener} that creates a {@link FlowFacesContext} instance when a flow request is submitted and
+ * releases it when the request has been processed.
+ *
+ * @author Rossen Stoyanchev
+ */
+public class FlowFacesContextLifecycleListener extends FlowExecutionListenerAdapter {
+
+ /**
+ * Creates a new instance of {@link FlowFacesContext} that is then available for the duration of the request.
+ * @param context the current flow request context
+ */
+ public void requestSubmitted(RequestContext context) {
+ FlowFacesContext.newInstance(context, FlowLifecycle.newInstance());
+ }
+
+ /**
+ * Releases the current {@link FlowFacesContext} instance.
+ * @param context the source of the event
+ */
+ public void requestProcessed(RequestContext context) {
+ FacesContext.getCurrentInstance().release();
+ }
+
+}
diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowRenderKit.java b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowRenderKit.java
new file mode 100644
index 00000000..bcf3420b
--- /dev/null
+++ b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowRenderKit.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2004-2010 the original author or authors.
+ *
+ * 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.springframework.faces.webflow;
+
+/**
+ * A render kit implementation that ensures use of Web Flow's FlowViewResponseStateManager, which takes over reading and
+ * writing JSF state and manages that in Web Flow's view scope. The FlowViewResponseStateManager is plugged in only in a
+ * JSF 2 environment.
+ *
+ * @author Rossen Stoyanchev
+ * @since 2.2.0
+ */
+import javax.faces.render.RenderKit;
+import javax.faces.render.RenderKitWrapper;
+import javax.faces.render.ResponseStateManager;
+
+public class FlowRenderKit extends RenderKitWrapper {
+
+ private RenderKit delegate;
+
+ private FlowViewResponseStateManager responseStateManager;
+
+ public FlowRenderKit(RenderKit delegate) {
+ this.delegate = delegate;
+ if (JsfRuntimeInformation.isAtLeastJsf20()) {
+ this.responseStateManager = new FlowViewResponseStateManager(delegate.getResponseStateManager());
+ }
+ }
+
+ public RenderKit getWrapped() {
+ return delegate;
+ }
+
+ /**
+ * Returns an instance of {@link FlowViewResponseStateManager} in a JSF 2 environment or returns the delegates's
+ * ResponseStateManager instance otherwise.
+ */
+ public ResponseStateManager getResponseStateManager() {
+ return (JsfRuntimeInformation.isAtLeastJsf20()) ? responseStateManager : delegate.getResponseStateManager();
+ }
+
+}
diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowViewResponseStateManager.java b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowViewResponseStateManager.java
new file mode 100644
index 00000000..25deb785
--- /dev/null
+++ b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowViewResponseStateManager.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2004-2010 the original author or authors.
+ *
+ * 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.springframework.faces.webflow;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import javax.faces.context.FacesContext;
+import javax.faces.context.ResponseWriter;
+import javax.faces.render.RenderKitFactory;
+import javax.faces.render.ResponseStateManager;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.webflow.execution.RequestContext;
+import org.springframework.webflow.execution.RequestContextHolder;
+
+/**
+ *
+ * A custom ResponseStateManager that writes JSF state to a Web Flow managed view-scoped variable. This class is plugged
+ * in via {@link FlowRenderKit} in JSF 2 runtime environments only.
+ *
+ *
+ *
+ * In JSF 2 where a partial state saving algorithm is used, Web Flow delegates to the JSF 2 runtime to handle state
+ * saving. However, an instance of this class plugged in via {@link FlowRenderKit} will ensure that state is saved in a
+ * Web Flow managed view-scoped variable.
+ *
+ * Wraps state in an instance of {@link FlowSerializedView} and stores it in view scope.
+ *
+ *
+ *
+ * Also complies with the contract for {@link ResponseStateManager#writeState(FacesContext, Object)} by writing the
+ * "javax.faces.ViewState" and optionally the "javax.faces.RenderKitId" hidden input fields to the response.
+ *
+ * Retrieves the state from view scope as an instance of {@link FlowSerializedView} and turns it to an array before
+ * returning.
+ *
+ */
+ @Override
+ public Object getState(FacesContext facesContext, String viewId) {
+ if (!JsfUtils.isFlowRequest()) {
+ return delegate.getState(facesContext, viewId);
+ }
+ RequestContext requestContext = RequestContextHolder.getRequestContext();
+ FlowSerializedView view = (FlowSerializedView) requestContext.getViewScope().get(
+ FlowViewStateManager.SERIALIZED_VIEW_STATE);
+ Object[] state = null;
+ if (view == null) {
+ logger.debug("No matching view in view scope");
+ } else {
+ state = new Object[] { view.getTreeStructure(), view.getComponentState() };
+ }
+ return state;
+ }
+
+ /**
+ * This method returns the flow execution key to be used as the value for the "javax.faces.ViewState" hidden input
+ * field. The value of this key is not important because JSF state is stored in a Web Flow managed view scoped
+ * variable. However the presence of the view state parameter alone is important for triggering actions. Hence we
+ * return the most logical value, which is the flow execution key.
+ */
+ @Override
+ public String getViewState(FacesContext facesContext, Object state) {
+ if (!JsfUtils.isFlowRequest()) {
+ return delegate.getViewState(facesContext, state);
+ }
+ return getFlowExecutionKey();
+ }
+
+ // ------------------- Delegation methods ------------------//
+
+ @SuppressWarnings( { "deprecation" })
+ @Override
+ public Object getTreeStructureToRestore(FacesContext context, String viewId) {
+ return delegate.getTreeStructureToRestore(context, viewId);
+ }
+
+ @SuppressWarnings( { "deprecation" })
+ @Override
+ public Object getComponentStateToRestore(FacesContext context) {
+ return delegate.getComponentStateToRestore(context);
+ }
+
+ // ------------------- Private helper methods ------------------//
+
+ private String getFlowExecutionKey() {
+ RequestContext requestContext = RequestContextHolder.getRequestContext();
+ return requestContext.getFlowExecutionContext().getKey().toString();
+ }
+
+ /**
+ * See comments on {@link ResponseStateManager#VIEW_STATE_PARAM}.
+ *
+ * @param context the FacesContext for the current request
+ * @param writer the ResponseWriter to write to
+ * @throws IOException if an error occurs writing to the client
+ */
+ private void writeViewStateField(FacesContext context, Writer writer) throws IOException {
+ writer.write(stateFieldStart);
+ writer.write(getFlowExecutionKey());
+ writer.write(stateFieldEnd);
+ }
+
+ /**
+ * See comments on ResponseStateManager.RENDER_KIT_ID_PARAM in
+ * {@link ResponseStateManager#writeState(FacesContext, Object)}.
+ *
+ * @param context the FacesContext for the current request
+ * @param writer the ResponseWriter to write to
+ * @throws IOException if an error occurs writing to the client
+ */
+ private void writeRenderKitIdField(FacesContext context, ResponseWriter writer) throws IOException {
+ String result = context.getApplication().getDefaultRenderKitId();
+ if (result != null && !RenderKitFactory.HTML_BASIC_RENDER_KIT.equals(result)) {
+ writer.startElement("input", context.getViewRoot());
+ writer.writeAttribute("type", "hidden", "type");
+ writer.writeAttribute("name", ResponseStateManager.RENDER_KIT_ID_PARAM, "name");
+ writer.writeAttribute("value", result, "value");
+ writer.endElement("input");
+ }
+ }
+
+}
diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowViewStateManager.java b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowViewStateManager.java
index 9c81325b..fcbacb15 100644
--- a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowViewStateManager.java
+++ b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowViewStateManager.java
@@ -15,6 +15,8 @@
*/
package org.springframework.faces.webflow;
+import static org.springframework.faces.webflow.JsfRuntimeInformation.isAtLeastJsf20;
+
import java.io.IOException;
import javax.faces.application.StateManager;
@@ -35,7 +37,7 @@ public class FlowViewStateManager extends StateManager {
private static final Log logger = LogFactory.getLog(FlowViewStateManager.class);
- private static final String SERIALIZED_VIEW_STATE = "flowSerializedViewState";
+ protected static final String SERIALIZED_VIEW_STATE = "flowSerializedViewState";
private StateManager delegate;
@@ -136,49 +138,78 @@ public class FlowViewStateManager extends StateManager {
if (!JsfUtils.isFlowRequest()) {
return delegate.saveSerializedView(context);
}
- FlowSerializedView view = (FlowSerializedView) saveView(context);
- return new javax.faces.application.StateManager.SerializedView(view.getTreeStructure(), view
- .getComponentState());
+ Object state = saveView(context);
+ if (state instanceof FlowSerializedView) {
+ FlowSerializedView serializedState = (FlowSerializedView) state;
+ return new javax.faces.application.StateManager.SerializedView(serializedState.getTreeStructure(),
+ serializedState.getComponentState());
+ } else {
+ Object[] serializedState = (Object[]) state;
+ return new javax.faces.application.StateManager.SerializedView(serializedState[0], serializedState[1]);
+ }
}
/**
- * JSF 1.2 version of state saving
+ *
+ * JSF 1.2 (or higher) version of state saving.
+ *
+ *
+ *
+ * In JSF 2 where a partial state saving algorithm is used, this method merely delegates to the next
+ * ViewStateManager. Thus partial state saving is handled by the JSF 2 runtime. However, a
+ * {@link FlowViewResponseStateManager} plugged in via {@link FlowRenderKit} will ensure the state is saved in a Web
+ * Flow view-scoped variable.
+ *
+ * In JSF 2 where a partial state saving algorithm is used, this method merely delegates to the next
+ * ViewStateManager. Thus partial state saving is handled by the JSF 2 runtime. However, a
+ * {@link FlowViewResponseStateManager} plugged in via {@link FlowRenderKit} will ensure the state is saved in a Web
+ * Flow view-scoped variable.
+ *
+ */
public UIViewRoot restoreView(FacesContext context, String viewId, String renderKitId) {
- if (!JsfUtils.isFlowRequest()) {
+ if ((!JsfUtils.isFlowRequest()) || isAtLeastJsf20()) {
return delegate.restoreView(context, viewId, renderKitId);
+ } else {
+ UIViewRoot viewRoot = restoreTreeStructure(context, viewId, renderKitId);
+ if (viewRoot != null) {
+ context.setViewRoot(viewRoot);
+ restoreComponentState(context, viewRoot, renderKitId);
+ }
+ return viewRoot;
}
- UIViewRoot viewRoot = restoreTreeStructure(context, viewId, renderKitId);
- if (viewRoot != null) {
- context.setViewRoot(viewRoot);
- restoreComponentState(context, viewRoot, renderKitId);
- }
- return viewRoot;
}
@Override
public String getViewState(FacesContext context) {
+ if (!JsfUtils.isFlowRequest()) {
+ return delegate.getViewState(context);
+ }
/*
- * Mojarra 2: PartialRequestContextImpl.renderState() invokes this method during Ajax request rendering. It is
- * overridden to convert FlowSerializedView to an array containing tree structure and component state. The
- * ResponseStateManager.getViewState() calls the ServerSideStateHelper, which expects the array.
+ * Mojarra 2: PartialRequestContextImpl.renderState() invokes this method during Ajax request rendering. We
+ * overridde it to convert FlowSerializedView state to an array before calling the
+ * ResponseStateManager.getViewState(), which in turn calls the ServerSideStateHelper and expects state to be an
+ * array.
*/
Object state = saveView(context);
if (state != null) {
diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/Jsf2FlowFacesContext.java b/spring-faces/src/main/java/org/springframework/faces/webflow/Jsf2FlowFacesContext.java
index 742403de..fc4e5bcc 100644
--- a/spring-faces/src/main/java/org/springframework/faces/webflow/Jsf2FlowFacesContext.java
+++ b/spring-faces/src/main/java/org/springframework/faces/webflow/Jsf2FlowFacesContext.java
@@ -32,6 +32,8 @@ import javax.faces.context.PartialViewContext;
import javax.faces.context.PartialViewContextFactory;
import javax.faces.event.PhaseId;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.springframework.webflow.execution.RequestContext;
/**
@@ -41,6 +43,8 @@ import org.springframework.webflow.execution.RequestContext;
*/
public class Jsf2FlowFacesContext extends FlowFacesContext {
+ private ExternalContext externalContext;
+
/*
* This partialViewContext duplicates the one FacesContextImpl because the constructor of FacesContextImpl calls
* getPartialViewContext(), which causes it to be instantiated with an instance of FacesContextImpl. This leads to
@@ -52,13 +56,15 @@ public class Jsf2FlowFacesContext extends FlowFacesContext {
public Jsf2FlowFacesContext(RequestContext context, FacesContext delegate) {
super(context, delegate);
+ this.externalContext = new Jsf2FlowExternalContext(getDelegate().getExternalContext());
+
PartialViewContextFactory f = (PartialViewContextFactory) FactoryFinder
.getFactory(FactoryFinder.PARTIAL_VIEW_CONTEXT_FACTORY);
- partialViewContext = f.getPartialViewContext(this);
+ this.partialViewContext = f.getPartialViewContext(this);
}
public ExternalContext getExternalContext() {
- return new Jsf2FlowExternalContext(getDelegate().getExternalContext());
+ return externalContext;
}
// --------------- JSF 2.0 Pass-through delegate methods ------------------//
@@ -128,10 +134,17 @@ public class Jsf2FlowFacesContext extends FlowFacesContext {
protected class Jsf2FlowExternalContext extends FlowExternalContext {
+ Log logger = LogFactory.getLog(FlowExternalContext.class);
+
public Jsf2FlowExternalContext(ExternalContext delegate) {
super(delegate);
}
+ public void responseSendError(int statusCode, String message) throws IOException {
+ logger.debug("Sending error HTTP status code " + statusCode + " with message '" + message + "'");
+ delegate.responseSendError(statusCode, message);
+ }
+
// --------------- JSF 2.0 Pass-through delegate methods ------------------//
public String getContextName() {
@@ -210,10 +223,6 @@ public class Jsf2FlowFacesContext extends FlowFacesContext {
delegate.responseReset();
}
- public void responseSendError(int statusCode, String message) throws IOException {
- delegate.responseSendError(statusCode, message);
- }
-
public void setResponseStatus(int statusCode) {
delegate.setResponseStatus(statusCode);
}
diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/JsfView.java b/spring-faces/src/main/java/org/springframework/faces/webflow/JsfView.java
index d9643d43..ed7cfb63 100644
--- a/spring-faces/src/main/java/org/springframework/faces/webflow/JsfView.java
+++ b/spring-faces/src/main/java/org/springframework/faces/webflow/JsfView.java
@@ -16,6 +16,7 @@
package org.springframework.faces.webflow;
import static org.springframework.faces.webflow.JsfRuntimeInformation.isAtLeastJsf12;
+import static org.springframework.faces.webflow.JsfRuntimeInformation.isLessThanJsf20;
import java.io.IOException;
import java.io.Serializable;
@@ -79,7 +80,7 @@ public class JsfView implements View {
* Performs the standard duties of the JSF RENDER_RESPONSE phase.
*/
public void render() throws IOException {
- FacesContext facesContext = FlowFacesContext.newInstance(requestContext, facesLifecycle);
+ FacesContext facesContext = FlowFacesContext.getCurrentInstance();
if (facesContext.getResponseComplete()) {
return;
}
@@ -90,7 +91,6 @@ public class JsfView implements View {
} finally {
logger.debug("View rendering complete");
facesContext.responseComplete();
- facesContext.release();
}
}
@@ -107,15 +107,11 @@ public class JsfView implements View {
* INVOKE_APPLICATION.
*/
public void processUserEvent() {
- FacesContext facesContext = FlowFacesContext.newInstance(requestContext, facesLifecycle);
+ FacesContext facesContext = FlowFacesContext.getCurrentInstance();
facesContext.setViewRoot(viewRoot);
- try {
- // Must respect these flags in case user set them during RESTORE_VIEW phase
- if (!facesContext.getRenderResponse() && !facesContext.getResponseComplete()) {
- facesLifecycle.execute(facesContext);
- }
- } finally {
- facesContext.release();
+ // Must respect these flags in case user set them during RESTORE_VIEW phase
+ if (!facesContext.getRenderResponse() && !facesContext.getResponseComplete()) {
+ facesLifecycle.execute(facesContext);
}
}
@@ -124,22 +120,26 @@ public class JsfView implements View {
* snapshot
*/
public void saveState() {
- FacesContext facesContext = FlowFacesContext.newInstance(requestContext, facesLifecycle);
+ FacesContext facesContext = FlowFacesContext.getCurrentInstance();
if (viewRoot instanceof AjaxViewRoot) {
facesContext.setViewRoot(((AjaxViewRoot) viewRoot).getOriginalViewRoot());
} else {
facesContext.setViewRoot(viewRoot);
}
- try {
- facesContext.getApplication().getStateManager().saveSerializedView(facesContext);
- } finally {
- facesContext.release();
- }
+ facesContext.getApplication().getStateManager().saveSerializedView(facesContext);
}
public Serializable getUserEventState() {
- // Set the temporary UIViewRoot state so that it will be available across the redirect
- return new ViewRootHolder(getViewRoot());
+ if (isLessThanJsf20()) {
+ // Set the temporary UIViewRoot state so that it will be available across the redirect
+ return new ViewRootHolder(getViewRoot());
+ } else {
+ // In JSF 2 the partial state saving algorithm attaches a system event listener to the UIViewRoot with
+ // a reference to the FacesContext instance. The FacesContext instance is released at end of each request.
+ // Hence, keeping the UIViewRoot across the redirect is not feasible.
+ logger.debug("User event state requested but not saved.");
+ return null;
+ }
}
public boolean hasFlowEvent() {
diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/JsfViewFactory.java b/spring-faces/src/main/java/org/springframework/faces/webflow/JsfViewFactory.java
index ae4e6594..1d9a4f45 100644
--- a/spring-faces/src/main/java/org/springframework/faces/webflow/JsfViewFactory.java
+++ b/spring-faces/src/main/java/org/springframework/faces/webflow/JsfViewFactory.java
@@ -17,7 +17,6 @@ package org.springframework.faces.webflow;
import static org.springframework.faces.webflow.JsfRuntimeInformation.isAtLeastJsf12;
import static org.springframework.faces.webflow.JsfRuntimeInformation.isAtLeastJsf20;
-import static org.springframework.faces.webflow.JsfRuntimeInformation.isLessThanJsf20;
import static org.springframework.faces.webflow.JsfRuntimeInformation.isPortletRequest;
import java.util.Iterator;
@@ -72,65 +71,61 @@ public class JsfViewFactory implements ViewFactory {
* be rendered in the case of an executing transition.
*/
public View getView(RequestContext context) {
- FacesContext facesContext = FlowFacesContext.newInstance(context, lifecycle);
- try {
- if (isAtLeastJsf20()) {
- facesContext.setCurrentPhaseId(PhaseId.RESTORE_VIEW);
+ FacesContext facesContext = FlowFacesContext.getCurrentInstance();
+ if (isAtLeastJsf20()) {
+ facesContext.setCurrentPhaseId(PhaseId.RESTORE_VIEW);
+ }
+ if (!facesContext.getRenderResponse()) {
+ // only publish a RESTORE_VIEW event if this is the first phase of the lifecycle
+ // this won't be true when this method is called after a transition from one view-state to another
+ JsfUtils.notifyBeforeListeners(PhaseId.RESTORE_VIEW, lifecycle, facesContext);
+ }
+ ViewHandler viewHandler = facesContext.getApplication().getViewHandler();
+ if (isAtLeastJsf12() && (!isPortletRequest(facesContext))) {
+ viewHandler.initView(facesContext);
+ }
+ JsfView view;
+ String viewName = (String) viewIdExpression.getValue(context);
+ if (viewAlreadySet(facesContext, viewName)) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Existing view root found with id '" + facesContext.getViewRoot().getId() + "'");
}
- if (!facesContext.getRenderResponse()) {
- // only publish a RESTORE_VIEW event if this is the first phase of the lifecycle
- // this won't be true when this method is called after a transition from one view-state to another
- JsfUtils.notifyBeforeListeners(PhaseId.RESTORE_VIEW, lifecycle, facesContext);
- }
- ViewHandler viewHandler = facesContext.getApplication().getViewHandler();
- if (isAtLeastJsf12() && (!isPortletRequest(facesContext))) {
- viewHandler.initView(facesContext);
- }
- JsfView view;
- String viewName = (String) viewIdExpression.getValue(context);
- if (viewAlreadySet(facesContext, viewName)) {
- if (logger.isDebugEnabled()) {
- logger.debug("Existing view root found with id '" + facesContext.getViewRoot().getId() + "'");
- }
- UIViewRoot viewRoot = facesContext.getViewRoot();
- viewRoot.setLocale(context.getExternalContext().getLocale());
- processTree(facesContext, viewRoot);
- view = createJsfView(facesContext.getViewRoot(), lifecycle, context);
- } else {
- if (context.inViewState()) {
- UIViewRoot viewRoot = viewHandler.restoreView(facesContext, viewName);
- if (viewRoot != null) {
- if (logger.isDebugEnabled()) {
- logger.debug("UIViewRoot restored for '" + viewName + "'");
- }
- facesContext.setViewRoot(viewRoot);
- processTree(facesContext, viewRoot);
- view = createJsfView(viewRoot, lifecycle, context);
- } else {
- if (logger.isDebugEnabled()) {
- logger.debug("Creating UIViewRoot from '" + viewName + "'");
- }
- viewRoot = viewHandler.createView(facesContext, viewName);
- facesContext.setViewRoot(viewRoot);
- view = createJsfView(viewRoot, lifecycle, context);
+ UIViewRoot viewRoot = facesContext.getViewRoot();
+ viewRoot.setLocale(context.getExternalContext().getLocale());
+ processTree(facesContext, viewRoot);
+ view = createJsfView(facesContext.getViewRoot(), lifecycle, context);
+ } else {
+ if (context.inViewState()) {
+ UIViewRoot viewRoot = viewHandler.restoreView(facesContext, viewName);
+ if (viewRoot != null) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("UIViewRoot restored for '" + viewName + "'");
}
+ facesContext.setViewRoot(viewRoot);
+ processTree(facesContext, viewRoot);
+ view = createJsfView(viewRoot, lifecycle, context);
} else {
if (logger.isDebugEnabled()) {
- logger.debug("Creating transient UIViewRoot from '" + viewName + "'");
+ logger.debug("Creating UIViewRoot from '" + viewName + "'");
}
- UIViewRoot viewRoot = viewHandler.createView(facesContext, viewName);
- viewRoot.setTransient(true);
+ viewRoot = viewHandler.createView(facesContext, viewName);
facesContext.setViewRoot(viewRoot);
view = createJsfView(viewRoot, lifecycle, context);
}
+ } else {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Creating transient UIViewRoot from '" + viewName + "'");
+ }
+ UIViewRoot viewRoot = viewHandler.createView(facesContext, viewName);
+ viewRoot.setTransient(true);
+ facesContext.setViewRoot(viewRoot);
+ view = createJsfView(viewRoot, lifecycle, context);
}
- if (!facesContext.getRenderResponse()) {
- JsfUtils.notifyAfterListeners(PhaseId.RESTORE_VIEW, lifecycle, facesContext);
- }
- return view;
- } finally {
- facesContext.release();
}
+ if (!facesContext.getRenderResponse()) {
+ JsfUtils.notifyAfterListeners(PhaseId.RESTORE_VIEW, lifecycle, facesContext);
+ }
+ return view;
}
private boolean viewAlreadySet(FacesContext facesContext, String viewName) {
@@ -143,7 +138,7 @@ public class JsfViewFactory implements ViewFactory {
}
private JsfView createJsfView(UIViewRoot root, Lifecycle lifecycle, RequestContext context) {
- if (isLessThanJsf20() && isSpringJavascriptAjaxRequest(context.getExternalContext())) {
+ if (isSpringJavascriptAjaxRequest(context.getExternalContext())) {
root = new AjaxViewRoot(root);
}
return new JsfView(root, lifecycle, context);
diff --git a/spring-faces/src/main/resources/META-INF/faces-config.xml b/spring-faces/src/main/resources/META-INF/faces-config.xml
index 0ef11f11..c5a1cb66 100644
--- a/spring-faces/src/main/resources/META-INF/faces-config.xml
+++ b/spring-faces/src/main/resources/META-INF/faces-config.xml
@@ -88,6 +88,7 @@
HTML_BASIC
+ org.springframework.faces.webflow.FlowRenderKitjavax.faces.Command
diff --git a/spring-faces/src/test/java/org/springframework/faces/ui/ProgressiveCommandLinkRendererTests.java b/spring-faces/src/test/java/org/springframework/faces/ui/ProgressiveCommandLinkRendererTests.java
index 93e1ec4c..cedb8036 100644
--- a/spring-faces/src/test/java/org/springframework/faces/ui/ProgressiveCommandLinkRendererTests.java
+++ b/spring-faces/src/test/java/org/springframework/faces/ui/ProgressiveCommandLinkRendererTests.java
@@ -1,13 +1,10 @@
package org.springframework.faces.ui;
-import java.io.StringWriter;
-
import javax.faces.component.UIForm;
import javax.faces.component.UIParameter;
import junit.framework.TestCase;
-import org.apache.myfaces.test.mock.MockResponseWriter;
import org.springframework.faces.webflow.JSFMockHelper;
public class ProgressiveCommandLinkRendererTests extends TestCase {
@@ -16,15 +13,11 @@ public class ProgressiveCommandLinkRendererTests extends TestCase {
ProgressiveCommandLinkRenderer renderer = new ProgressiveCommandLinkRenderer();
- StringWriter output = new StringWriter();
-
public void setUp() throws Exception {
jsf.setUp();
- jsf.facesContext().setResponseWriter(new MockResponseWriter(output, null, null));
}
public void tearDown() throws Exception {
- System.out.println(output);
jsf.tearDown();
}
@@ -47,7 +40,7 @@ public class ProgressiveCommandLinkRendererTests extends TestCase {
jsf.facesContext().getResponseWriter().endElement("a");
- assertEquals(expected, output.toString());
+ assertEquals(expected, jsf.contentAsString());
}
public void testRenderOnClick_AjaxEnabled_WithParams() throws Exception {
@@ -78,7 +71,7 @@ public class ProgressiveCommandLinkRendererTests extends TestCase {
jsf.facesContext().getResponseWriter().endElement("a");
- assertEquals(expected, output.toString());
+ assertEquals(expected, jsf.contentAsString());
}
public void testRenderOnClick_AjaxDisabled_NoParams() throws Exception {
@@ -100,7 +93,7 @@ public class ProgressiveCommandLinkRendererTests extends TestCase {
jsf.facesContext().getResponseWriter().endElement("a");
- assertEquals(expected, output.toString());
+ assertEquals(expected, jsf.contentAsString());
}
public void testRenderOnClick_AjaxDisabled_WithParams() throws Exception {
@@ -132,6 +125,6 @@ public class ProgressiveCommandLinkRendererTests extends TestCase {
jsf.facesContext().getResponseWriter().endElement("a");
- assertEquals(expected, output.toString());
+ assertEquals(expected, jsf.contentAsString());
}
}
diff --git a/spring-faces/src/test/java/org/springframework/faces/webflow/JSFMockHelper.java b/spring-faces/src/test/java/org/springframework/faces/webflow/JSFMockHelper.java
index 74fdf966..c73b6d0b 100644
--- a/spring-faces/src/test/java/org/springframework/faces/webflow/JSFMockHelper.java
+++ b/spring-faces/src/test/java/org/springframework/faces/webflow/JSFMockHelper.java
@@ -1,5 +1,6 @@
package org.springframework.faces.webflow;
+import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
@@ -19,8 +20,10 @@ import org.apache.myfaces.test.mock.MockHttpServletRequest;
import org.apache.myfaces.test.mock.MockHttpServletResponse;
import org.apache.myfaces.test.mock.MockHttpSession;
import org.apache.myfaces.test.mock.MockPartialViewContextFactory;
+import org.apache.myfaces.test.mock.MockPrintWriter;
import org.apache.myfaces.test.mock.MockRenderKit;
import org.apache.myfaces.test.mock.MockRenderKitFactory;
+import org.apache.myfaces.test.mock.MockResponseWriter;
import org.apache.myfaces.test.mock.MockServletConfig;
import org.apache.myfaces.test.mock.MockServletContext;
import org.apache.myfaces.test.mock.lifecycle.MockLifecycle;
@@ -45,6 +48,10 @@ public class JSFMockHelper {
return mock.config();
}
+ public String contentAsString() throws IOException {
+ return mock.contentAsString();
+ }
+
public MockExternalContext externalContext() {
return mock.externalContext();
}
@@ -132,6 +139,8 @@ public class JSFMockHelper {
facesContextFactory = (FacesContextFactory) FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
facesContext = facesContextFactory.getFacesContext(servletContext, request, response, lifecycle);
externalContext = (MockExternalContext) facesContext.getExternalContext();
+ facesContext.setResponseWriter(new MockResponseWriter(response.getWriter()));
+
UIViewRoot root = new UIViewRoot();
root.setViewId("/viewId");
root.setRenderKitId(RenderKitFactory.HTML_BASIC_RENDER_KIT);
@@ -174,6 +183,11 @@ public class JSFMockHelper {
return config;
}
+ public String contentAsString() throws IOException {
+ MockPrintWriter writer = (MockPrintWriter) response.getWriter();
+ return new String(writer.content());
+ }
+
public MockExternalContext externalContext() {
return externalContext;
}
diff --git a/spring-faces/src/test/java/org/springframework/faces/webflow/JsfAjaxHandlerTests.java b/spring-faces/src/test/java/org/springframework/faces/webflow/JsfAjaxHandlerTests.java
index 051a3378..544fb019 100644
--- a/spring-faces/src/test/java/org/springframework/faces/webflow/JsfAjaxHandlerTests.java
+++ b/spring-faces/src/test/java/org/springframework/faces/webflow/JsfAjaxHandlerTests.java
@@ -1,10 +1,7 @@
package org.springframework.faces.webflow;
-import java.io.IOException;
-
import junit.framework.TestCase;
-import org.apache.myfaces.test.mock.MockPrintWriter;
import org.springframework.web.context.support.StaticWebApplicationContext;
public class JsfAjaxHandlerTests extends TestCase {
@@ -27,13 +24,8 @@ public class JsfAjaxHandlerTests extends TestCase {
public void testSendAjaxRedirect() throws Exception {
ajaxHandler.sendAjaxRedirectInternal("/target", jsfMock.request(), jsfMock.response(), false);
assertEquals(
- "\n",
- extractResponseContent());
- }
-
- private String extractResponseContent() throws IOException {
- MockPrintWriter writer = (MockPrintWriter) jsfMock.response().getWriter();
- return new String(writer.content());
+ "\n",
+ jsfMock.contentAsString());
}
}
diff --git a/spring-faces/src/test/java/org/springframework/faces/webflow/JsfViewTests.java b/spring-faces/src/test/java/org/springframework/faces/webflow/JsfViewTests.java
index 1516b078..f4df7b0d 100644
--- a/spring-faces/src/test/java/org/springframework/faces/webflow/JsfViewTests.java
+++ b/spring-faces/src/test/java/org/springframework/faces/webflow/JsfViewTests.java
@@ -115,8 +115,6 @@ public class JsfViewTests extends TestCase {
EasyMock.replay(new Object[] { context, flowExecutionContext, flowMap, flashScope });
view.render();
-
- assertNull("The FacesContext was not released", FacesContext.getCurrentInstance());
}
public final void testRenderException() throws IOException {
@@ -131,7 +129,6 @@ public class JsfViewTests extends TestCase {
try {
view.render();
} catch (Exception ex) {
- assertNull("The FacesContext was not released", FacesContext.getCurrentInstance());
}
}
diff --git a/spring-faces/src/test/java/org/springframework/faces/webflow/MockBaseFacesContextFactory.java b/spring-faces/src/test/java/org/springframework/faces/webflow/MockBaseFacesContextFactory.java
index 888564c0..2da2e12c 100644
--- a/spring-faces/src/test/java/org/springframework/faces/webflow/MockBaseFacesContextFactory.java
+++ b/spring-faces/src/test/java/org/springframework/faces/webflow/MockBaseFacesContextFactory.java
@@ -10,6 +10,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.myfaces.test.mock.MockExternalContext20;
+import org.apache.myfaces.test.mock.MockHttpServletResponse;
public class MockBaseFacesContextFactory extends FacesContextFactory {
@@ -22,7 +23,25 @@ public class MockBaseFacesContextFactory extends FacesContextFactory {
} else {
ExternalContext ext = new MockExternalContext20((ServletContext) context, (HttpServletRequest) request,
- (HttpServletResponse) response);
+ (HttpServletResponse) response) {
+
+ public void setResponseBufferSize(int size) {
+ ((MockHttpServletResponse) getResponse()).setBufferSize(size);
+ }
+
+ public void setResponseContentLength(int length) {
+ ((MockHttpServletResponse) getResponse()).setContentLength(length);
+ }
+
+ public void setResponseContentType(String contentType) {
+ ((MockHttpServletResponse) getResponse()).setContentType(contentType);
+ }
+
+ public void setResponseStatus(int statusCode) {
+ ((MockHttpServletResponse) getResponse()).setStatus(statusCode);
+ }
+
+ };
return new MockBaseFacesContext(ext, lifecycle);
}
diff --git a/spring-webflow-samples/booking-faces/.classpath b/spring-webflow-samples/booking-faces/.classpath
index f85cdb95..c84dc702 100755
--- a/spring-webflow-samples/booking-faces/.classpath
+++ b/spring-webflow-samples/booking-faces/.classpath
@@ -8,6 +8,7 @@
+
diff --git a/spring-webflow-samples/booking-faces/ivy.xml b/spring-webflow-samples/booking-faces/ivy.xml
index b1d136bb..2dc658ee 100755
--- a/spring-webflow-samples/booking-faces/ivy.xml
+++ b/spring-webflow-samples/booking-faces/ivy.xml
@@ -21,7 +21,6 @@
-
@@ -49,21 +48,8 @@
-
-
-
-
-
+
diff --git a/spring-webflow-samples/booking-faces/pom.xml b/spring-webflow-samples/booking-faces/pom.xml
index 5d83895e..3abdb720 100644
--- a/spring-webflow-samples/booking-faces/pom.xml
+++ b/spring-webflow-samples/booking-faces/pom.xml
@@ -153,12 +153,6 @@
2.0.2
-
- javax.el
- com.springsource.javax.el
- 1.0.0
- provided
- javax.servletcom.springsource.javax.servlet
diff --git a/spring-webflow-samples/booking-faces/src/main/java/org/springframework/webflow/samples/booking/Booking.java b/spring-webflow-samples/booking-faces/src/main/java/org/springframework/webflow/samples/booking/Booking.java
index 98079fb3..8e7875c5 100755
--- a/spring-webflow-samples/booking-faces/src/main/java/org/springframework/webflow/samples/booking/Booking.java
+++ b/spring-webflow-samples/booking-faces/src/main/java/org/springframework/webflow/samples/booking/Booking.java
@@ -15,9 +15,6 @@ import javax.persistence.ManyToOne;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
-import javax.validation.constraints.NotNull;
-import javax.validation.constraints.Pattern;
-import javax.validation.constraints.Size;
import org.springframework.binding.message.MessageBuilder;
import org.springframework.binding.message.MessageContext;
@@ -37,17 +34,12 @@ public class Booking implements Serializable {
private Hotel hotel;
- @NotNull
private Date checkinDate;
- @NotNull
private Date checkoutDate;
- @Pattern(regexp = "[0-9]{16}", message = "Credit card number must be 16 digits.")
private String creditCard;
- @NotNull
- @Size(min = 3, message = "A valid credit card name is required.")
private String creditCardName;
private int creditCardExpiryMonth;
diff --git a/spring-webflow-samples/booking-faces/src/main/webapp/WEB-INF/config/webflow-config.xml b/spring-webflow-samples/booking-faces/src/main/webapp/WEB-INF/config/webflow-config.xml
index 6addb4ff..876d4388 100644
--- a/spring-webflow-samples/booking-faces/src/main/webapp/WEB-INF/config/webflow-config.xml
+++ b/spring-webflow-samples/booking-faces/src/main/webapp/WEB-INF/config/webflow-config.xml
@@ -13,7 +13,8 @@
-
+
+
@@ -26,7 +27,10 @@
-
+
+
+
+
@@ -35,5 +39,5 @@
-
+
\ No newline at end of file
diff --git a/spring-webflow-samples/booking-faces/src/main/webapp/WEB-INF/faces-config-12.xml b/spring-webflow-samples/booking-faces/src/main/webapp/WEB-INF/faces-config-12.xml
deleted file mode 100644
index a1d74854..00000000
--- a/spring-webflow-samples/booking-faces/src/main/webapp/WEB-INF/faces-config-12.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
-
- com.sun.facelets.FaceletViewHandler
-
-
\ No newline at end of file
diff --git a/spring-webflow-samples/booking-faces/src/main/webapp/WEB-INF/layouts/standard.xhtml b/spring-webflow-samples/booking-faces/src/main/webapp/WEB-INF/layouts/standard.xhtml
index 4464eec0..86a65b61 100644
--- a/spring-webflow-samples/booking-faces/src/main/webapp/WEB-INF/layouts/standard.xhtml
+++ b/spring-webflow-samples/booking-faces/src/main/webapp/WEB-INF/layouts/standard.xhtml
@@ -4,13 +4,15 @@
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:c="http://java.sun.com/jsp/jstl/core"
- xmlns:sf="http://www.springframework.org/tags/faces"
contentType="text/html" encoding="UTF-8">
Spring Faces: Hotel Booking Sample Application
-
+
-
- javax.faces.PARTIAL_STATE_SAVING
- false
-
-
charEncodingFilter
@@ -56,11 +50,11 @@
-
+ springSecurityFilterChainorg.springframework.web.filter.DelegatingFilterProxy
-
+
springSecurityFilterChain/*
@@ -71,19 +65,6 @@
org.springframework.web.context.ContextLoaderListener
-
-
- Resources Servlet
- org.springframework.js.resource.ResourceServlet
- 0
-
-
-
-
- Resources Servlet
- /resources/*
-
-
Spring MVC Dispatcher Servlet
diff --git a/spring-webflow-samples/booking-portlet-faces/src/main/webapp/WEB-INF/config/hotelbooking-portlet-config.xml b/spring-webflow-samples/booking-portlet-faces/src/main/webapp/WEB-INF/config/hotelbooking-portlet-config.xml
index 7b13834e..ba4a43d6 100644
--- a/spring-webflow-samples/booking-portlet-faces/src/main/webapp/WEB-INF/config/hotelbooking-portlet-config.xml
+++ b/spring-webflow-samples/booking-portlet-faces/src/main/webapp/WEB-INF/config/hotelbooking-portlet-config.xml
@@ -36,6 +36,7 @@
+
@@ -49,6 +50,9 @@
+
+
+
diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/ViewState.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/ViewState.java
index c7188d5d..598640ab 100644
--- a/spring-webflow/src/main/java/org/springframework/webflow/engine/ViewState.java
+++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/ViewState.java
@@ -61,6 +61,12 @@ public class ViewState extends TransitionableState {
*/
private Boolean redirect;
+ /**
+ * Whether or not a redirect should occur when the state is not exited (e.g. invalid form submission, a transition
+ * without a "to" attribute).
+ */
+ private Boolean redirectInSameState = Boolean.FALSE;
+
/**
* Whether or not the view should render as a popup.
*/
@@ -122,7 +128,7 @@ public class ViewState extends TransitionableState {
* Returns whether this view state should request a flow execution redirect when entered.
*/
public boolean getRedirect() {
- return redirect.booleanValue();
+ return (redirect != null) ? redirect.booleanValue() : false;
}
/**
@@ -133,6 +139,22 @@ public class ViewState extends TransitionableState {
this.redirect = redirect;
}
+ /**
+ * Returns whether this view state should request a flow execution redirect when the state hasn't been exited.
+ */
+ public boolean getRedirectInSameState() {
+ return (redirectInSameState != null) ? redirectInSameState.booleanValue() : false;
+ }
+
+ /**
+ * Sets whether this view state should requests a flow execution redirect when entered when processing is done but
+ * the state hasn't been exited (e.g. invalid form submissions).
+ * @param redirectInSameState the redirect flag
+ */
+ public void setRedirectInSameState(Boolean redirectInSameState) {
+ this.redirectInSameState = redirectInSameState;
+ }
+
/**
* Returns whether this view state should render as a popup.
*/
@@ -206,7 +228,7 @@ public class ViewState extends TransitionableState {
if (externalContext.isAjaxRequest()) {
render(context, view);
} else {
- if (shouldRedirect(context)) {
+ if (shouldRedirectInSameState(context)) {
context.getFlashScope().put(View.USER_EVENT_STATE_ATTRIBUTE, view.getUserEventState());
externalContext.requestFlowExecutionRedirect();
} else {
@@ -270,6 +292,14 @@ public class ViewState extends TransitionableState {
}
}
+ private boolean shouldRedirectInSameState(RequestControlContext context) {
+ if (redirectInSameState != null) {
+ return redirectInSameState.booleanValue();
+ } else {
+ return shouldRedirect(context);
+ }
+ }
+
private void render(RequestControlContext context, View view) throws ViewRenderingException {
if (logger.isDebugEnabled()) {
logger.debug("Rendering + " + view);
diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/FlowArtifactFactory.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/FlowArtifactFactory.java
index 5b28218e..06e5fa56 100644
--- a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/FlowArtifactFactory.java
+++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/FlowArtifactFactory.java
@@ -36,8 +36,8 @@ import org.springframework.webflow.execution.Action;
import org.springframework.webflow.execution.ViewFactory;
/**
- * A factory for core web flow elements such as {@link Flow flows}, {@link State states}, and
- * {@link Transition transitions}.
+ * A factory for core web flow elements such as {@link Flow flows}, {@link State states}, and {@link Transition
+ * transitions}.
*
* This factory encapsulates the construction of each Flow implementation as well as each core artifact type. Subclasses
* may customize how the core elements are created.
@@ -86,6 +86,7 @@ public class FlowArtifactFactory {
ViewState viewState = new ViewState(flow, id, viewFactory);
viewState.addVariables(variables);
viewState.setRedirect(redirect);
+ viewState.setRedirectInSameState(Boolean.FALSE);
viewState.setPopup(popup);
viewState.getRenderActionList().addAll(renderActions);
configureCommonProperties(viewState, entryActions, transitions, exceptionHandlers, exitActions, attributes);