From 61c405b2958fb3c942e95c59353c8627b89dd353 Mon Sep 17 00:00:00 2001 From: Scott Andrews Date: Wed, 15 Oct 2008 20:26:51 +0000 Subject: [PATCH] SWF-735 provide additional context to vaidation methods invoked by convention --- .../binding/validation/ValidationContext.java | 46 ++++++ .../faces/webflow/FlowActionListener.java | 41 +---- .../webflow/samples/booking/Booking.java | 14 +- .../webflow/samples/booking/Booking.java | 13 +- .../webflow/mvc/view/AbstractMvcView.java | 38 +---- .../validation/DefaultValidationContext.java | 37 +++++ .../webflow/validation/ValidationHelper.java | 155 ++++++++++++++++++ .../webflow/validation/StubModelErrors.java | 29 ++++ .../validation/StubModelErrorsOverridden.java | 29 ++++ .../validation/StubModelMessageContext.java | 34 ++++ .../StubModelValidationContext.java | 36 ++++ .../validation/ValidationHelperTests.java | 103 ++++++++++++ 12 files changed, 492 insertions(+), 83 deletions(-) create mode 100644 spring-binding/src/main/java/org/springframework/binding/validation/ValidationContext.java create mode 100644 spring-webflow/src/main/java/org/springframework/webflow/validation/DefaultValidationContext.java create mode 100644 spring-webflow/src/main/java/org/springframework/webflow/validation/ValidationHelper.java create mode 100644 spring-webflow/src/test/java/org/springframework/webflow/validation/StubModelErrors.java create mode 100644 spring-webflow/src/test/java/org/springframework/webflow/validation/StubModelErrorsOverridden.java create mode 100644 spring-webflow/src/test/java/org/springframework/webflow/validation/StubModelMessageContext.java create mode 100644 spring-webflow/src/test/java/org/springframework/webflow/validation/StubModelValidationContext.java create mode 100644 spring-webflow/src/test/java/org/springframework/webflow/validation/ValidationHelperTests.java diff --git a/spring-binding/src/main/java/org/springframework/binding/validation/ValidationContext.java b/spring-binding/src/main/java/org/springframework/binding/validation/ValidationContext.java new file mode 100644 index 00000000..ccc646cf --- /dev/null +++ b/spring-binding/src/main/java/org/springframework/binding/validation/ValidationContext.java @@ -0,0 +1,46 @@ +/* + * Copyright 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.validation; + +import java.security.Principal; + +import org.springframework.binding.message.MessageContext; + +/** + * A context for validation events. + * + * @author Scott Andrews + * @since 2.0.4 + */ +public interface ValidationContext { + + /** + * Get the context for recording messages + */ + public MessageContext getMessageContext(); + + /** + * Get the current user principal + */ + public Principal getUserPrincipal(); + + /** + * Get the event that triggered validation + */ + public String getUserEvent(); + +} diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowActionListener.java b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowActionListener.java index c1cbfc07..bd5e7e87 100644 --- a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowActionListener.java +++ b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowActionListener.java @@ -15,7 +15,6 @@ */ package org.springframework.faces.webflow; -import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; @@ -28,17 +27,13 @@ import javax.faces.event.ActionListener; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.beans.factory.BeanFactory; import org.springframework.binding.expression.Expression; -import org.springframework.binding.message.MessageContext; -import org.springframework.binding.message.MessageContextErrors; -import org.springframework.util.ReflectionUtils; import org.springframework.util.StringUtils; -import org.springframework.validation.Errors; import org.springframework.webflow.definition.TransitionDefinition; import org.springframework.webflow.execution.RequestContext; import org.springframework.webflow.execution.RequestContextHolder; import org.springframework.webflow.execution.View; +import org.springframework.webflow.validation.ValidationHelper; /** * The default {@link ActionListener} implementation to be used with Web Flow. @@ -104,7 +99,7 @@ public class FlowActionListener implements ActionListener { RequestContext requestContext = RequestContextHolder.getRequestContext(); Object model = getModelObject(requestContext); if (shouldValidate(requestContext, model, eventId)) { - validate(requestContext, model); + validate(requestContext, model, eventId); if (requestContext.getMessageContext().hasErrorMessages()) { isValid = false; if (requestContext.getExternalContext().isAjaxRequest()) { @@ -155,34 +150,8 @@ public class FlowActionListener implements ActionListener { return true; } - private void validate(RequestContext requestContext, Object model) { - String validateMethodName = "validate" + StringUtils.capitalize(requestContext.getCurrentState().getId()); - Method validateMethod = ReflectionUtils.findMethod(model.getClass(), validateMethodName, - new Class[] { MessageContext.class }); - if (validateMethod != null) { - ReflectionUtils.invokeMethod(validateMethod, model, new Object[] { requestContext.getMessageContext() }); - } - BeanFactory beanFactory = requestContext.getActiveFlow().getApplicationContext(); - if (beanFactory != null) { - String validatorName = getModelExpression(requestContext).getExpressionString() + "Validator"; - if (beanFactory.containsBean(validatorName)) { - Object validator = beanFactory.getBean(validatorName); - validateMethod = ReflectionUtils.findMethod(validator.getClass(), validateMethodName, new Class[] { - model.getClass(), MessageContext.class }); - if (validateMethod != null) { - ReflectionUtils.invokeMethod(validateMethod, validator, new Object[] { model, - requestContext.getMessageContext() }); - } else { - validateMethod = ReflectionUtils.findMethod(validator.getClass(), validateMethodName, new Class[] { - model.getClass(), Errors.class }); - if (validateMethod != null) { - String objectName = getModelExpression(requestContext).getExpressionString(); - MessageContextErrors errors = new MessageContextErrors(requestContext.getMessageContext(), - objectName, model, null, null); - ReflectionUtils.invokeMethod(validateMethod, validator, new Object[] { model, errors }); - } - } - } - } + private void validate(RequestContext requestContext, Object model, String eventId) { + new ValidationHelper(model, requestContext, eventId, getModelExpression(requestContext).getExpressionString(), + null, null).validate(); } } 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 9b153f2a..8dbdaef2 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 @@ -17,7 +17,7 @@ import javax.persistence.TemporalType; import javax.persistence.Transient; import org.springframework.binding.message.MessageBuilder; -import org.springframework.binding.message.MessageContext; +import org.springframework.binding.validation.ValidationContext; /** * A Hotel Booking made by a User. @@ -189,13 +189,15 @@ public class Booking implements Serializable { this.amenities = amenities; } - public void validateEnterBookingDetails(MessageContext context) { + public void validateEnterBookingDetails(ValidationContext context) { + context.getUserEvent(); if (checkinDate.before(today())) { - context.addMessage(new MessageBuilder().error().source("checkinDate").code( - "booking.checkinDate.beforeToday").build()); + context.getMessageContext().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()); + context.getMessageContext().addMessage( + new MessageBuilder().error().source("checkoutDate").code("booking.checkoutDate.beforeCheckinDate") + .build()); } } diff --git a/spring-webflow-samples/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/Booking.java b/spring-webflow-samples/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/Booking.java index 75c0dbf2..30e3fe83 100755 --- a/spring-webflow-samples/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/Booking.java +++ b/spring-webflow-samples/booking-mvc/src/main/java/org/springframework/webflow/samples/booking/Booking.java @@ -18,7 +18,7 @@ import javax.persistence.TemporalType; import javax.persistence.Transient; import org.springframework.binding.message.MessageBuilder; -import org.springframework.binding.message.MessageContext; +import org.springframework.binding.validation.ValidationContext; /** * A Hotel Booking made by a User. @@ -188,13 +188,14 @@ public class Booking implements Serializable { this.amenities = amenities; } - public void validateEnterBookingDetails(MessageContext context) { + public void validateEnterBookingDetails(ValidationContext context) { if (checkinDate.before(today())) { - context.addMessage(new MessageBuilder().error().source("checkinDate").code( - "booking.checkinDate.beforeToday").build()); + context.getMessageContext().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()); + context.getMessageContext().addMessage( + new MessageBuilder().error().source("checkoutDate").code("booking.checkoutDate.beforeCheckinDate") + .build()); } } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcView.java b/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcView.java index 5bc7709b..2e473dd9 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcView.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcView.java @@ -17,7 +17,6 @@ package org.springframework.webflow.mvc.view; import java.io.IOException; import java.lang.reflect.Array; -import java.lang.reflect.Method; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -26,7 +25,6 @@ import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.beans.factory.BeanFactory; import org.springframework.binding.convert.ConversionExecutor; import org.springframework.binding.convert.ConversionService; import org.springframework.binding.expression.EvaluationException; @@ -41,13 +39,8 @@ import org.springframework.binding.mapping.MappingResultsCriteria; import org.springframework.binding.mapping.impl.DefaultMapper; import org.springframework.binding.mapping.impl.DefaultMapping; import org.springframework.binding.message.MessageBuilder; -import org.springframework.binding.message.MessageContext; -import org.springframework.binding.message.MessageContextErrors; import org.springframework.binding.message.MessageResolver; -import org.springframework.util.ReflectionUtils; -import org.springframework.util.StringUtils; import org.springframework.validation.BindingResult; -import org.springframework.validation.Errors; import org.springframework.web.util.WebUtils; import org.springframework.webflow.core.collection.ParameterMap; import org.springframework.webflow.definition.TransitionDefinition; @@ -57,6 +50,7 @@ import org.springframework.webflow.execution.Event; import org.springframework.webflow.execution.FlowExecutionKey; import org.springframework.webflow.execution.RequestContext; import org.springframework.webflow.execution.View; +import org.springframework.webflow.validation.ValidationHelper; /** * Base view implementation for the Spring Web MVC Servlet and Spring Web MVC Portlet frameworks. @@ -414,34 +408,8 @@ public abstract class AbstractMvcView implements View { } private void validate(Object model) { - String validateMethodName = "validate" + StringUtils.capitalize(requestContext.getCurrentState().getId()); - Method validateMethod = ReflectionUtils.findMethod(model.getClass(), validateMethodName, - new Class[] { MessageContext.class }); - if (validateMethod != null) { - ReflectionUtils.invokeMethod(validateMethod, model, new Object[] { requestContext.getMessageContext() }); - } - BeanFactory beanFactory = requestContext.getActiveFlow().getApplicationContext(); - if (beanFactory != null) { - String validatorName = getModelExpression().getExpressionString() + "Validator"; - if (beanFactory.containsBean(validatorName)) { - Object validator = beanFactory.getBean(validatorName); - validateMethod = ReflectionUtils.findMethod(validator.getClass(), validateMethodName, new Class[] { - model.getClass(), MessageContext.class }); - if (validateMethod != null) { - ReflectionUtils.invokeMethod(validateMethod, validator, new Object[] { model, - requestContext.getMessageContext() }); - } else { - validateMethod = ReflectionUtils.findMethod(validator.getClass(), validateMethodName, new Class[] { - model.getClass(), Errors.class }); - if (validateMethod != null) { - String objectName = getModelExpression().getExpressionString(); - MessageContextErrors errors = new MessageContextErrors(requestContext.getMessageContext(), - objectName, model, expressionParser, mappingResults); - ReflectionUtils.invokeMethod(validateMethod, validator, new Object[] { model, errors }); - } - } - } - } + new ValidationHelper(model, requestContext, eventId, getModelExpression().getExpressionString(), + expressionParser, mappingResults).validate(); } private void determineEventId(RequestContext context) { diff --git a/spring-webflow/src/main/java/org/springframework/webflow/validation/DefaultValidationContext.java b/spring-webflow/src/main/java/org/springframework/webflow/validation/DefaultValidationContext.java new file mode 100644 index 00000000..92c8a451 --- /dev/null +++ b/spring-webflow/src/main/java/org/springframework/webflow/validation/DefaultValidationContext.java @@ -0,0 +1,37 @@ +package org.springframework.webflow.validation; + +import java.security.Principal; + +import org.springframework.binding.message.MessageContext; +import org.springframework.binding.validation.ValidationContext; +import org.springframework.webflow.execution.RequestContext; + +public class DefaultValidationContext implements ValidationContext { + + private RequestContext requestContext; + private String eventId; + + public DefaultValidationContext(RequestContext requestContext, String eventId) { + this.requestContext = requestContext; + this.eventId = eventId; + } + + public MessageContext getMessageContext() { + return requestContext.getMessageContext(); + } + + public String getUserEvent() { + if (eventId != null) { + return eventId; + } else if (requestContext.getCurrentEvent() != null) { + return requestContext.getCurrentEvent().getId(); + } else { + return null; + } + } + + public Principal getUserPrincipal() { + return requestContext.getExternalContext().getCurrentUser(); + } + +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/validation/ValidationHelper.java b/spring-webflow/src/main/java/org/springframework/webflow/validation/ValidationHelper.java new file mode 100644 index 00000000..1fabbfde --- /dev/null +++ b/spring-webflow/src/main/java/org/springframework/webflow/validation/ValidationHelper.java @@ -0,0 +1,155 @@ +/* + * Copyright 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.webflow.validation; + +import java.lang.reflect.Method; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.binding.expression.ExpressionParser; +import org.springframework.binding.mapping.MappingResults; +import org.springframework.binding.message.MessageContext; +import org.springframework.binding.message.MessageContextErrors; +import org.springframework.binding.validation.ValidationContext; +import org.springframework.util.ReflectionUtils; +import org.springframework.util.StringUtils; +import org.springframework.validation.Errors; +import org.springframework.webflow.execution.RequestContext; + +/** + * A helper class the encapsulates conventions to invoke validation logic. + * + * @author Scott Andrews + */ +public class ValidationHelper { + + private final Object model; + private final RequestContext requestContext; + private final String eventId; + private final String modelName; + private final ExpressionParser expressionParser; + private final MappingResults mappingResults; + + /** + * Create a throwaway validation helper object. Validation is invoked by the {@link #validate()} method. + *

+ * Validation methods invoked include a validation method on the model object or a validator bean. The method name + * on either object is in the form of validate[viewStateId]. A ValidationContext is passed in the method signature + * along with the model object for validator beans. A MessageContext can be substituted for the ValidationContext. + *

+ * For example: model.validateEnterBookingDetails(VaticationContext) or + * context.getBean("modelValidator").validateEnterBookingDetails(model, VaticationContext) + * + * @param model the object to validate + * @param requestContext the context for the request + * @param eventId the event triggering validation + * @param modelName the name of the model object + * @param expressionParser the expression parser + * @param mappingResults object mapping results + */ + public ValidationHelper(Object model, RequestContext requestContext, String eventId, String modelName, + ExpressionParser expressionParser, MappingResults mappingResults) { + this.model = model; + this.requestContext = requestContext; + this.eventId = eventId; + this.modelName = modelName; + this.expressionParser = expressionParser; + this.mappingResults = mappingResults; + } + + /** + * Invoke the validators available by convention. + */ + public void validate() { + String validateMethodName = "validate" + StringUtils.capitalize(requestContext.getCurrentState().getId()); + validateWithContext(model, validateMethodName); + BeanFactory beanFactory = requestContext.getActiveFlow().getApplicationContext(); + if (beanFactory != null) { + String validatorName = modelName + "Validator"; + if (beanFactory.containsBean(validatorName)) { + Object validator = beanFactory.getBean(validatorName); + if (!validateWithModelAndContext(model, validator, validateMethodName)) { + validateWithModelAndErrors(model, validator, validateMethodName); + } + } + } + } + + /* + * Invoke validate method on the model for the current state passing either a MessageContext or ValidationContext. + * Preference is given to the ValidationContext method. + */ + private boolean validateWithContext(Object model, String validateMethodName) { + boolean validationInvoked = false; + Method validateMethod = ReflectionUtils.findMethod(model.getClass(), validateMethodName, + new Class[] { ValidationContext.class }); + if (validateMethod != null) { + ReflectionUtils.invokeMethod(validateMethod, model, new Object[] { new DefaultValidationContext( + requestContext, eventId) }); + validationInvoked = true; + } else { + validateMethod = ReflectionUtils.findMethod(model.getClass(), validateMethodName, + new Class[] { MessageContext.class }); + if (validateMethod != null) { + ReflectionUtils + .invokeMethod(validateMethod, model, new Object[] { requestContext.getMessageContext() }); + validationInvoked = true; + } + } + return validationInvoked; + } + + /* + * Invoke validate method on a distinct validator providing the model to validate and either a MessageContext or + * ValidationContext. Preference is given to the ValidationContext method. + */ + private boolean validateWithModelAndContext(Object model, Object validator, String validateMethodName) { + boolean validationInvoked = false; + Method validateMethod = ReflectionUtils.findMethod(validator.getClass(), validateMethodName, new Class[] { + model.getClass(), ValidationContext.class }); + if (validateMethod != null) { + ReflectionUtils.invokeMethod(validateMethod, validator, new Object[] { model, + new DefaultValidationContext(requestContext, eventId) }); + validationInvoked = true; + } else { + validateMethod = ReflectionUtils.findMethod(validator.getClass(), validateMethodName, new Class[] { + model.getClass(), MessageContext.class }); + if (validateMethod != null) { + ReflectionUtils.invokeMethod(validateMethod, validator, new Object[] { model, + requestContext.getMessageContext() }); + validationInvoked = true; + } + } + return validationInvoked; + } + + /* + * Invoke validate method on a distinct validator providing the model to validate and an Errors object. + */ + private boolean validateWithModelAndErrors(Object model, Object validator, String validateMethodName) { + boolean validationInvoked = false; + Method validateMethod = ReflectionUtils.findMethod(validator.getClass(), validateMethodName, new Class[] { + model.getClass(), Errors.class }); + if (validateMethod != null) { + MessageContextErrors errors = new MessageContextErrors(requestContext.getMessageContext(), modelName, + model, expressionParser, mappingResults); + ReflectionUtils.invokeMethod(validateMethod, validator, new Object[] { model, errors }); + validationInvoked = true; + } + return validationInvoked; + } + +} diff --git a/spring-webflow/src/test/java/org/springframework/webflow/validation/StubModelErrors.java b/spring-webflow/src/test/java/org/springframework/webflow/validation/StubModelErrors.java new file mode 100644 index 00000000..adc27a59 --- /dev/null +++ b/spring-webflow/src/test/java/org/springframework/webflow/validation/StubModelErrors.java @@ -0,0 +1,29 @@ +/* + * Copyright 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.webflow.validation; + +import org.springframework.validation.Errors; + +/** + * Support class for {@link ValidationHelperTest} + */ +public class StubModelErrors { + + public void validateMockState(Object model, Errors errors) { + errors.rejectValue("errors-external", "", ""); + } + +} diff --git a/spring-webflow/src/test/java/org/springframework/webflow/validation/StubModelErrorsOverridden.java b/spring-webflow/src/test/java/org/springframework/webflow/validation/StubModelErrorsOverridden.java new file mode 100644 index 00000000..830379a1 --- /dev/null +++ b/spring-webflow/src/test/java/org/springframework/webflow/validation/StubModelErrorsOverridden.java @@ -0,0 +1,29 @@ +/* + * Copyright 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.webflow.validation; + +import org.springframework.validation.Errors; + +/** + * Support class for {@link ValidationHelperTest} + */ +public class StubModelErrorsOverridden extends StubModelValidationContext { + + public void validateMockState(Object model, Errors errors) { + errors.rejectValue("errors-context", "", ""); + } + +} diff --git a/spring-webflow/src/test/java/org/springframework/webflow/validation/StubModelMessageContext.java b/spring-webflow/src/test/java/org/springframework/webflow/validation/StubModelMessageContext.java new file mode 100644 index 00000000..299fc750 --- /dev/null +++ b/spring-webflow/src/test/java/org/springframework/webflow/validation/StubModelMessageContext.java @@ -0,0 +1,34 @@ +/* + * Copyright 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.webflow.validation; + +import org.springframework.binding.message.MessageBuilder; +import org.springframework.binding.message.MessageContext; + +/** + * Support class for {@link ValidationHelperTest} + */ +public class StubModelMessageContext { + + public void validateMockState(MessageContext context) { + context.addMessage(new MessageBuilder().source("messagecontext").defaultText("").build()); + } + + public void validateMockState(Object model, MessageContext context) { + context.addMessage(new MessageBuilder().source("messagecontext-external").defaultText("").build()); + } + +} diff --git a/spring-webflow/src/test/java/org/springframework/webflow/validation/StubModelValidationContext.java b/spring-webflow/src/test/java/org/springframework/webflow/validation/StubModelValidationContext.java new file mode 100644 index 00000000..ec9c3c44 --- /dev/null +++ b/spring-webflow/src/test/java/org/springframework/webflow/validation/StubModelValidationContext.java @@ -0,0 +1,36 @@ +/* + * Copyright 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.webflow.validation; + +import org.springframework.binding.message.MessageBuilder; +import org.springframework.binding.validation.ValidationContext; + +/** + * Support class for {@link ValidationHelperTest} + */ +public class StubModelValidationContext { + + public void validateMockState(ValidationContext context) { + context.getMessageContext() + .addMessage(new MessageBuilder().source("validationcontext").defaultText("").build()); + } + + public void validateMockState(Object model, ValidationContext context) { + context.getMessageContext().addMessage( + new MessageBuilder().source("validationcontext-external").defaultText("").build()); + } + +} diff --git a/spring-webflow/src/test/java/org/springframework/webflow/validation/ValidationHelperTests.java b/spring-webflow/src/test/java/org/springframework/webflow/validation/ValidationHelperTests.java new file mode 100644 index 00000000..202958ab --- /dev/null +++ b/spring-webflow/src/test/java/org/springframework/webflow/validation/ValidationHelperTests.java @@ -0,0 +1,103 @@ +/* + * Copyright 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.webflow.validation; + +import junit.framework.TestCase; + +import org.springframework.binding.message.MessageContext; +import org.springframework.context.support.StaticApplicationContext; +import org.springframework.webflow.engine.Flow; +import org.springframework.webflow.test.MockRequestContext; + +/** + * Unit test for {@link ValidationHelper} + */ +public class ValidationHelperTests extends TestCase { + + private MockRequestContext requestContext; + private String eventId; + private String modelName; + + protected void setUp() throws Exception { + requestContext = new MockRequestContext(); + eventId = "userEvent"; + modelName = "model"; + } + + public void testValidateWithMessageContext() { + Object model = new StubModelMessageContext(); + ValidationHelper helper = new ValidationHelper(model, requestContext, eventId, modelName, null, null); + helper.validate(); + MessageContext messages = requestContext.getMessageContext(); + assertEquals(1, messages.getAllMessages().length); + assertEquals(1, messages.getMessagesBySource("messagecontext").length); + assertEquals(0, messages.getMessagesBySource("validationcontext").length); + } + + public void testValidateWithValidatioContext() { + Object model = new StubModelValidationContext(); + ValidationHelper helper = new ValidationHelper(model, requestContext, eventId, modelName, null, null); + helper.validate(); + MessageContext messages = requestContext.getMessageContext(); + assertEquals(1, messages.getAllMessages().length); + assertEquals(1, messages.getMessagesBySource("validationcontext").length); + } + + public void testValidateWithMessageContextForBeanValidator() { + StaticApplicationContext applicationContext = new StaticApplicationContext(); + applicationContext.registerSingleton("modelValidator", StubModelMessageContext.class); + ((Flow) requestContext.getActiveFlow()).setApplicationContext(applicationContext); + ValidationHelper helper = new ValidationHelper(new Object(), requestContext, eventId, modelName, null, null); + helper.validate(); + MessageContext messages = requestContext.getMessageContext(); + assertEquals(1, messages.getAllMessages().length); + assertEquals(1, messages.getMessagesBySource("messagecontext-external").length); + } + + public void testValidateWithValidationContextForBeanValidator() { + StaticApplicationContext applicationContext = new StaticApplicationContext(); + applicationContext.registerSingleton("modelValidator", StubModelValidationContext.class); + ((Flow) requestContext.getActiveFlow()).setApplicationContext(applicationContext); + ValidationHelper helper = new ValidationHelper(new Object(), requestContext, eventId, modelName, null, null); + helper.validate(); + MessageContext messages = requestContext.getMessageContext(); + assertEquals(1, messages.getAllMessages().length); + assertEquals(1, messages.getMessagesBySource("validationcontext-external").length); + } + + public void testValidateWithErrorsForBeanValidator() { + StaticApplicationContext applicationContext = new StaticApplicationContext(); + applicationContext.registerSingleton("modelValidator", StubModelErrors.class); + ((Flow) requestContext.getActiveFlow()).setApplicationContext(applicationContext); + ValidationHelper helper = new ValidationHelper(new Object(), requestContext, eventId, modelName, null, null); + helper.validate(); + MessageContext messages = requestContext.getMessageContext(); + assertEquals(1, messages.getAllMessages().length); + assertEquals(1, messages.getMessagesBySource("errors-external").length); + } + + public void testValidateWithErrorsForBeanValidatorOverridden() { + StaticApplicationContext applicationContext = new StaticApplicationContext(); + applicationContext.registerSingleton("modelValidator", StubModelErrorsOverridden.class); + ((Flow) requestContext.getActiveFlow()).setApplicationContext(applicationContext); + ValidationHelper helper = new ValidationHelper(new Object(), requestContext, eventId, modelName, null, null); + helper.validate(); + MessageContext messages = requestContext.getMessageContext(); + assertEquals(1, messages.getAllMessages().length); + assertEquals(1, messages.getMessagesBySource("validationcontext-external").length); + } + +}