diff --git a/build-spring-webflow/resources/changelog.txt b/build-spring-webflow/resources/changelog.txt index d0c0bbda..a1faa53d 100644 --- a/build-spring-webflow/resources/changelog.txt +++ b/build-spring-webflow/resources/changelog.txt @@ -17,6 +17,7 @@ Improvements Please see the existing converters in the org.springframework.binding.converters package for examples of refined Converter implementations. * Improved booking samples by removing the unnecessary dispatcher-servlet-config.xml file and favoring configuration driven by a single master Spring configuration file. * Made RequestContext and ExternalContext thread locals named for supporting introspection +* Added a MockExternalContext.setCurrentUser(Principal) method allowing for control over Principal implementation. Bug Fixes * Fixed a bug preventing the handling of NumberFormatExceptions when binding to number properties using the default NumberFormatter. @@ -28,8 +29,10 @@ Bug Fixes access an attribute through the 'attributes' property like ${currentEvent.attributes.attr}. The reference documentation was updated to reflect this change. * Fixed a bug resulting in loss of JSF ExternalContext state during execution of the JSF Lifecycle. This bug was effecting integration of the Trindad component library, which requires a special Response object to be set for its Ajax support to work. - +* Fixed a bug preventing resolution of flow-local messages for flows launched as subflows. + Documentation +* Added documentation on Spring Faces integration with Rich Faces, Trindad, and IceFaces. * Added documentation on FlowHandler and externalRedirect: redirect prefixes. * Added documentation on accessing Web Flow artifacts from Maven Central. * Clarified the conversation-scoped and view-state managed persistence context patterns will be considered for implementation in future Web Flow releases. diff --git a/spring-binding/src/main/java/org/springframework/binding/message/DefaultMessageContext.java b/spring-binding/src/main/java/org/springframework/binding/message/DefaultMessageContext.java index f1f1c113..6587f5ab 100644 --- a/spring-binding/src/main/java/org/springframework/binding/message/DefaultMessageContext.java +++ b/spring-binding/src/main/java/org/springframework/binding/message/DefaultMessageContext.java @@ -16,6 +16,7 @@ package org.springframework.binding.message; import java.io.Serializable; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; @@ -28,8 +29,8 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.context.MessageSource; import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.context.support.AbstractMessageSource; import org.springframework.core.style.ToStringCreator; -import org.springframework.util.Assert; import org.springframework.util.CachingMapDecorator; /** @@ -37,7 +38,7 @@ import org.springframework.util.CachingMapDecorator; * * @author Keith Donald */ -class DefaultMessageContext implements StateManageableMessageContext { +public class DefaultMessageContext implements StateManageableMessageContext { private static final Log logger = LogFactory.getLog(DefaultMessageContext.class); @@ -49,10 +50,25 @@ class DefaultMessageContext implements StateManageableMessageContext { } }; + /** + * Creates a new default message context. + */ + public DefaultMessageContext() { + init(null); + } + + /** + * Creates a new default message context. + * @param messageSource the message source to resolve messages added to this context (may be null) + */ public DefaultMessageContext(MessageSource messageSource) { init(messageSource); } + public MessageSource getMessageSource() { + return messageSource; + } + // implementing message context public Message[] getAllMessages() { @@ -69,7 +85,6 @@ class DefaultMessageContext implements StateManageableMessageContext { } public Message[] getMessagesByCriteria(MessageCriteria criteria) { - Assert.notNull(criteria, "The message criteria is required"); List messages = new ArrayList(); Iterator it = sourceMessages.values().iterator(); while (it.hasNext()) { @@ -125,10 +140,17 @@ class DefaultMessageContext implements StateManageableMessageContext { sourceMessages.putAll((Map) messagesMemento); } + public void setMessageSource(MessageSource messageSource) { + if (messageSource == null) { + messageSource = new DefaultTextFallbackMessageSource(); + } + this.messageSource = messageSource; + } + // internal helpers private void init(MessageSource messageSource) { - this.messageSource = messageSource; + setMessageSource(messageSource); // create the 'null' source message list eagerly to ensure global messages are indexed first this.sourceMessages.get(null); } @@ -137,4 +159,9 @@ class DefaultMessageContext implements StateManageableMessageContext { return new ToStringCreator(this).append("sourceMessages", sourceMessages).toString(); } + private static class DefaultTextFallbackMessageSource extends AbstractMessageSource { + protected MessageFormat resolveCode(String code, Locale locale) { + return null; + } + } } \ No newline at end of file diff --git a/spring-binding/src/main/java/org/springframework/binding/message/DefaultMessageContextFactory.java b/spring-binding/src/main/java/org/springframework/binding/message/DefaultMessageContextFactory.java deleted file mode 100644 index 0fa1caa1..00000000 --- a/spring-binding/src/main/java/org/springframework/binding/message/DefaultMessageContextFactory.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2004-2008 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.binding.message; - -import java.text.MessageFormat; -import java.util.Locale; - -import org.springframework.context.MessageSource; -import org.springframework.context.support.AbstractMessageSource; - -/** - * Default message context factory that simply stores messages indexed in a map by their source. Suitable for use in - * most Spring applications that use Spring message sources for message resource bundles. Holds a reference to a Spring - * message resource bundle for performing message text resolution. - * - * @author Keith Donald - */ -public class DefaultMessageContextFactory implements MessageContextFactory { - - private MessageSource messageSource; - - /** - * Create a new message context factory. - * @param messageSource - */ - public DefaultMessageContextFactory(MessageSource messageSource) { - if (messageSource == null) { - messageSource = new DefaultTextFallbackMessageSource(); - } - this.messageSource = messageSource; - } - - public StateManageableMessageContext createMessageContext() { - return new DefaultMessageContext(messageSource); - } - - private class DefaultTextFallbackMessageSource extends AbstractMessageSource { - protected MessageFormat resolveCode(String code, Locale locale) { - return null; - } - } -} \ No newline at end of file diff --git a/spring-binding/src/main/java/org/springframework/binding/message/MessageContextFactory.java b/spring-binding/src/main/java/org/springframework/binding/message/MessageContextFactory.java deleted file mode 100644 index 1089850c..00000000 --- a/spring-binding/src/main/java/org/springframework/binding/message/MessageContextFactory.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2004-2008 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.binding.message; - -/** - * A factory for creating message context's whose internal state can be externally managed. Encapsulates the message - * context implementation used in a given environment. - * - * @author Keith Donald - */ -public interface MessageContextFactory { - - /** - * Create a new message context. - * @return the message context, initially empty, capable of having its state managed by an external care-taker. - */ - public StateManageableMessageContext createMessageContext(); -} diff --git a/spring-binding/src/main/java/org/springframework/binding/message/StateManageableMessageContext.java b/spring-binding/src/main/java/org/springframework/binding/message/StateManageableMessageContext.java index 31e9a683..0a943c81 100644 --- a/spring-binding/src/main/java/org/springframework/binding/message/StateManageableMessageContext.java +++ b/spring-binding/src/main/java/org/springframework/binding/message/StateManageableMessageContext.java @@ -17,6 +17,8 @@ package org.springframework.binding.message; import java.io.Serializable; +import org.springframework.context.MessageSource; + /** * A message context whose internal state can be managed by an external care-taker. State management employs the GOF * Memento pattern. This context can produce a serializable memento representing its internal state at any time. A @@ -27,7 +29,7 @@ import java.io.Serializable; public interface StateManageableMessageContext extends MessageContext { /** - * Create a serializable memento (token) representing a snapshot of the internal state of this message context. + * Create a serializable memento, or token representing a snapshot of the internal state of this message context. * @return the messages memento */ public Serializable createMessagesMemento(); @@ -38,4 +40,11 @@ public interface StateManageableMessageContext extends MessageContext { * @param messagesMemento the messages memento */ public void restoreMessages(Serializable messagesMemento); + + /** + * Configure the message source used to resolve messages added to this context. + * @param messageSource the message source + * @see MessageContext#addMessage(MessageResolver) + */ + public void setMessageSource(MessageSource messageSource); } diff --git a/spring-binding/src/test/java/org/springframework/binding/message/DefaultMessageContextFactoryTests.java b/spring-binding/src/test/java/org/springframework/binding/message/DefaultMessageContextFactoryTests.java index f7f788f4..3f2d53fa 100644 --- a/spring-binding/src/test/java/org/springframework/binding/message/DefaultMessageContextFactoryTests.java +++ b/spring-binding/src/test/java/org/springframework/binding/message/DefaultMessageContextFactoryTests.java @@ -8,17 +8,16 @@ import junit.framework.TestCase; import org.springframework.context.support.StaticMessageSource; public class DefaultMessageContextFactoryTests extends TestCase { - private DefaultMessageContextFactory factory; + private DefaultMessageContext context; protected void setUp() { StaticMessageSource messageSource = new StaticMessageSource(); - factory = new DefaultMessageContextFactory(messageSource); messageSource.addMessage("message", Locale.getDefault(), "Hello world resolved!"); messageSource.addMessage("argmessage", Locale.getDefault(), "Hello world {0}!"); + context = new DefaultMessageContext(messageSource); } public void testCreateMessageContext() { - MessageContext context = factory.createMessageContext(); context.addMessage(new MessageBuilder().defaultText("Hello world!").build()); Message[] messages = context.getAllMessages(); assertEquals(1, messages.length); @@ -28,7 +27,6 @@ public class DefaultMessageContextFactoryTests extends TestCase { } public void testResolveMessage() { - MessageContext context = factory.createMessageContext(); context.addMessage(new MessageBuilder().warning().source(this).code("message").build()); Message[] messages = context.getMessagesBySource(this); assertEquals(1, messages.length); @@ -38,7 +36,6 @@ public class DefaultMessageContextFactoryTests extends TestCase { } public void testResolveMessageDefaultText() { - MessageContext context = factory.createMessageContext(); context.addMessage(new MessageBuilder().error().code("bogus").defaultText("Hello world fallback!").build()); Message[] messages = context.getAllMessages(); assertEquals(1, messages.length); @@ -49,7 +46,6 @@ public class DefaultMessageContextFactoryTests extends TestCase { } public void testResolveMessageWithArgs() { - MessageContext context = factory.createMessageContext(); context.addMessage(new MessageBuilder().error().source(this).code("argmessage").arg("Keith").defaultText( "Hello world fallback!").build()); Message[] messages = context.getAllMessages(); @@ -61,7 +57,6 @@ public class DefaultMessageContextFactoryTests extends TestCase { } public void testResolveMessageWithMultipleCodes() { - MessageContext context = factory.createMessageContext(); context.addMessage(new MessageBuilder().error().source(this).code("bogus").code("argmessage").arg("Keith") .defaultText("Hello world fallback!").build()); Message[] messages = context.getMessagesBySource(this); @@ -73,7 +68,6 @@ public class DefaultMessageContextFactoryTests extends TestCase { } public void testSaveRestoreMessages() { - MessageContext context = factory.createMessageContext(); context.addMessage(new MessageBuilder().defaultText("Info").build()); context.addMessage(new MessageBuilder().error().defaultText("Error").build()); context.addMessage(new MessageBuilder().warning().source(this).code("message").build()); @@ -82,7 +76,7 @@ public class DefaultMessageContextFactoryTests extends TestCase { assertTrue(context instanceof StateManageableMessageContext); StateManageableMessageContext manageable = (StateManageableMessageContext) context; Serializable messages = manageable.createMessagesMemento(); - context = factory.createMessageContext(); + context = new DefaultMessageContext(context.getMessageSource()); assertEquals(0, context.getAllMessages().length); manageable = (StateManageableMessageContext) context; manageable.restoreMessages(messages); @@ -91,7 +85,6 @@ public class DefaultMessageContextFactoryTests extends TestCase { } public void testMessageSequencing() { - MessageContext context = factory.createMessageContext(); context.addMessage(new MessageBuilder().defaultText("Info").build()); context.addMessage(new MessageBuilder().warning().source(this).code("message").build()); context.addMessage(new MessageBuilder().error().defaultText("Error").build()); diff --git a/spring-webflow-samples/booking-faces/src/main/java/org/springframework/webflow/samples/booking/Booking.java b/spring-webflow-samples/booking-faces/src/main/java/org/springframework/webflow/samples/booking/Booking.java index 679cd04c..333c0cfb 100755 --- a/spring-webflow-samples/booking-faces/src/main/java/org/springframework/webflow/samples/booking/Booking.java +++ b/spring-webflow-samples/booking-faces/src/main/java/org/springframework/webflow/samples/booking/Booking.java @@ -180,11 +180,11 @@ public class Booking implements Serializable { public void validateEnterBookingDetails(MessageContext context) { if (checkinDate.before(today())) { - context.addMessage(new MessageBuilder().error().source("checkinDate").defaultText( - "The Check In Date must be a future date").build()); - } else if (!checkinDate.before(checkoutDate)) { - context.addMessage(new MessageBuilder().error().source("checkoutDate").defaultText( - "The Check Out Date must be later than the Check In Date").build()); + context.addMessage(new MessageBuilder().error().source("checkinDate").code( + "booking.checkinDate.beforeToday").build()); + } else if (checkoutDate.before(checkinDate)) { + context.addMessage(new MessageBuilder().error().source("checkoutDate").code( + "booking.checkoutDate.beforeCheckinDate").build()); } } diff --git a/spring-webflow-samples/booking-faces/src/main/webapp/WEB-INF/flows/booking/messages.properties b/spring-webflow-samples/booking-faces/src/main/webapp/WEB-INF/flows/booking/messages.properties new file mode 100644 index 00000000..cbae4eb3 --- /dev/null +++ b/spring-webflow-samples/booking-faces/src/main/webapp/WEB-INF/flows/booking/messages.properties @@ -0,0 +1,2 @@ +booking.checkinDate.beforeToday=The Check In Date must be a future date +booking.checkoutDate.beforeCheckinDate=The Check Out Date must be later than the Check In Date diff --git a/spring-webflow-samples/booking-mvc/src/main/webapp/WEB-INF/hotels/booking/messages.properties b/spring-webflow-samples/booking-mvc/src/main/webapp/WEB-INF/hotels/booking/messages.properties index bb7f4792..f91d121f 100644 --- a/spring-webflow-samples/booking-mvc/src/main/webapp/WEB-INF/hotels/booking/messages.properties +++ b/spring-webflow-samples/booking-mvc/src/main/webapp/WEB-INF/hotels/booking/messages.properties @@ -2,4 +2,4 @@ booking.checkinDate.typeMismatch=The Check In Date must be in the format dd/mm/y booking.checkinDate.beforeToday=The Check In Date must be a future date booking.checkoutDate.typeMismatch=The Check Out Date must be in the format dd/mm/yy -booking.checkoutDate.beforeCheckinDate=The Check Out date must be later than the Check In Date +booking.checkoutDate.beforeCheckinDate=The Check Out Date must be later than the Check In Date diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/impl/FlowExecutionImpl.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/impl/FlowExecutionImpl.java index 5a7105a9..9c90d44d 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/impl/FlowExecutionImpl.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/impl/FlowExecutionImpl.java @@ -25,9 +25,10 @@ import java.util.LinkedList; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.binding.message.DefaultMessageContext; import org.springframework.binding.message.MessageContext; -import org.springframework.binding.message.MessageContextFactory; import org.springframework.binding.message.StateManageableMessageContext; +import org.springframework.context.MessageSource; import org.springframework.core.style.ToStringCreator; import org.springframework.util.Assert; import org.springframework.webflow.context.ExternalContext; @@ -104,11 +105,6 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable { */ private transient FlowExecutionKeyFactory keyFactory; - /** - * The factory for message contexts for tracking flow execution messages. - */ - private transient MessageContextFactory messageContextFactory; - /** * The key assigned to this flow execution. May be null if a key has not been assigned. */ @@ -216,26 +212,27 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable { logger.debug("Starting execution in " + externalContext); } started = true; - RequestControlContext context = createControlContext(externalContext, createMessageContext()); - RequestContextHolder.setRequestContext(context); - listeners.fireRequestSubmitted(context); + MessageContext messageContext = createMessageContext(null); + RequestControlContext requestContext = createRequestContext(externalContext, messageContext); + RequestContextHolder.setRequestContext(requestContext); + listeners.fireRequestSubmitted(requestContext); try { - start(flow, input, context); + start(flow, input, requestContext); } catch (FlowExecutionException e) { - handleException(e, context); + handleException(e, requestContext); } catch (Exception e) { - handleException(wrap(e), context); + handleException(wrap(e), requestContext); } finally { if (!hasEnded()) { - saveMessages(context); + saveMessages(requestContext); try { - listeners.firePaused(context); + listeners.firePaused(requestContext); } catch (Throwable e) { logger.error("Flow execution listener threw exception", e); } } try { - listeners.fireRequestProcessed(context); + listeners.fireRequestProcessed(requestContext); } catch (Throwable e) { logger.error("Flow execution listener threw exception", e); } @@ -243,18 +240,6 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable { } } - public void setCurrentState(String stateId) { - State state = flow.getStateInstance(stateId); - FlowSessionImpl session; - if (started) { - session = getActiveSessionInternal(); - } else { - session = activateSession(flow); - started = true; - } - session.setCurrentState(state); - } - public void resume(ExternalContext externalContext) throws FlowExecutionException, IllegalStateException { if (!isActive()) { if (started) { @@ -266,27 +251,29 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable { if (logger.isDebugEnabled()) { logger.debug("Resuming execution in " + externalContext); } - RequestControlContext context = createControlContext(externalContext, createMessageContext()); - RequestContextHolder.setRequestContext(context); - listeners.fireRequestSubmitted(context); + Flow activeFlow = getActiveSessionInternal().getFlow(); + MessageContext messageContext = createMessageContext(activeFlow.getApplicationContext()); + RequestControlContext requestContext = createRequestContext(externalContext, messageContext); + RequestContextHolder.setRequestContext(requestContext); + listeners.fireRequestSubmitted(requestContext); try { - listeners.fireResuming(context); - getActiveSessionInternal().getFlow().resume(context); + listeners.fireResuming(requestContext); + activeFlow.resume(requestContext); } catch (FlowExecutionException e) { - handleException(e, context); + handleException(e, requestContext); } catch (Exception e) { - handleException(wrap(e), context); + handleException(wrap(e), requestContext); } finally { if (!hasEnded()) { - saveMessages(context); + saveMessages(requestContext); try { - listeners.firePaused(context); + listeners.firePaused(requestContext); } catch (Throwable e) { logger.error("Flow execution listener threw exception", e); } } try { - listeners.fireRequestProcessed(context); + listeners.fireRequestProcessed(requestContext); } catch (Throwable e) { logger.error("Flow execution listener threw exception", e); } @@ -294,8 +281,27 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable { } } - private MessageContext createMessageContext() { - StateManageableMessageContext messageContext = messageContextFactory.createMessageContext(); + /** + * Jump to a state of the currently active flow. If this execution has not been started, a new session will be + * activated and its current state will be set. This is a implementation-internal method that bypasses the + * {@link #start(MutableAttributeMap, ExternalContext)} operation and allows for jumping to an arbitrary flow state. + * Useful for testing. + * @param stateId the identifier of the state to jump to + */ + public void setCurrentState(String stateId) { + FlowSessionImpl session; + if (started) { + session = getActiveSessionInternal(); + } else { + session = activateSession(flow); + started = true; + } + State state = session.getFlow().getStateInstance(stateId); + session.setCurrentState(state); + } + + private MessageContext createMessageContext(MessageSource messageSource) { + StateManageableMessageContext messageContext = new DefaultMessageContext(messageSource); Serializable messagesMemento = (Serializable) getFlashScope().extract("messagesMemento"); if (messagesMemento != null) { messageContext.restoreMessages(messagesMemento); @@ -304,8 +310,8 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable { } private void saveMessages(RequestContext context) { - Serializable messagesMemento = ((StateManageableMessageContext) context.getMessageContext()) - .createMessagesMemento(); + StateManageableMessageContext messageContext = (StateManageableMessageContext) context.getMessageContext(); + Serializable messagesMemento = messageContext.createMessagesMemento(); getFlashScope().put("messagesMemento", messagesMemento); } @@ -315,7 +321,8 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable { * Create a flow execution control context. * @param externalContext the external context triggering this request */ - protected RequestControlContext createControlContext(ExternalContext externalContext, MessageContext messageContext) { + protected RequestControlContext createRequestContext(ExternalContext externalContext, + MessageContext messageContext) { return new RequestControlContextImpl(this, externalContext, messageContext); } @@ -337,6 +344,8 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable { if (input == null) { input = new LocalAttributeMap(); } + StateManageableMessageContext messageContext = (StateManageableMessageContext) context.getMessageContext(); + messageContext.setMessageSource(flow.getApplicationContext()); listeners.fireSessionStarting(context, session, input); flow.start(context, input); listeners.fireSessionStarted(context, session); @@ -429,14 +438,6 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable { this.keyFactory = keyFactory; } - MessageContextFactory getMessageContextFactory() { - return messageContextFactory; - } - - void setMessageContextFactory(MessageContextFactory messageContextFactory) { - this.messageContextFactory = messageContextFactory; - } - // Used by {@link FlowExecutionImplFactory} /** diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/impl/FlowExecutionImplFactory.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/impl/FlowExecutionImplFactory.java index 1cf6721f..bbb5245f 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/impl/FlowExecutionImplFactory.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/impl/FlowExecutionImplFactory.java @@ -19,7 +19,6 @@ import java.util.Iterator; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.binding.message.DefaultMessageContextFactory; import org.springframework.util.Assert; import org.springframework.webflow.core.collection.AttributeMap; import org.springframework.webflow.core.collection.CollectionUtils; @@ -81,7 +80,8 @@ public class FlowExecutionImplFactory implements FlowExecutionFactory { logger.debug("Creating new execution of '" + flowDefinition.getId() + "'"); } FlowExecutionImpl execution = new FlowExecutionImpl((Flow) flowDefinition); - configureServices(execution); + execution.setAttributes(executionAttributes); + execution.setListeners(executionListenerLoader.getListeners(execution.getDefinition())); execution.setKeyFactory(executionKeyFactory); return execution; } @@ -112,20 +112,10 @@ public class FlowExecutionImplFactory implements FlowExecutionFactory { conversationScope = new LocalAttributeMap(); } execution.setConversationScope(conversationScope); - configureServices(execution); - return execution; - } - - /** - * Called by subclasses to apply the configured set of standard services to the flow execution. - * @param execution the flow execution - */ - protected void configureServices(FlowExecutionImpl execution) { execution.setAttributes(executionAttributes); execution.setListeners(executionListenerLoader.getListeners(execution.getDefinition())); execution.setKeyFactory(executionKeyFactory); - execution.setMessageContextFactory(new DefaultMessageContextFactory(execution.getDefinition() - .getApplicationContext())); + return execution; } /** diff --git a/spring-webflow/src/main/java/org/springframework/webflow/test/MockExternalContext.java b/spring-webflow/src/main/java/org/springframework/webflow/test/MockExternalContext.java index 19dfa22e..902abd21 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/test/MockExternalContext.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/test/MockExternalContext.java @@ -247,7 +247,15 @@ public class MockExternalContext implements ExternalContext { } /** - * Sets the current user principal as a string. + * Sets the current user principal. + * @param currentUser the current user + */ + public void setCurrentUser(Principal currentUser) { + this.currentUser = currentUser; + } + + /** + * Convenience method that sets the current user principal as a string. * @param currentUser the current user name */ public void setCurrentUser(String currentUser) { diff --git a/spring-webflow/src/main/java/org/springframework/webflow/test/MockRequestContext.java b/spring-webflow/src/main/java/org/springframework/webflow/test/MockRequestContext.java index 822bee78..354a1470 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/test/MockRequestContext.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/test/MockRequestContext.java @@ -15,9 +15,8 @@ */ package org.springframework.webflow.test; -import org.springframework.binding.message.DefaultMessageContextFactory; +import org.springframework.binding.message.DefaultMessageContext; import org.springframework.binding.message.MessageContext; -import org.springframework.context.support.StaticMessageSource; import org.springframework.webflow.context.ExternalContext; import org.springframework.webflow.core.collection.AttributeMap; import org.springframework.webflow.core.collection.LocalAttributeMap; @@ -94,7 +93,7 @@ public class MockRequestContext implements RequestContext { public MockRequestContext(ParameterMap requestParameterMap) { this.flowExecutionContext = new MockFlowExecutionContext(); this.externalContext = new MockExternalContext(requestParameterMap); - this.messageContext = new DefaultMessageContextFactory(new StaticMessageSource()).createMessageContext(); + this.messageContext = new DefaultMessageContext(); } /** @@ -105,7 +104,7 @@ public class MockRequestContext implements RequestContext { public MockRequestContext(FlowExecutionContext flowExecutionContext) { this.flowExecutionContext = flowExecutionContext; this.externalContext = new MockExternalContext(); - this.messageContext = new DefaultMessageContextFactory(new StaticMessageSource()).createMessageContext(); + this.messageContext = new DefaultMessageContext(); } // implementing RequestContext diff --git a/spring-webflow/src/test/java/org/springframework/webflow/engine/impl/FlowExecutionImplTests.java b/spring-webflow/src/test/java/org/springframework/webflow/engine/impl/FlowExecutionImplTests.java index 0219cac3..3b95467b 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/engine/impl/FlowExecutionImplTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/engine/impl/FlowExecutionImplTests.java @@ -17,8 +17,6 @@ package org.springframework.webflow.engine.impl; import junit.framework.TestCase; -import org.springframework.binding.message.DefaultMessageContextFactory; -import org.springframework.context.support.StaticMessageSource; import org.springframework.webflow.core.collection.MutableAttributeMap; import org.springframework.webflow.engine.EndState; import org.springframework.webflow.engine.Flow; @@ -55,7 +53,6 @@ public class FlowExecutionImplTests extends TestCase { FlowExecutionListener[] listeners = new FlowExecutionListener[] { mockListener }; FlowExecutionImpl execution = new FlowExecutionImpl(flow); execution.setListeners(listeners); - execution.setMessageContextFactory(new DefaultMessageContextFactory(new StaticMessageSource())); MockExternalContext context = new MockExternalContext(); assertFalse(execution.hasStarted()); execution.start(null, context); @@ -89,7 +86,6 @@ public class FlowExecutionImplTests extends TestCase { FlowExecutionListener[] listeners = new FlowExecutionListener[] { mockListener }; FlowExecutionImpl execution = new FlowExecutionImpl(flow); execution.setListeners(listeners); - execution.setMessageContextFactory(new DefaultMessageContextFactory(new StaticMessageSource())); MockExternalContext context = new MockExternalContext(); execution.start(null, context); assertTrue(execution.isActive()); @@ -112,7 +108,6 @@ public class FlowExecutionImplTests extends TestCase { FlowExecutionListener[] listeners = new FlowExecutionListener[] { mockListener }; FlowExecutionImpl execution = new FlowExecutionImpl(flow); execution.setListeners(listeners); - execution.setMessageContextFactory(new DefaultMessageContextFactory(new StaticMessageSource())); MockExternalContext context = new MockExternalContext(); execution.start(null, context); assertTrue(execution.isActive()); @@ -130,7 +125,6 @@ public class FlowExecutionImplTests extends TestCase { FlowExecutionListener[] listeners = new FlowExecutionListener[] { mockListener }; FlowExecutionImpl execution = new FlowExecutionImpl(flow); execution.setListeners(listeners); - execution.setMessageContextFactory(new DefaultMessageContextFactory(new StaticMessageSource())); MockExternalContext context = new MockExternalContext(); assertFalse(execution.hasStarted()); try { @@ -150,7 +144,6 @@ public class FlowExecutionImplTests extends TestCase { } }; FlowExecutionImpl execution = new FlowExecutionImpl(flow); - execution.setMessageContextFactory(new DefaultMessageContextFactory(new StaticMessageSource())); MockExternalContext context = new MockExternalContext(); assertFalse(execution.hasStarted()); try { @@ -171,7 +164,6 @@ public class FlowExecutionImplTests extends TestCase { } }; FlowExecutionImpl execution = new FlowExecutionImpl(flow); - execution.setMessageContextFactory(new DefaultMessageContextFactory(new StaticMessageSource())); MockExternalContext context = new MockExternalContext(); assertFalse(execution.hasStarted()); try { @@ -186,7 +178,6 @@ public class FlowExecutionImplTests extends TestCase { Flow flow = new Flow("flow"); new EndState(flow, "end"); FlowExecutionImpl execution = new FlowExecutionImpl(flow); - execution.setMessageContextFactory(new DefaultMessageContextFactory(new StaticMessageSource())); MockExternalContext context = new MockExternalContext(); execution.start(null, context); try { @@ -203,7 +194,6 @@ public class FlowExecutionImplTests extends TestCase { MockFlowExecutionListener mockListener = new MockFlowExecutionListener(); FlowExecutionListener[] listeners = new FlowExecutionListener[] { mockListener }; FlowExecutionImpl execution = new FlowExecutionImpl(flow); - execution.setMessageContextFactory(new DefaultMessageContextFactory(new StaticMessageSource())); execution.setListeners(listeners); execution.setKeyFactory(new MockFlowExecutionKeyFactory()); MockExternalContext context = new MockExternalContext(); @@ -224,7 +214,6 @@ public class FlowExecutionImplTests extends TestCase { MockFlowExecutionListener mockListener = new MockFlowExecutionListener(); FlowExecutionListener[] listeners = new FlowExecutionListener[] { mockListener }; FlowExecutionImpl execution = new FlowExecutionImpl(flow); - execution.setMessageContextFactory(new DefaultMessageContextFactory(new StaticMessageSource())); execution.setListeners(listeners); MockExternalContext context = new MockExternalContext(); execution.start(null, context); @@ -242,7 +231,6 @@ public class FlowExecutionImplTests extends TestCase { Flow flow = new Flow("flow"); new EndState(flow, "end"); FlowExecutionImpl execution = new FlowExecutionImpl(flow); - execution.setMessageContextFactory(new DefaultMessageContextFactory(new StaticMessageSource())); MockExternalContext context = new MockExternalContext(); execution.start(null, context); try { @@ -263,7 +251,6 @@ public class FlowExecutionImplTests extends TestCase { MockFlowExecutionListener mockListener = new MockFlowExecutionListener(); FlowExecutionListener[] listeners = new FlowExecutionListener[] { mockListener }; FlowExecutionImpl execution = new FlowExecutionImpl(flow); - execution.setMessageContextFactory(new DefaultMessageContextFactory(new StaticMessageSource())); execution.setListeners(listeners); execution.setKeyFactory(new MockFlowExecutionKeyFactory()); MockExternalContext context = new MockExternalContext(); @@ -289,7 +276,6 @@ public class FlowExecutionImplTests extends TestCase { MockFlowExecutionListener mockListener = new MockFlowExecutionListener(); FlowExecutionListener[] listeners = new FlowExecutionListener[] { mockListener }; FlowExecutionImpl execution = new FlowExecutionImpl(flow); - execution.setMessageContextFactory(new DefaultMessageContextFactory(new StaticMessageSource())); execution.setListeners(listeners); execution.setKeyFactory(new MockFlowExecutionKeyFactory()); MockExternalContext context = new MockExternalContext(); @@ -318,7 +304,6 @@ public class FlowExecutionImplTests extends TestCase { FlowExecutionListener[] listeners = new FlowExecutionListener[] { mockListener }; FlowExecutionImpl execution = new FlowExecutionImpl(flow); execution.setListeners(listeners); - execution.setMessageContextFactory(new DefaultMessageContextFactory(new StaticMessageSource())); execution.setKeyFactory(new MockFlowExecutionKeyFactory()); MockExternalContext context = new MockExternalContext(); execution.start(null, context); @@ -336,7 +321,6 @@ public class FlowExecutionImplTests extends TestCase { } }; FlowExecutionImpl execution = new FlowExecutionImpl(flow); - execution.setMessageContextFactory(new DefaultMessageContextFactory(new StaticMessageSource())); execution.setKeyFactory(new MockFlowExecutionKeyFactory()); MockExternalContext context = new MockExternalContext();