m2 code review / polishing / simplification

- removed flow faces context factory, not needed, favoring simple creation of flow faces context from jsf view factory / jsf view instead
- replace response state manager usage with state manager as discussed; allowed removal of custom render kit
- removed flow lifecycle factory; not needed, favoring simple creation of flow lifecycle factory from view factory instead.
this needs review, several tests still need updating
- misc naming improvements
- removed use of thread locals where possible
This commit is contained in:
Keith Donald
2007-11-18 04:37:05 +00:00
parent 4eb9192b70
commit ebfcf6b6bc
25 changed files with 472 additions and 671 deletions

View File

@@ -10,16 +10,12 @@
<classpathentry kind="lib" path="lib/global/spring-core.jar"/>
<classpathentry kind="lib" path="lib/global/spring-web.jar"/>
<classpathentry kind="lib" path="lib/global/spring-webmvc.jar"/>
<classpathentry kind="lib" path="lib/buildtime/avalon-framework.jar"/>
<classpathentry kind="lib" path="lib/buildtime/commons-beanutils.jar"/>
<classpathentry kind="lib" path="lib/buildtime/commons-codec.jar"/>
<classpathentry kind="lib" path="lib/buildtime/commons-collections.jar"/>
<classpathentry kind="lib" path="lib/buildtime/commons-digester.jar"/>
<classpathentry kind="lib" path="lib/buildtime/commons-discovery.jar"/>
<classpathentry kind="lib" path="lib/buildtime/concurrent.jar"/>
<classpathentry kind="lib" path="lib/buildtime/el-api.jar"/>
<classpathentry kind="lib" path="lib/buildtime/log4j.jar"/>
<classpathentry kind="lib" path="lib/buildtime/logkit.jar"/>
<classpathentry kind="lib" path="lib/buildtime/myfaces-api.jar" sourcepath="/Users/jgrelle/Desktop/myfaces-api-1.2.0-sources.jar"/>
<classpathentry kind="lib" path="lib/buildtime/myfaces-impl.jar" sourcepath="/Users/jgrelle/Desktop/myfaces-impl-1.2.0-sources.jar"/>
<classpathentry kind="lib" path="lib/test/easymock.jar"/>

View File

@@ -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">
<factory>
<lifecycle-factory>org.springframework.faces.webflow.FlowLifecycleFactory</lifecycle-factory>
<faces-context-factory>org.springframework.faces.webflow.FlowFacesContextFactory</faces-context-factory>
<render-kit-factory>org.springframework.faces.webflow.FlowRenderKitFactory</render-kit-factory>
</factory>
<application>
<action-listener>org.springframework.faces.webflow.FlowActionListener</action-listener>
<el-resolver>org.springframework.webflow.core.expression.el.RequestContextELResolver</el-resolver>
<el-resolver>org.springframework.webflow.core.expression.el.ScopeSearchingELResolver</el-resolver>
<view-handler>org.springframework.faces.webflow.FlowExecutionViewHandler</view-handler>
<state-manager>org.springframework.faces.webflow.FlowViewStateManager</state-manager>
<view-handler>org.springframework.faces.webflow.FlowViewHandler</view-handler>
</application>
<lifecycle>
<phase-listener>org.springframework.faces.support.RequestLoggingPhaseListener</phase-listener>
</lifecycle>
<component>
<component-type>spring.faces.DojoClientTextValidator</component-type>
<component-class>org.springframework.faces.ui.DojoClientTextValidator</component-class>

View File

@@ -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();
}
}

View File

@@ -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<String> 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<FacesMessage> 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<FacesMessage> 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<FacesMessage> 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<FacesMessage> {
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<String> {
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];

View File

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

View File

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

View File

@@ -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.
* <p>
* 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<String> getLifecycleIds() {
return delegate.getLifecycleIds();
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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 = ("<input type=\"hidden\" name=\"" + VIEW_STATE_PARAM + "\" id=\""
+ VIEW_STATE_PARAM + "\" value=\"").toCharArray();
private static final char[] STATE_FIELD_END = "\" />".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);
}
}

View File

@@ -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();
}

View File

@@ -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<String, SerializedView> views;
public SerializedViewMap() {
views = new HashMap<String, SerializedView>();
}
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);
}
}
}
}

View File

@@ -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");
}
}

View File

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

View File

@@ -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;
}
}

View File

@@ -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() + "']";
}
}

View File

@@ -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<UIComponent> iter = component.getFacetsAndChildren(); iter.hasNext();) {
processComponentBinding(context, iter.next());
}
}
}
}

View File

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

View File

@@ -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<TreeStructComponent> structChildList = new ArrayList<TreeStructComponent>();
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<String, UIComponent> facetMap = component.getFacets();
if (!facetMap.isEmpty()) {
List<Object[]> structFacetList = new ArrayList<Object[]>();
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<UIComponent> 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<String, UIComponent> 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;
}
}
}

View File

@@ -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 {

View File

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

View File

@@ -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;
}

View File

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

View File

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

View File

@@ -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();
}
}
}