diff --git a/spring-faces/.classpath b/spring-faces/.classpath index 2c313ea9..66cf4fe3 100644 --- a/spring-faces/.classpath +++ b/spring-faces/.classpath @@ -10,16 +10,12 @@ - - - - diff --git a/spring-faces/src/main/java/META-INF/faces-config.xml b/spring-faces/src/main/java/META-INF/faces-config.xml index b607d502..01e750a7 100644 --- a/spring-faces/src/main/java/META-INF/faces-config.xml +++ b/spring-faces/src/main/java/META-INF/faces-config.xml @@ -4,23 +4,14 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"> - - org.springframework.faces.webflow.FlowLifecycleFactory - org.springframework.faces.webflow.FlowFacesContextFactory - org.springframework.faces.webflow.FlowRenderKitFactory - - org.springframework.faces.webflow.FlowActionListener org.springframework.webflow.core.expression.el.RequestContextELResolver org.springframework.webflow.core.expression.el.ScopeSearchingELResolver - org.springframework.faces.webflow.FlowExecutionViewHandler + org.springframework.faces.webflow.FlowViewStateManager + org.springframework.faces.webflow.FlowViewHandler - - org.springframework.faces.support.RequestLoggingPhaseListener - - spring.faces.DojoClientTextValidator org.springframework.faces.ui.DojoClientTextValidator diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowActionListener.java b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowActionListener.java index a8fec695..16bfa09c 100644 --- a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowActionListener.java +++ b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowActionListener.java @@ -16,12 +16,14 @@ package org.springframework.faces.webflow; import javax.faces.application.NavigationHandler; -import javax.faces.component.ActionSource; +import javax.faces.component.ActionSource2; import javax.faces.context.FacesContext; import javax.faces.event.AbortProcessingException; import javax.faces.event.ActionEvent; import javax.faces.event.ActionListener; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.util.StringUtils; /** @@ -34,32 +36,29 @@ import org.springframework.util.StringUtils; */ public class FlowActionListener implements ActionListener { - private ActionListener delegate; + private static final Log logger = LogFactory.getLog(FlowActionListener.class); public FlowActionListener(ActionListener delegate) { - this.delegate = delegate; } public void processAction(ActionEvent actionEvent) throws AbortProcessingException { - - if (!JsfFlowUtils.isFlowRequest()) { - delegate.processAction(actionEvent); - } - FacesContext context = FacesContext.getCurrentInstance(); - ActionSource source = (ActionSource) actionEvent.getSource(); + ActionSource2 source = (ActionSource2) actionEvent.getSource(); String result = null; - - if (source.getAction() != null) { - result = (String) source.getAction().invoke(context, null); + if (source.getActionExpression() != null) { + if (logger.isDebugEnabled()) { + logger.debug("Invoking action expression " + source.getActionExpression()); + } + result = (String) source.getActionExpression().invoke(context.getELContext(), null); } - if (StringUtils.hasText(result)) { + if (logger.isDebugEnabled()) { + logger.debug("Event '" + result + "' detected"); + } context.getExternalContext().getRequestMap().put(JsfView.EVENT_KEY, result); } else { + logger.debug("No action event detected"); context.getExternalContext().getRequestMap().remove(JsfView.EVENT_KEY); } - context.renderResponse(); } - } 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 0bcfd5c5..3441e993 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 @@ -33,6 +33,7 @@ import org.springframework.binding.message.Messages; import org.springframework.binding.message.Severity; import org.springframework.context.MessageSource; import org.springframework.util.StringUtils; +import org.springframework.webflow.execution.RequestContext; import org.springframework.webflow.execution.RequestContextHolder; /** @@ -44,42 +45,30 @@ import org.springframework.webflow.execution.RequestContextHolder; public class FlowFacesContext extends FacesContext { /** - * The key for storing the responseComplete flag + * The Web Flow request context. */ - static final String RESPONSE_COMPLETE_KEY = "responseComplete"; - - /** - * The key for storing the renderResponse flag - */ - static final String RENDER_RESPONSE_KEY = "renderResponse"; + private RequestContext context; /** * The base FacesContext delegate */ private FacesContext delegate; - public FlowFacesContext(FacesContext delegate) { + public FlowFacesContext(RequestContext context, FacesContext delegate) { + this.context = context; this.delegate = delegate; - FacesContext.setCurrentInstance(this); + setCurrentInstance(this); } /** * Translates a FacesMessage to an SWF Message and adds it to the current MessageContext */ public void addMessage(String clientId, FacesMessage message) { - if (!JsfFlowUtils.isFlowRequest()) { - delegate.addMessage(clientId, message); - return; - } - MessageResolver messageResolver; - StringBuffer msgText = new StringBuffer(); - if (StringUtils.hasText(message.getSummary())) { msgText.append(message.getSummary()); } - if (message.getSeverity() == FacesMessage.SEVERITY_INFO) { messageResolver = Messages.text(msgText.toString(), Severity.INFO); } else if (message.getSeverity() == FacesMessage.SEVERITY_WARN) { @@ -87,18 +76,13 @@ public class FlowFacesContext extends FacesContext { } else { messageResolver = Messages.text(msgText.toString(), Severity.ERROR); } - - RequestContextHolder.getRequestContext().getMessageContext().addMessage(messageResolver); + context.getMessageContext().addMessage(messageResolver); } /** * Returns an Iterator for all component clientId's for which messages have been added. */ - @SuppressWarnings("unchecked") public Iterator getClientIdsWithMessages() { - if (!JsfFlowUtils.isFlowRequest()) { - return delegate.getClientIdsWithMessages(); - } return new ClientIdIterator(); } @@ -107,15 +91,9 @@ public class FlowFacesContext extends FacesContext { * associated with any specific UIComponent. If no such messages have been queued, return null. */ public FacesMessage.Severity getMaximumSeverity() { - - if (!JsfFlowUtils.isFlowRequest()) { - return delegate.getMaximumSeverity(); - } - - if (RequestContextHolder.getRequestContext().getMessageContext().getMessages() == null - || RequestContextHolder.getRequestContext().getMessageContext().getMessages().length == 0) + if (context.getMessageContext().getMessages().length == 0) { return null; - + } FacesMessage.Severity max = FacesMessage.SEVERITY_INFO; Iterator i = getMessages(); while (i.hasNext()) { @@ -132,11 +110,7 @@ public class FlowFacesContext extends FacesContext { /** * Returns an Iterator for all Messages in the current MessageContext that does translation to FacesMessages. */ - @SuppressWarnings("unchecked") public Iterator getMessages() { - if (!JsfFlowUtils.isFlowRequest()) { - return delegate.getMessages(); - } return new FacesMessageIterator(); } @@ -144,55 +118,24 @@ public class FlowFacesContext extends FacesContext { * Returns an Iterator for all Messages with the given clientId in the current MessageContext that does translation * to FacesMessages. */ - @SuppressWarnings("unchecked") public Iterator getMessages(String clientId) { - if (!JsfFlowUtils.isFlowRequest()) { - return delegate.getMessages(clientId); - } return new FacesMessageIterator(clientId); } public boolean getRenderResponse() { - if (!JsfFlowUtils.isFlowRequest()) { - return delegate.getRenderResponse(); - } - - Boolean renderResponse = RequestContextHolder.getRequestContext().getFlashScope().getBoolean( - RENDER_RESPONSE_KEY); - if (renderResponse == null) { - return false; - } - return renderResponse; + return delegate.getRenderResponse(); } public boolean getResponseComplete() { - - if (!JsfFlowUtils.isFlowRequest()) { - return delegate.getResponseComplete(); - } - - Boolean responseComplete = RequestContextHolder.getRequestContext().getFlashScope().getBoolean( - RESPONSE_COMPLETE_KEY); - if (responseComplete == null) { - return false; - } - return responseComplete; + return delegate.getResponseComplete(); } public void renderResponse() { - if (!JsfFlowUtils.isFlowRequest()) { - delegate.renderResponse(); - return; - } - RequestContextHolder.getRequestContext().getFlashScope().put(RENDER_RESPONSE_KEY, Boolean.TRUE); + delegate.renderResponse(); } public void responseComplete() { - if (!JsfFlowUtils.isFlowRequest()) { - delegate.responseComplete(); - return; - } - RequestContextHolder.getRequestContext().getFlashScope().put(RESPONSE_COMPLETE_KEY, Boolean.TRUE); + delegate.responseComplete(); } // ------------------ Pass-through delegate methods ----------------------// @@ -227,6 +170,7 @@ public class FlowFacesContext extends FacesContext { public void release() { delegate.release(); + setCurrentInstance(null); } public void setResponseStream(ResponseStream responseStream) { @@ -245,7 +189,7 @@ public class FlowFacesContext extends FacesContext { return delegate; } - private class FacesMessageIterator implements Iterator { + private class FacesMessageIterator implements Iterator { private Message[] messages; @@ -263,10 +207,9 @@ public class FlowFacesContext extends FacesContext { return messages.length > currentIndex + 1; } - public Object next() { + public FacesMessage next() { currentIndex++; Message nextMessage = messages[currentIndex]; - FacesMessage facesMessage; if (nextMessage.getSeverity() == Severity.INFO) { facesMessage = new FacesMessage(FacesMessage.SEVERITY_INFO, nextMessage.getText(), nextMessage @@ -287,13 +230,12 @@ public class FlowFacesContext extends FacesContext { } - private class ClientIdIterator implements Iterator { + private class ClientIdIterator implements Iterator { private Message[] messages; int currentIndex = -1; - @SuppressWarnings("unchecked") protected ClientIdIterator() { this.messages = RequestContextHolder.getRequestContext().getMessageContext().getMessages(); } @@ -309,7 +251,7 @@ public class FlowFacesContext extends FacesContext { return false; } - public Object next() { + public String next() { Message next = messages[++currentIndex]; while (next.getSource() == null || "".equals(next.getSource())) { next = messages[++currentIndex]; diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowFacesContextFactory.java b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowFacesContextFactory.java deleted file mode 100644 index 29e3ed78..00000000 --- a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowFacesContextFactory.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2004-2007 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.FacesException; -import javax.faces.context.FacesContext; -import javax.faces.context.FacesContextFactory; -import javax.faces.lifecycle.Lifecycle; - -import org.springframework.context.MessageSource; - -/** - * {@link FacesContextFactory} implementation that installs the {@link FlowFacesContext}, allowing for integration with - * a Spring {@link MessageSource}. - * - * @author Jeremy Grelle - */ -public class FlowFacesContextFactory extends FacesContextFactory { - - FacesContextFactory delegate; - - public FlowFacesContextFactory(FacesContextFactory delegate) { - this.delegate = delegate; - } - - public FacesContext getFacesContext(Object context, Object request, Object response, Lifecycle lifecycle) - throws FacesException { - return new FlowFacesContext(delegate.getFacesContext(context, request, response, lifecycle)); - } - -} diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowLifecycle.java b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowLifecycle.java index 0f7c7a43..f34e2689 100644 --- a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowLifecycle.java +++ b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowLifecycle.java @@ -21,6 +21,9 @@ import javax.faces.event.PhaseId; import javax.faces.event.PhaseListener; import javax.faces.lifecycle.Lifecycle; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + /** * Custom {@link Lifecycle} for Spring Web Flow that only executes the APPLY_REQUEST_VALUES through INVOKE_APPLICATION * phases. @@ -30,7 +33,9 @@ import javax.faces.lifecycle.Lifecycle; * * @author Jeremy Grelle */ -public class FlowLifecycle extends Lifecycle { +class FlowLifecycle extends Lifecycle { + + private static final Log logger = LogFactory.getLog(FlowLifecycle.class); private final Lifecycle delegate; @@ -42,7 +47,7 @@ public class FlowLifecycle extends Lifecycle { * Executes APPLY_REQUEST_VALUES through INVOKE_APPLICATION. */ public void execute(FacesContext context) throws FacesException { - + logger.debug("Executing view post back lifecycle"); for (int p = PhaseId.APPLY_REQUEST_VALUES.getOrdinal(); p <= PhaseId.INVOKE_APPLICATION.getOrdinal(); p++) { PhaseId phaseId = (PhaseId) PhaseId.VALUES.get(p); if (!skipPhase(context, phaseId)) { @@ -90,16 +95,20 @@ public class FlowLifecycle extends Lifecycle { } private void invokePhase(FacesContext context, PhaseId phaseId) { - JsfFlowUtils.notifyBeforeListeners(phaseId, this); + JsfUtils.notifyBeforeListeners(phaseId, this, context); if (phaseId == PhaseId.APPLY_REQUEST_VALUES) { + logger.debug("Processing decodes"); context.getViewRoot().processDecodes(context); } else if (phaseId == PhaseId.PROCESS_VALIDATIONS) { + logger.debug("Processing validators"); context.getViewRoot().processValidators(context); } else if (phaseId == PhaseId.UPDATE_MODEL_VALUES) { + logger.debug("Processing model updates"); context.getViewRoot().processUpdates(context); } else { + logger.debug("Processing application"); context.getViewRoot().processApplication(context); } - JsfFlowUtils.notifyAfterListeners(phaseId, this); + JsfUtils.notifyAfterListeners(phaseId, this, context); } } diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowLifecycleFactory.java b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowLifecycleFactory.java deleted file mode 100644 index 14a5b1bf..00000000 --- a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowLifecycleFactory.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2004-2007 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.util.Iterator; - -import javax.faces.lifecycle.Lifecycle; -import javax.faces.lifecycle.LifecycleFactory; - -/** - * This {@link LifecycleFactory} implementation is responsible for installing a custom JSF Lifecycle the executes within - * the context of Spring Web Flow. - *

- * The {@link FlowLifecycle} will be configured to delegate to the default {@link Lifecycle} where custom behavior is - * not needed. - * - * @author Jeremy Grelle - */ -public class FlowLifecycleFactory extends LifecycleFactory { - - public static final String FLOW_LIFECYCLE_ID = "org.springframework.FlowLifecycle"; - - private final LifecycleFactory delegate; - - public FlowLifecycleFactory(LifecycleFactory delegate) { - this.delegate = delegate; - addLifecycle(FLOW_LIFECYCLE_ID, new FlowLifecycle(delegate.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE))); - } - - public void addLifecycle(String lifecycleId, Lifecycle lifecycle) { - delegate.addLifecycle(lifecycleId, lifecycle); - } - - public Lifecycle getLifecycle(String lifecycleId) { - return delegate.getLifecycle(lifecycleId); - } - - public Iterator getLifecycleIds() { - return delegate.getLifecycleIds(); - } - -} diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowRenderKitFactory.java b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowRenderKitFactory.java deleted file mode 100644 index 9ea9f587..00000000 --- a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowRenderKitFactory.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2004-2007 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.util.Iterator; - -import javax.faces.context.FacesContext; -import javax.faces.render.RenderKit; -import javax.faces.render.RenderKitFactory; - -/** - * {@link RenderKitFactory} implementation that wraps the current {@link RenderKit} implementation inside the - * {@link FlowRenderKitWrapper}. - * - * @author Jeremy Grelle - */ -public class FlowRenderKitFactory extends RenderKitFactory { - - private RenderKitFactory delegate; - - public FlowRenderKitFactory(RenderKitFactory renderKitFactory) { - this.delegate = renderKitFactory; - } - - public void addRenderKit(String renderKitId, RenderKit renderKit) { - FlowRenderKitWrapper wrapper = new FlowRenderKitWrapper(renderKit); - delegate.addRenderKit(renderKitId, wrapper); - } - - public RenderKit getRenderKit(FacesContext context, String renderKitId) { - RenderKit renderKit = delegate.getRenderKit(context, renderKitId); - if (!(renderKit instanceof FlowRenderKitWrapper)) { - return new FlowRenderKitWrapper(renderKit); - } - return renderKit; - } - - public Iterator getRenderKitIds() { - return delegate.getRenderKitIds(); - } - -} diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowRenderKitWrapper.java b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowRenderKitWrapper.java deleted file mode 100644 index 9728d475..00000000 --- a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowRenderKitWrapper.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2004-2007 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.OutputStream; -import java.io.Writer; - -import javax.faces.context.ResponseStream; -import javax.faces.context.ResponseWriter; -import javax.faces.render.RenderKit; -import javax.faces.render.Renderer; -import javax.faces.render.ResponseStateManager; - -/** - * Delegating {@link RenderKit} implementation that provides a custom {@link ResponseStateManager} for storing JSF view - * state as part of the current FlowExecution. - * - * @author Jeremy Grelle - */ -public class FlowRenderKitWrapper extends RenderKit { - - RenderKit delegate; - - ResponseStateManager manager = new FlowResponseStateManager(); - - public FlowRenderKitWrapper(RenderKit renderKit) { - this.delegate = renderKit; - } - - public void addRenderer(String family, String rendererType, Renderer renderer) { - delegate.addRenderer(family, rendererType, renderer); - } - - public ResponseStream createResponseStream(OutputStream out) { - return delegate.createResponseStream(out); - } - - public ResponseWriter createResponseWriter(Writer writer, String contentTypeList, String characterEncoding) { - return delegate.createResponseWriter(writer, contentTypeList, characterEncoding); - } - - public Renderer getRenderer(String family, String rendererType) { - return delegate.getRenderer(family, rendererType); - } - - public ResponseStateManager getResponseStateManager() { - if (!JsfFlowUtils.isFlowRequest()) { - return delegate.getResponseStateManager(); - } - return manager; - } - -} diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowResponseStateManager.java b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowResponseStateManager.java deleted file mode 100644 index 45e9e1e1..00000000 --- a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowResponseStateManager.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2004-2007 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.el.ValueExpression; -import javax.faces.application.StateManager.SerializedView; -import javax.faces.context.FacesContext; -import javax.faces.render.ResponseStateManager; - -import org.springframework.webflow.execution.FlowExecution; -import org.springframework.webflow.execution.FlowExecutionKey; -import org.springframework.webflow.execution.RequestContextHolder; - -/** - * {@link ResponseStateManager} implementation that writes out the current {@link FlowExecutionKey} in place of the JSF - * view state, and manages the JSF view state as part of the FlowExecution instance state. - * - * @author Jeremy Grelle - */ -public class FlowResponseStateManager extends ResponseStateManager { - - private static final int VIEW_ID_INDEX = 0; - - private static final int TREE_STATE_INDEX = 1; - - private static final int COMPONENT_STATE_INDEX = 2; - - // TODO - This needs to be replaced with a common static, probably from FlowExecutorArgumentExtractor - private static final String VIEW_STATE_PARAM = "org.springframework.webflow.FlowExecutionKey"; - - private static final char[] STATE_FIELD_START = ("".toCharArray(); - - public Object getState(FacesContext context, String viewId) { - Object[] structureAndState = new Object[2]; - structureAndState[0] = getTreeStructureToRestore(context, viewId); - if (structureAndState[0] == null) { - return null; - } - structureAndState[1] = getComponentStateToRestore(context); - return structureAndState; - } - - public Object getComponentStateToRestore(FacesContext context) { - Object[] state = (Object[]) RequestContextHolder.getRequestContext().getFlowScope().get(JsfView.STATE_KEY); - if (state == null) { - return null; - } else { - return state[COMPONENT_STATE_INDEX]; - } - } - - public Object getTreeStructureToRestore(FacesContext context, String viewId) { - Object[] state = (Object[]) RequestContextHolder.getRequestContext().getFlowScope().get(JsfView.STATE_KEY); - if (state == null || !state[VIEW_ID_INDEX].equals(viewId)) { - return null; - } else { - return state[TREE_STATE_INDEX]; - } - } - - private FlowExecution getFlowExecution() { - FacesContext ctx = FacesContext.getCurrentInstance(); - ValueExpression expr = ctx.getApplication().getExpressionFactory().createValueExpression(ctx.getELContext(), - "#{flowExecution}", FlowExecution.class); - return (FlowExecution) expr.getValue(ctx.getELContext()); - } - - /** - * Stores the serializable component state in Flash scope and writes out the FlowExecutionKey - */ - public void writeState(FacesContext context, SerializedView state) throws IOException { - - Object[] serializableState = new Object[] { context.getViewRoot().getViewId(), state.getStructure(), - state.getState() }; - - RequestContextHolder.getRequestContext().getFlowScope().put(JsfView.STATE_KEY, serializableState); - - Writer writer = context.getResponseWriter(); - writer.write(STATE_FIELD_START); - writer.write(RequestContextHolder.getRequestContext().getFlowExecutionContext().getKey().toString()); - writer.write(STATE_FIELD_END); - } - -} diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowExecutionViewHandler.java b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowViewHandler.java similarity index 91% rename from spring-faces/src/main/java/org/springframework/faces/webflow/FlowExecutionViewHandler.java rename to spring-faces/src/main/java/org/springframework/faces/webflow/FlowViewHandler.java index 8042b32b..53f4833f 100644 --- a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowExecutionViewHandler.java +++ b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowViewHandler.java @@ -31,18 +31,15 @@ import org.springframework.webflow.execution.RequestContextHolder; * * @author Jeremy Grelle */ -public class FlowExecutionViewHandler extends ViewHandler { +public class FlowViewHandler extends ViewHandler { - ViewHandler delegate; + private ViewHandler delegate; - public FlowExecutionViewHandler(ViewHandler delegate) { + public FlowViewHandler(ViewHandler delegate) { this.delegate = delegate; } public String getActionURL(FacesContext context, String viewId) { - if (!JsfFlowUtils.isFlowRequest()) { - return delegate.getActionURL(context, viewId); - } return RequestContextHolder.getRequestContext().getFlowExecutionUrl(); } 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 new file mode 100644 index 00000000..58cb93bc --- /dev/null +++ b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowViewStateManager.java @@ -0,0 +1,145 @@ +package org.springframework.faces.webflow; + +import java.io.IOException; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +import javax.faces.application.StateManager; +import javax.faces.component.UIViewRoot; +import javax.faces.context.FacesContext; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.webflow.execution.RequestContext; +import org.springframework.webflow.execution.RequestContextHolder; + +public class FlowViewStateManager extends StateManager { + + private static final Log logger = LogFactory.getLog(FlowViewStateManager.class); + + private static final String VIEW_MAP = "org.springframework.webflow.viewMap"; + + public boolean isSavingStateInClient(FacesContext context) { + return false; + } + + // required to implement for 1.1 view handlers - unfortunately, facelets is one of these... + public javax.faces.application.StateManager.SerializedView saveSerializedView(FacesContext context) { + SerializedView view = (SerializedView) saveView(context); + return new javax.faces.application.StateManager.SerializedView(view.treeStructure, view.componentState); + } + + public Object saveView(FacesContext context) { + RequestContext requestContext = RequestContextHolder.getRequestContext(); + SerializedViewMap viewMap = (SerializedViewMap) requestContext.getFlowScope().get(VIEW_MAP); + if (viewMap == null) { + viewMap = new SerializedViewMap(); + requestContext.getFlowScope().put(VIEW_MAP, viewMap); + } + logger.debug("Saving view root in flow scope"); + return viewMap.putSerializedView(context); + } + + public UIViewRoot restoreView(FacesContext context, String viewId, String renderKitId) { + RequestContext requestContext = RequestContextHolder.getRequestContext(); + SerializedViewMap viewMap = (SerializedViewMap) requestContext.getFlowScope().get(VIEW_MAP); + if (viewMap == null) { + logger.debug("No view map in flow scope; no views have been saved yet..."); + return null; + } + logger.debug("Restoring view root from flow scope"); + return viewMap.getDeserializedView(viewId, context); + } + + public void writeState(FacesContext context, Object state) throws IOException { + // nothing to do, as saving state to client always returns false + } + + private static class SerializedViewMap implements Serializable { + private static final Log logger = LogFactory.getLog(SerializedViewMap.class); + + private Map views; + + public SerializedViewMap() { + views = new HashMap(); + } + + public void put(String viewId, SerializedView view) { + views.put(viewId, view); + } + + public SerializedView get(String viewId) { + return views.get(viewId); + } + + public Object putSerializedView(FacesContext context) { + SerializedView view = SerializedView.create(context); + if (logger.isDebugEnabled()) { + logger.debug("Indexing serialized view under key '" + context.getViewRoot().getViewId() + "'"); + } + put(context.getViewRoot().getViewId(), view); + return view; + } + + public UIViewRoot getDeserializedView(String viewId, FacesContext context) { + SerializedView view = get(viewId); + if (view == null) { + if (logger.isDebugEnabled()) { + logger.debug("No serialized view found under key '" + viewId + "; returning null"); + } + return null; + } + return view.deserialize(context); + } + } + + private static class SerializedView implements Serializable { + private static final Log logger = LogFactory.getLog(SerializedView.class); + + private Serializable treeStructure; + + private Object componentState; + + private SerializedView(Serializable treeStructure, Object componentState) { + this.treeStructure = treeStructure; + this.componentState = componentState; + } + + public UIViewRoot deserialize(FacesContext context) { + if (treeStructure == null) { + logger.debug("Tree structure is null indicating transient UIViewRoot; returning null"); + return null; + } + UIViewRoot viewRoot = new TreeStructureManager().restoreTreeStructure(treeStructure); + logger.debug("UIViewRoot structure restored"); + viewRoot.processRestoreState(context, componentState); + logger.debug("UIViewRoot component state restored"); + logger.debug("Returning restored UIViewRoot"); + return viewRoot; + } + + public static SerializedView create(FacesContext context) { + return new SerializedView(getTreeStructure(context), getComponentState(context)); + } + + private static Serializable getTreeStructure(FacesContext context) { + UIViewRoot viewRoot = context.getViewRoot(); + if (viewRoot.isTransient()) { + return null; + } else { + return new TreeStructureManager().buildTreeStructureToSave(viewRoot); + } + } + + private static Object getComponentState(FacesContext context) { + UIViewRoot viewRoot = context.getViewRoot(); + if (viewRoot.isTransient()) { + return null; + } else { + return viewRoot.processSaveState(context); + } + } + } + +} diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/JsfRenderFinalResponseAction.java b/spring-faces/src/main/java/org/springframework/faces/webflow/JsfFinalResponseAction.java similarity index 82% rename from spring-faces/src/main/java/org/springframework/faces/webflow/JsfRenderFinalResponseAction.java rename to spring-faces/src/main/java/org/springframework/faces/webflow/JsfFinalResponseAction.java index 0ac786cd..724a43f7 100644 --- a/spring-faces/src/main/java/org/springframework/faces/webflow/JsfRenderFinalResponseAction.java +++ b/spring-faces/src/main/java/org/springframework/faces/webflow/JsfFinalResponseAction.java @@ -17,13 +17,11 @@ package org.springframework.faces.webflow; import javax.faces.component.UIViewRoot; -import org.springframework.util.Assert; import org.springframework.webflow.engine.EndState; import org.springframework.webflow.execution.Action; import org.springframework.webflow.execution.Event; import org.springframework.webflow.execution.RequestContext; import org.springframework.webflow.execution.View; -import org.springframework.webflow.execution.ViewFactory; /** * Specialized {@link Action} implementation for rendering the JSF view in an {@link EndState}. @@ -33,26 +31,19 @@ import org.springframework.webflow.execution.ViewFactory; * * @author Jeremy Grelle */ -public class JsfRenderFinalResponseAction implements Action { +public class JsfFinalResponseAction implements Action { - ViewFactory viewFactory; + private JsfViewFactory viewFactory; - public JsfRenderFinalResponseAction(ViewFactory viewFactory) { - Assert.notNull(viewFactory); + public JsfFinalResponseAction(JsfViewFactory viewFactory) { this.viewFactory = viewFactory; } public Event execute(RequestContext context) throws Exception { - View view = viewFactory.getView(context); - Assert.isInstanceOf(JsfView.class, view); - ((JsfView) view).getViewRoot().setTransient(true); - view.render(); - return new Event(this, "success"); - } } diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/JsfFlowConfigurationException.java b/spring-faces/src/main/java/org/springframework/faces/webflow/JsfFlowConfigurationException.java deleted file mode 100644 index c54935fe..00000000 --- a/spring-faces/src/main/java/org/springframework/faces/webflow/JsfFlowConfigurationException.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2004-2007 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 org.springframework.webflow.core.FlowException; - -/** - * Thrown when there is a configuration error with SWF within a JSF environment. - * - * @author Keith Donald - */ -public class JsfFlowConfigurationException extends FlowException { - - public JsfFlowConfigurationException(String msg) { - super(msg); - } - - public JsfFlowConfigurationException(String msg, Throwable cause) { - super(msg, cause); - } -} diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/JsfFlowUtils.java b/spring-faces/src/main/java/org/springframework/faces/webflow/JsfUtils.java similarity index 57% rename from spring-faces/src/main/java/org/springframework/faces/webflow/JsfFlowUtils.java rename to spring-faces/src/main/java/org/springframework/faces/webflow/JsfUtils.java index d20fde94..aa511d62 100644 --- a/spring-faces/src/main/java/org/springframework/faces/webflow/JsfFlowUtils.java +++ b/spring-faces/src/main/java/org/springframework/faces/webflow/JsfUtils.java @@ -15,39 +15,21 @@ */ package org.springframework.faces.webflow; -import javax.faces.FactoryFinder; import javax.faces.context.FacesContext; -import javax.faces.context.FacesContextFactory; import javax.faces.event.PhaseEvent; import javax.faces.event.PhaseId; import javax.faces.event.PhaseListener; import javax.faces.lifecycle.Lifecycle; -import org.springframework.webflow.execution.RequestContext; -import org.springframework.webflow.execution.RequestContextHolder; - /** * Common support for the JSF integration with Spring Web Flow. * * @author Jeremy Grelle */ -class JsfFlowUtils { +class JsfUtils { - public static FacesContext getFacesContext(Lifecycle lifecycle) { - FacesContext facesContext = FacesContext.getCurrentInstance(); - if (facesContext == null) { - RequestContext requestContext = RequestContextHolder.getRequestContext(); - FacesContextFactory facesContextFactory = (FacesContextFactory) FactoryFinder - .getFactory(FactoryFinder.FACES_CONTEXT_FACTORY); - facesContext = facesContextFactory.getFacesContext(requestContext.getExternalContext().getContext(), - requestContext.getExternalContext().getRequest(), - requestContext.getExternalContext().getResponse(), lifecycle); - } - return facesContext; - } - - public static void notifyAfterListeners(PhaseId phaseId, Lifecycle lifecycle) { - PhaseEvent afterPhaseEvent = new PhaseEvent(getFacesContext(lifecycle), phaseId, lifecycle); + public static void notifyAfterListeners(PhaseId phaseId, Lifecycle lifecycle, FacesContext context) { + PhaseEvent afterPhaseEvent = new PhaseEvent(context, phaseId, lifecycle); for (int i = 0; i < lifecycle.getPhaseListeners().length; i++) { PhaseListener listener = lifecycle.getPhaseListeners()[i]; if (listener.getPhaseId() == phaseId || listener.getPhaseId() == PhaseId.ANY_PHASE) { @@ -56,8 +38,8 @@ class JsfFlowUtils { } } - public static void notifyBeforeListeners(PhaseId phaseId, Lifecycle lifecycle) { - PhaseEvent beforePhaseEvent = new PhaseEvent(getFacesContext(lifecycle), phaseId, lifecycle); + public static void notifyBeforeListeners(PhaseId phaseId, Lifecycle lifecycle, FacesContext context) { + PhaseEvent beforePhaseEvent = new PhaseEvent(context, phaseId, lifecycle); for (int i = 0; i < lifecycle.getPhaseListeners().length; i++) { PhaseListener listener = lifecycle.getPhaseListeners()[i]; if (listener.getPhaseId() == phaseId || listener.getPhaseId() == PhaseId.ANY_PHASE) { @@ -65,11 +47,4 @@ class JsfFlowUtils { } } } - - public static boolean isFlowRequest() { - if (RequestContextHolder.getRequestContext() == null) { - return false; - } - return true; - } } 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 d5c29645..f4fac490 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 @@ -18,15 +18,17 @@ package org.springframework.faces.webflow; import java.io.IOException; import javax.faces.FacesException; +import javax.faces.FactoryFinder; import javax.faces.component.UIViewRoot; import javax.faces.context.FacesContext; +import javax.faces.context.FacesContextFactory; import javax.faces.event.PhaseId; import javax.faces.lifecycle.Lifecycle; -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.webflow.execution.Event; -import org.springframework.webflow.execution.RequestContextHolder; +import org.springframework.webflow.execution.RequestContext; import org.springframework.webflow.execution.View; /** @@ -36,42 +38,32 @@ import org.springframework.webflow.execution.View; */ public class JsfView implements View { - public static final String EVENT_KEY = "org.springframework.webflow.FacesEvent"; + private static final Log logger = LogFactory.getLog(JsfView.class); - public static final String STATE_KEY = "org.springframework.webflow.FacesState"; + public static final String EVENT_KEY = "org.springframework.webflow.FacesEvent"; /** * The root of the JSF component tree managed by this view */ private UIViewRoot viewRoot; - private Event event; - private Lifecycle facesLifecycle; - public JsfView(UIViewRoot viewRoot, Lifecycle facesLifecycle) { - - Assert.notNull(viewRoot); - Assert.notNull(facesLifecycle); + private RequestContext context; + public JsfView(UIViewRoot viewRoot, Lifecycle facesLifecycle, RequestContext context) { this.viewRoot = viewRoot; this.facesLifecycle = facesLifecycle; + this.context = context; } public boolean eventSignaled() { - return getEvent() != null; + return context.getExternalContext().getRequestMap().contains(EVENT_KEY); } public Event getEvent() { - if (event == null) { - - String jsfEvent = (String) RequestContextHolder.getRequestContext().getExternalContext().getRequestMap() - .get(EVENT_KEY); - if (StringUtils.hasText(jsfEvent)) { - event = new Event(this, jsfEvent); - } - } - return event; + String eventId = (String) context.getExternalContext().getRequestMap().get(EVENT_KEY); + return new Event(this, eventId); } public UIViewRoot getViewRoot() { @@ -82,19 +74,33 @@ public class JsfView implements View { * This implementation performs the standard duties of the JSF RENDER_RESPONSE phase. */ public void render() { - FacesContext facesContext = JsfFlowUtils.getFacesContext(facesLifecycle); + FacesContext facesContext = createFlowFacesContext(); facesContext.setViewRoot(viewRoot); facesContext.renderResponse(); try { - JsfFlowUtils.notifyBeforeListeners(PhaseId.RENDER_RESPONSE, facesLifecycle); + JsfUtils.notifyBeforeListeners(PhaseId.RENDER_RESPONSE, facesLifecycle, facesContext); + logger.debug("Asking view handler to render view"); facesContext.getApplication().getViewHandler().renderView(facesContext, viewRoot); - JsfFlowUtils.notifyAfterListeners(PhaseId.RENDER_RESPONSE, facesLifecycle); + JsfUtils.notifyAfterListeners(PhaseId.RENDER_RESPONSE, facesLifecycle, facesContext); } catch (IOException e) { throw new FacesException("An I/O error occurred during view rendering", e); } finally { + logger.debug("View rendering complete"); facesContext.responseComplete(); facesContext.release(); } } -} + private FacesContext createFlowFacesContext() { + FacesContextFactory facesContextFactory = (FacesContextFactory) FactoryFinder + .getFactory(FactoryFinder.FACES_CONTEXT_FACTORY); + FacesContext defaultFacesContext = facesContextFactory.getFacesContext(context.getExternalContext() + .getContext(), context.getExternalContext().getRequest(), context.getExternalContext().getResponse(), + facesLifecycle); + return new FlowFacesContext(context, defaultFacesContext); + } + + public String toString() { + return "[JSFView = '" + viewRoot.getViewId() + "']"; + } +} \ No newline at end of file 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 daef629d..2b7e083a 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,15 +17,19 @@ package org.springframework.faces.webflow; import java.util.Iterator; -import javax.el.ELContext; import javax.el.ValueExpression; +import javax.faces.FactoryFinder; import javax.faces.application.ViewHandler; import javax.faces.component.UIComponent; import javax.faces.component.UIViewRoot; import javax.faces.context.FacesContext; +import javax.faces.context.FacesContextFactory; import javax.faces.event.PhaseId; import javax.faces.lifecycle.Lifecycle; +import javax.faces.lifecycle.LifecycleFactory; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.binding.expression.Expression; import org.springframework.core.io.ContextResource; import org.springframework.core.io.ResourceLoader; @@ -44,67 +48,67 @@ import org.springframework.webflow.execution.ViewFactory; */ public class JsfViewFactory implements ViewFactory { - private final Lifecycle facesLifecycle; + private static final Log logger = LogFactory.getLog(JsfViewFactory.class); private final Expression viewExpr; private final ResourceLoader resourceLoader; - public JsfViewFactory(Lifecycle facesLifecycle, Expression viewExpr, ResourceLoader resourceLoader) { - - this.facesLifecycle = facesLifecycle; + public JsfViewFactory(Expression viewExpr, ResourceLoader resourceLoader) { this.viewExpr = viewExpr; this.resourceLoader = resourceLoader; } public View getView(RequestContext context) { - - String viewName = resolveViewName(context); - FacesContext facesContext = JsfFlowUtils.getFacesContext(facesLifecycle); + Lifecycle lifecycle = createFlowFacesLifecycle(); + FacesContext facesContext = createFlowFacesContext(context, lifecycle); try { - boolean restored = false; - if (!facesContext.getRenderResponse()) { - JsfFlowUtils.notifyBeforeListeners(PhaseId.RESTORE_VIEW, facesLifecycle); + JsfUtils.notifyBeforeListeners(PhaseId.RESTORE_VIEW, lifecycle, facesContext); } - - JsfView view; - - ViewHandler handler = facesContext.getApplication().getViewHandler(); - - if (viewExists(facesContext, viewName)) { - view = new JsfView(facesContext.getViewRoot(), facesLifecycle); - restored = true; - } else { - UIViewRoot root = handler.restoreView(facesContext, viewName); - if (root != null) { - view = new JsfView(root, facesLifecycle); - restored = true; - } else { - view = new JsfView(handler.createView(facesContext, viewName), facesLifecycle); - restored = false; + String viewName = resolveViewName(context); + ViewHandler viewHandler = facesContext.getApplication().getViewHandler(); + viewHandler.initView(facesContext); + UIViewRoot viewRoot = viewHandler.restoreView(facesContext, viewName); + if (viewRoot != null) { + if (logger.isDebugEnabled()) { + logger.debug("View root restored for '" + viewName + "'"); } + facesContext.setViewRoot(viewRoot); + processComponentBinding(facesContext, viewRoot); + JsfUtils.notifyAfterListeners(PhaseId.RESTORE_VIEW, lifecycle, facesContext); + lifecycle.execute(facesContext); + return new JsfView(viewRoot, lifecycle, context); + } else { + if (logger.isDebugEnabled()) { + logger.debug("Creating view root for '" + viewName + "'"); + } + viewRoot = viewHandler.createView(facesContext, viewName); + facesContext.setViewRoot(viewRoot); + JsfUtils.notifyAfterListeners(PhaseId.RESTORE_VIEW, lifecycle, facesContext); + return new JsfView(viewRoot, lifecycle, context); } - - facesContext.setViewRoot(view.getViewRoot()); - - processBindings(facesContext.getELContext(), view.getViewRoot()); - - if (!facesContext.getRenderResponse()) { - JsfFlowUtils.notifyAfterListeners(PhaseId.RESTORE_VIEW, facesLifecycle); - } - - if (restored && !facesContext.getResponseComplete() && !facesContext.getRenderResponse()) { - facesLifecycle.execute(facesContext); - facesContext.renderResponse(); - } - - return view; } finally { facesContext.release(); } } + private Lifecycle createFlowFacesLifecycle() { + LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder + .getFactory(FactoryFinder.LIFECYCLE_FACTORY); + Lifecycle defaultLifecycle = lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE); + return new FlowLifecycle(defaultLifecycle); + } + + private FacesContext createFlowFacesContext(RequestContext context, Lifecycle lifecycle) { + FacesContextFactory facesContextFactory = (FacesContextFactory) FactoryFinder + .getFactory(FactoryFinder.FACES_CONTEXT_FACTORY); + FacesContext defaultFacesContext = facesContextFactory.getFacesContext(context.getExternalContext() + .getContext(), context.getExternalContext().getRequest(), context.getExternalContext().getResponse(), + lifecycle); + return new FlowFacesContext(context, defaultFacesContext); + } + private String resolveViewName(RequestContext context) { String viewId = (String) viewExpr.getValue(context); if (viewId.startsWith("/")) { @@ -115,24 +119,13 @@ public class JsfViewFactory implements ViewFactory { } } - private boolean viewExists(FacesContext facesContext, String viewId) { - if (facesContext.getViewRoot() != null && facesContext.getViewRoot().getViewId().equals(viewId)) { - return true; + private void processComponentBinding(FacesContext context, UIComponent component) { + ValueExpression binding = component.getValueExpression("binding"); + if (binding != null) { + binding.setValue(context.getELContext(), component); } - return false; - } - - private void processBindings(ELContext elContext, UIComponent component) { - - ValueExpression expr = component.getValueExpression("binding"); - if (expr != null) { - expr.setValue(elContext, component); - } - - Iterator i = component.getChildren().iterator(); - while (i.hasNext()) { - UIComponent child = (UIComponent) i.next(); - processBindings(elContext, child); + for (Iterator iter = component.getFacetsAndChildren(); iter.hasNext();) { + processComponentBinding(context, iter.next()); } } -} +} \ No newline at end of file diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/JsfViewFactoryCreator.java b/spring-faces/src/main/java/org/springframework/faces/webflow/JsfViewFactoryCreator.java index 3235aa37..88e4eff3 100644 --- a/spring-faces/src/main/java/org/springframework/faces/webflow/JsfViewFactoryCreator.java +++ b/spring-faces/src/main/java/org/springframework/faces/webflow/JsfViewFactoryCreator.java @@ -15,9 +15,6 @@ */ package org.springframework.faces.webflow; -import javax.faces.FactoryFinder; -import javax.faces.lifecycle.LifecycleFactory; - import org.springframework.binding.expression.Expression; import org.springframework.core.io.ResourceLoader; import org.springframework.webflow.engine.builder.ViewFactoryCreator; @@ -32,14 +29,11 @@ import org.springframework.webflow.execution.ViewFactory; public class JsfViewFactoryCreator implements ViewFactoryCreator { public Action createFinalResponseAction(Expression viewName, ResourceLoader resourceLoader) { - return new JsfRenderFinalResponseAction(new JsfViewFactory(((LifecycleFactory) FactoryFinder - .getFactory(FactoryFinder.LIFECYCLE_FACTORY)).getLifecycle(FlowLifecycleFactory.FLOW_LIFECYCLE_ID), - viewName, resourceLoader)); + return new JsfFinalResponseAction(new JsfViewFactory(viewName, resourceLoader)); } public ViewFactory createViewFactory(Expression viewName, ResourceLoader resourceLoader) { - return new JsfViewFactory(((LifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY)) - .getLifecycle(FlowLifecycleFactory.FLOW_LIFECYCLE_ID), viewName, resourceLoader); + return new JsfViewFactory(viewName, resourceLoader); } } diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/TreeStructureManager.java b/spring-faces/src/main/java/org/springframework/faces/webflow/TreeStructureManager.java new file mode 100644 index 00000000..699abd34 --- /dev/null +++ b/spring-faces/src/main/java/org/springframework/faces/webflow/TreeStructureManager.java @@ -0,0 +1,153 @@ +/* + * Copyright 2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.faces.webflow; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.faces.component.UIComponent; +import javax.faces.component.UIViewRoot; + +import org.apache.myfaces.shared_impl.util.ClassUtils; + +/** + * @author Manfred Geiler (latest modification by $Author: dennisbyrne $) + * @version $Revision: 511715 $ $Date: 2007-02-26 05:05:36 +0100 (Mo, 26 Feb 2007) $ + */ +class TreeStructureManager { + public Serializable buildTreeStructureToSave(UIViewRoot viewRoot) { + return internalBuildTreeStructureToSave(viewRoot); + } + + private TreeStructComponent internalBuildTreeStructureToSave(UIComponent component) { + TreeStructComponent structComp = new TreeStructComponent(component.getClass().getName(), component.getId()); + + // children + if (component.getChildCount() > 0) { + List childList = component.getChildren(); + List structChildList = new ArrayList(); + for (int i = 0, len = childList.size(); i < len; i++) { + UIComponent child = (UIComponent) childList.get(i); + if (!child.isTransient()) { + TreeStructComponent structChild = internalBuildTreeStructureToSave(child); + structChildList.add(structChild); + } + } + TreeStructComponent[] childArray = structChildList.toArray(new TreeStructComponent[structChildList.size()]); + structComp.setChildren(childArray); + } + + // facets + Map facetMap = component.getFacets(); + if (!facetMap.isEmpty()) { + List structFacetList = new ArrayList(); + for (Iterator it = facetMap.entrySet().iterator(); it.hasNext();) { + Map.Entry entry = (Map.Entry) it.next(); + UIComponent child = (UIComponent) entry.getValue(); + if (!child.isTransient()) { + String facetName = (String) entry.getKey(); + TreeStructComponent structChild = internalBuildTreeStructureToSave(child); + structFacetList.add(new Object[] { facetName, structChild }); + } + } + Object[] facetArray = structFacetList.toArray(new Object[structFacetList.size()]); + structComp.setFacets(facetArray); + } + + return structComp; + } + + public UIViewRoot restoreTreeStructure(Object treeStructRoot) { + if (treeStructRoot instanceof TreeStructComponent) { + return (UIViewRoot) internalRestoreTreeStructure((TreeStructComponent) treeStructRoot); + } + throw new IllegalArgumentException("TreeStructure of type " + treeStructRoot.getClass().getName() + + " is not supported."); + } + + private UIComponent internalRestoreTreeStructure(TreeStructComponent treeStructComp) { + String compClass = treeStructComp.getComponentClass(); + String compId = treeStructComp.getComponentId(); + UIComponent component = (UIComponent) ClassUtils.newInstance(compClass); + component.setId(compId); + + // children + TreeStructComponent[] childArray = treeStructComp.getChildren(); + if (childArray != null) { + List childList = component.getChildren(); + for (int i = 0, len = childArray.length; i < len; i++) { + UIComponent child = internalRestoreTreeStructure(childArray[i]); + childList.add(child); + } + } + + // facets + Object[] facetArray = treeStructComp.getFacets(); + if (facetArray != null) { + Map facetMap = component.getFacets(); + for (int i = 0, len = facetArray.length; i < len; i++) { + Object[] tuple = (Object[]) facetArray[i]; + String facetName = (String) tuple[0]; + TreeStructComponent structChild = (TreeStructComponent) tuple[1]; + UIComponent child = internalRestoreTreeStructure(structChild); + facetMap.put(facetName, child); + } + } + + return component; + } + + public static class TreeStructComponent implements Serializable { + private static final long serialVersionUID = 5069109074684737231L; + private String _componentClass; + private String _componentId; + private TreeStructComponent[] _children = null; // Array of children + private Object[] _facets = null; // Array of Array-tuples with Facetname and TreeStructComponent + + TreeStructComponent(String componentClass, String componentId) { + _componentClass = componentClass; + _componentId = componentId; + } + + public String getComponentClass() { + return _componentClass; + } + + public String getComponentId() { + return _componentId; + } + + void setChildren(TreeStructComponent[] children) { + _children = children; + } + + TreeStructComponent[] getChildren() { + return _children; + } + + Object[] getFacets() { + return _facets; + } + + void setFacets(Object[] facets) { + _facets = facets; + } + } + +} diff --git a/spring-faces/src/test/java/org/springframework/faces/webflow/FlowFacesContextTests.java b/spring-faces/src/test/java/org/springframework/faces/webflow/FlowFacesContextTests.java index b0dc6fc6..d07d00eb 100644 --- a/spring-faces/src/test/java/org/springframework/faces/webflow/FlowFacesContextTests.java +++ b/spring-faces/src/test/java/org/springframework/faces/webflow/FlowFacesContextTests.java @@ -16,7 +16,6 @@ import org.springframework.binding.message.MessageContext; import org.springframework.binding.message.MessageResolver; import org.springframework.binding.message.Severity; import org.springframework.webflow.execution.RequestContext; -import org.springframework.webflow.execution.RequestContextHolder; public class FlowFacesContextTests extends TestCase { @@ -30,8 +29,7 @@ public class FlowFacesContextTests extends TestCase { protected void setUp() throws Exception { jsf.setUp(); - facesContext = new FlowFacesContext(jsf.facesContext()); - RequestContextHolder.setRequestContext(requestContext); + facesContext = new FlowFacesContext(requestContext, jsf.facesContext()); } protected void tearDown() throws Exception { diff --git a/spring-faces/src/test/java/org/springframework/faces/webflow/JSFFlowExecutionTests.java b/spring-faces/src/test/java/org/springframework/faces/webflow/JSFFlowExecutionTests.java index 8969e0c6..8df4a7f1 100644 --- a/spring-faces/src/test/java/org/springframework/faces/webflow/JSFFlowExecutionTests.java +++ b/spring-faces/src/test/java/org/springframework/faces/webflow/JSFFlowExecutionTests.java @@ -48,6 +48,7 @@ import org.springframework.webflow.execution.FlowExecutionKey; import org.springframework.webflow.execution.FlowExecutionKeyFactory; import org.springframework.webflow.execution.RequestContext; import org.springframework.webflow.execution.ScopeType; +import org.springframework.webflow.test.MockRequestContext; public class JSFFlowExecutionTests extends TestCase { @@ -77,8 +78,8 @@ public class JSFFlowExecutionTests extends TestCase { flow = Flow.create("jsf-flow", null); - ViewState view1 = new ViewState(flow, "viewState1", new JsfViewFactory(new TestLifecycle(jsf.lifecycle()), - parser.parseExpression("/view1", RequestContext.class, String.class, null), null)); + ViewState view1 = new ViewState(flow, "viewState1", new JsfViewFactory(parser.parseExpression("/view1", + RequestContext.class, String.class, null), null)); view1.getTransitionSet().add(new Transition(on("event1"), to("doSomething"))); view1.getTransitionSet().add(new Transition(on("event2"), to("evalSomething"))); @@ -98,8 +99,8 @@ public class JSFFlowExecutionTests extends TestCase { String.class, null))); evalSomething.getTransitionSet().add(new Transition(on("success"), to("viewState2"))); - ViewState viewState2 = new ViewState(flow, "viewState2", new JsfViewFactory(new TestLifecycle(jsf.lifecycle()), - parser.parseExpression("/view2", RequestContext.class, String.class, null), null)); + ViewState viewState2 = new ViewState(flow, "viewState2", new JsfViewFactory(parser.parseExpression("/view2", + RequestContext.class, String.class, null), null)); viewState2.getEntryActionList().add(new ViewState2SetupAction()); viewState2.getTransitionSet().add(new Transition(on("event1"), to("endState1"))); @@ -114,7 +115,7 @@ public class JSFFlowExecutionTests extends TestCase { jsf = new JSFMockHelper(); jsf.tearDown(); jsf.setUp(); - FacesContext flowContext = new FlowFacesContext(jsf.facesContext()); + FacesContext flowContext = new FlowFacesContext(new MockRequestContext(), jsf.facesContext()); org.apache.shale.test.mock.MockFacesContext.setCurrentInstance(flowContext); viewHandler = new NoRenderViewHandler(); 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 cb641944..2aeb0c0f 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 @@ -3,6 +3,8 @@ package org.springframework.faces.webflow; import javax.faces.FactoryFinder; import javax.faces.application.Application; import javax.faces.component.UIViewRoot; +import javax.faces.context.FacesContext; +import javax.faces.context.FacesContextFactory; import javax.faces.lifecycle.LifecycleFactory; import javax.faces.render.RenderKitFactory; @@ -29,9 +31,6 @@ public class JSFMockHelper { private JSFMock mock = new JSFMock(); public Application application() { - if (mock.application() == null) { - return mock.facesContext.getApplication(); - } return mock.application(); } @@ -43,11 +42,11 @@ public class JSFMockHelper { return mock.externalContext(); } - public FlowFacesContext facesContext() { + public FacesContext facesContext() { return mock.facesContext(); } - public FlowFacesContextFactory facesContextFactory() { + public FacesContextFactory facesContextFactory() { return mock.facesContextFactory(); } @@ -93,8 +92,8 @@ public class JSFMockHelper { super("JSFMock"); } - FlowFacesContextFactory facesContextFactory; - FlowFacesContext facesContext; + FacesContextFactory facesContextFactory; + FacesContext facesContext; public void setUp() throws Exception { @@ -116,19 +115,18 @@ public class JSFMockHelper { FactoryFinder.setFactory(FactoryFinder.FACES_CONTEXT_FACTORY, "org.springframework.faces.webflow.MockBaseFacesContextFactory"); FactoryFinder.setFactory(FactoryFinder.FACES_CONTEXT_FACTORY, - "org.springframework.faces.webflow.FlowFacesContextFactory"); + "org.apache.shale.test.mock.MockFacesContextFactory"); FactoryFinder .setFactory(FactoryFinder.LIFECYCLE_FACTORY, "org.apache.shale.test.mock.MockLifecycleFactory"); FactoryFinder.setFactory(FactoryFinder.RENDER_KIT_FACTORY, "org.apache.shale.test.mock.MockRenderKitFactory"); + application = new MockApplication(); externalContext = new MockExternalContext(servletContext, request, response); lifecycleFactory = (MockLifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY); lifecycle = (MockLifecycle) lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE); - facesContextFactory = (FlowFacesContextFactory) FactoryFinder - .getFactory(FactoryFinder.FACES_CONTEXT_FACTORY); - facesContext = (FlowFacesContext) facesContextFactory.getFacesContext(servletContext, request, response, - lifecycle); + facesContextFactory = (FacesContextFactory) FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY); + facesContext = facesContextFactory.getFacesContext(servletContext, request, response, lifecycle); externalContext = (MockExternalContext) facesContext.getExternalContext(); UIViewRoot root = new UIViewRoot(); root.setViewId("/viewId"); @@ -171,11 +169,11 @@ public class JSFMockHelper { return externalContext; } - public FlowFacesContext facesContext() { + public FacesContext facesContext() { return facesContext; } - public FlowFacesContextFactory facesContextFactory() { + public FacesContextFactory facesContextFactory() { return facesContextFactory; } diff --git a/spring-faces/src/test/java/org/springframework/faces/webflow/JsfRenderFinalResponseActionTests.java b/spring-faces/src/test/java/org/springframework/faces/webflow/JsfFinalResponseActionTests.java similarity index 90% rename from spring-faces/src/test/java/org/springframework/faces/webflow/JsfRenderFinalResponseActionTests.java rename to spring-faces/src/test/java/org/springframework/faces/webflow/JsfFinalResponseActionTests.java index fc184c82..520f20e8 100644 --- a/spring-faces/src/test/java/org/springframework/faces/webflow/JsfRenderFinalResponseActionTests.java +++ b/spring-faces/src/test/java/org/springframework/faces/webflow/JsfFinalResponseActionTests.java @@ -25,16 +25,15 @@ import org.springframework.webflow.core.collection.LocalAttributeMap; import org.springframework.webflow.core.expression.el.WebFlowELExpressionParser; import org.springframework.webflow.execution.RequestContext; import org.springframework.webflow.execution.RequestContextHolder; -import org.springframework.webflow.execution.ViewFactory; import org.springframework.webflow.test.MockExternalContext; -public class JsfRenderFinalResponseActionTests extends TestCase { +public class JsfFinalResponseActionTests extends TestCase { private static final String VIEW_ID = "/testView.xhtml"; - private ViewFactory factory; + private JsfViewFactory factory; - private JsfRenderFinalResponseAction finalResponseAction; + private JsfFinalResponseAction finalResponseAction; private JSFMockHelper jsfMock = new JSFMockHelper(); @@ -67,9 +66,9 @@ public class JsfRenderFinalResponseActionTests extends TestCase { jsfMock.facesContext().setViewRoot(null); jsfMock.application().setViewHandler(viewHandler); lifecycle = new TestLifecycle(jsfMock.lifecycle()); - factory = new JsfViewFactory(lifecycle, parser.parseExpression("#{'" + VIEW_ID + "'}", RequestContext.class, - String.class, null), null); - finalResponseAction = new JsfRenderFinalResponseAction(factory); + factory = new JsfViewFactory(parser.parseExpression("#{'" + VIEW_ID + "'}", RequestContext.class, String.class, + null), null); + finalResponseAction = new JsfFinalResponseAction(factory); RequestContextHolder.setRequestContext(context); ExternalContext ext = new MockExternalContext(); EasyMock.expect(context.getExternalContext()).andStubReturn(ext); diff --git a/spring-faces/src/test/java/org/springframework/faces/webflow/JsfViewFactoryTests.java b/spring-faces/src/test/java/org/springframework/faces/webflow/JsfViewFactoryTests.java index ae89e6f3..9a4b4ac1 100644 --- a/spring-faces/src/test/java/org/springframework/faces/webflow/JsfViewFactoryTests.java +++ b/spring-faces/src/test/java/org/springframework/faces/webflow/JsfViewFactoryTests.java @@ -77,8 +77,7 @@ public class JsfViewFactoryTests extends TestCase { public final void testGetView_Create() { lifecycle = new NoEventLifecycle(jsfMock.lifecycle()); - factory = new JsfViewFactory(lifecycle, parser.parseExpression(VIEW_ID, RequestContext.class, String.class, - null), null); + factory = new JsfViewFactory(parser.parseExpression(VIEW_ID, RequestContext.class, String.class, null), null); UIViewRoot newRoot = new UIViewRoot(); newRoot.setViewId(VIEW_ID); @@ -99,8 +98,7 @@ public class JsfViewFactoryTests extends TestCase { public final void testGetView_Restore_NoEvent() { lifecycle = new NoEventLifecycle(jsfMock.lifecycle()); - factory = new JsfViewFactory(lifecycle, parser.parseExpression(VIEW_ID, RequestContext.class, String.class, - null), null); + factory = new JsfViewFactory(parser.parseExpression(VIEW_ID, RequestContext.class, String.class, null), null); UIViewRoot existingRoot = new UIViewRoot(); existingRoot.setViewId(VIEW_ID); @@ -121,8 +119,7 @@ public class JsfViewFactoryTests extends TestCase { public final void testGetView_Restore_EventSignaled() { lifecycle = new EventSignalingLifecycle(jsfMock.lifecycle()); - factory = new JsfViewFactory(lifecycle, parser.parseExpression(VIEW_ID, RequestContext.class, String.class, - null), null); + factory = new JsfViewFactory(parser.parseExpression(VIEW_ID, RequestContext.class, String.class, null), null); UIViewRoot existingRoot = new UIViewRoot(); existingRoot.setViewId(VIEW_ID); @@ -173,8 +170,7 @@ public class JsfViewFactoryTests extends TestCase { public final void testGetView_ExternalViewRoot() { lifecycle = new NoEventLifecycle(jsfMock.lifecycle()); - factory = new JsfViewFactory(lifecycle, parser.parseExpression(VIEW_ID, RequestContext.class, String.class, - null), null); + factory = new JsfViewFactory(parser.parseExpression(VIEW_ID, RequestContext.class, String.class, null), null); UIViewRoot newRoot = new UIViewRoot(); newRoot.setViewId(VIEW_ID); 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 43a6f6f9..7731f962 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 @@ -4,20 +4,15 @@ import java.io.IOException; import java.io.StringWriter; import javax.faces.FacesException; -import javax.faces.FactoryFinder; import javax.faces.component.UIForm; import javax.faces.component.UIInput; import javax.faces.component.UIViewRoot; import javax.faces.component.html.HtmlForm; import javax.faces.component.html.HtmlInputText; import javax.faces.context.FacesContext; -import javax.faces.render.RenderKitFactory; -import javax.faces.render.Renderer; -import javax.faces.render.ResponseStateManager; import junit.framework.TestCase; -import org.apache.shale.test.mock.MockRenderKit; import org.apache.shale.test.mock.MockResponseWriter; import org.apache.shale.test.mock.MockStateManager; import org.easymock.EasyMock; @@ -25,7 +20,6 @@ import org.springframework.webflow.core.collection.MutableAttributeMap; import org.springframework.webflow.execution.FlowExecutionContext; import org.springframework.webflow.execution.FlowExecutionKey; import org.springframework.webflow.execution.RequestContext; -import org.springframework.webflow.execution.RequestContextHolder; public class JsfViewTests extends TestCase { @@ -64,9 +58,6 @@ public class JsfViewTests extends TestCase { jsfMock.application().setStateManager(new TestStateManager()); jsfMock.facesContext().setResponseWriter(new MockResponseWriter(output, null, null)); - RenderKitFactory rkf = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY); - rkf.addRenderKit("TEST_KIT", new TestRenderKit()); - UIViewRoot viewToRender = new UIViewRoot(); viewToRender.setRenderKitId("TEST_KIT"); viewToRender.setViewId(VIEW_ID); @@ -81,9 +72,7 @@ public class JsfViewTests extends TestCase { form.getChildren().add(input); viewToRender.getChildren().add(form); - view = new JsfView(viewToRender, jsfMock.lifecycle()); - - RequestContextHolder.setRequestContext(requestContext); + view = new JsfView(viewToRender, jsfMock.lifecycle(), requestContext); } protected void tearDown() throws Exception { @@ -96,7 +85,6 @@ public class JsfViewTests extends TestCase { EasyMock.expect(requestContext.getFlowScope()).andStubReturn(flowMap); EasyMock.expect(requestContext.getFlowExecutionContext()).andStubReturn(flowExecutionContext); EasyMock.expect(flowExecutionContext.getKey()).andStubReturn(key); - EasyMock.expect(flowMap.put(EasyMock.matches(JsfView.STATE_KEY), EasyMock.anyObject())).andStubReturn(null); EasyMock.expect(flashMap.put(EasyMock.matches("renderResponse"), EasyMock.anyObject())).andStubReturn(null); EasyMock.expect(flashMap.put(EasyMock.matches("responseComplete"), EasyMock.anyObject())).andStubReturn(null); @@ -139,17 +127,4 @@ public class JsfViewTests extends TestCase { return state; } } - - private class TestRenderKit extends MockRenderKit { - Renderer renderer = new Renderer() { - }; - - public Renderer getRenderer(String family, String rendererType) { - return renderer; - } - - public ResponseStateManager getResponseStateManager() { - return new FlowResponseStateManager(); - } - } }