Author: lukaszlenart Date: Wed May 22 11:10:29 2013 New Revision: 1485149 URL: http://svn.apache.org/r1485149 Log: WW-4071 Adds new ValidationErrorAware interface to allow notify action about action/field errors
Added: struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/interceptor/ValidationErrorAware.java struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/interceptor/ValidationErrorAwareTest.java Modified: struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/interceptor/DefaultWorkflowInterceptor.java Modified: struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/interceptor/DefaultWorkflowInterceptor.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/interceptor/DefaultWorkflowInterceptor.java?rev=1485149&r1=1485148&r2=1485149&view=diff ============================================================================== --- struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/interceptor/DefaultWorkflowInterceptor.java (original) +++ struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/interceptor/DefaultWorkflowInterceptor.java Wed May 22 11:10:29 2013 @@ -71,14 +71,14 @@ import java.lang.reflect.Method; * <p/> * <pre> * <!-- START SNIPPET: example --> - * <p/> + * * <action name="someAction" class="com.examples.SomeAction"> * <interceptor-ref name="params"/> * <interceptor-ref name="validation"/> * <interceptor-ref name="workflow"/> * <result name="success">good_result.ftl</result> * </action> - * <p/> + * * <-- In this case myMethod as well as mySecondMethod of the action class * will not pass through the workflow process --> * <action name="someAction" class="com.examples.SomeAction"> @@ -89,7 +89,7 @@ import java.lang.reflect.Method; * </interceptor-ref name="workflow"> * <result name="success">good_result.ftl</result> * </action> - * <p/> + * * <-- In this case, the result named "error" will be used when * an action / field error is found --> * <-- The Interceptor will only be applied for myWorkflowMethod method of action @@ -104,7 +104,7 @@ import java.lang.reflect.Method; * </interceptor-ref> * <result name="success">good_result.ftl</result> * </action> - * <p/> + * * <!-- END SNIPPET: example --> * </pre> * @@ -121,7 +121,7 @@ public class DefaultWorkflowInterceptor private static final Logger LOG = LoggerFactory.getLogger(DefaultWorkflowInterceptor.class); private static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; - + private String inputResultName = Action.INPUT; /** @@ -149,31 +149,73 @@ public class DefaultWorkflowInterceptor if (validationAwareAction.hasErrors()) { if (LOG.isDebugEnabled()) { - LOG.debug("Errors on action " + validationAwareAction + ", returning result name 'input'"); + LOG.debug("Errors on action [#0], returning result name [#1]", validationAwareAction, inputResultName); } String resultName = inputResultName; + resultName = processValidationWorkflowAware(action, resultName); + resultName = processInputConfig(action, invocation.getProxy().getMethod(), resultName); + resultName = processValidationErrorAware(action, resultName); - if (action instanceof ValidationWorkflowAware) { - resultName = ((ValidationWorkflowAware) action).getInputResultName(); - } + return resultName; + } + } - InputConfig annotation = action.getClass().getMethod(invocation.getProxy().getMethod(), EMPTY_CLASS_ARRAY).getAnnotation(InputConfig.class); - if (annotation != null) { - if (!annotation.methodName().equals("")) { - Method method = action.getClass().getMethod(annotation.methodName()); - resultName = (String) method.invoke(action); - } else { - resultName = annotation.resultName(); - } - } + return invocation.invoke(); + } + /** + * Process {@link ValidationWorkflowAware} interface + */ + private String processValidationWorkflowAware(final Object action, final String currentResultName) { + String resultName = currentResultName; + if (action instanceof ValidationWorkflowAware) { + resultName = ((ValidationWorkflowAware) action).getInputResultName(); + if (LOG.isDebugEnabled()) { + LOG.debug("Changing result name from [#0] to [#1] because of processing [#2] interface applied to [#3]", + currentResultName, resultName, InputConfig.class.getSimpleName(), ValidationWorkflowAware.class.getSimpleName(), action); + } + } + return resultName; + } - return resultName; + /** + * Process {@link InputConfig} annotation applied to method + */ + protected String processInputConfig(final Object action, final String method, final String currentResultName) throws Exception { + String resultName = currentResultName; + InputConfig annotation = action.getClass().getMethod(method, EMPTY_CLASS_ARRAY).getAnnotation(InputConfig.class); + if (annotation != null) { + if (!annotation.methodName().equals("")) { + Method m = action.getClass().getMethod(annotation.methodName()); + resultName = (String) m.invoke(action); + } else { + resultName = annotation.resultName(); + } + if (LOG.isDebugEnabled()) { + LOG.debug("Changing result name from [#0] to [#1] because of processing annotation [#2] on action [#3]", + currentResultName, resultName, InputConfig.class.getSimpleName(), action); } } + return resultName; + } - return invocation.invoke(); + /** + * Notify action if it implements {@see ValidationErrorAware} interface + */ + protected String processValidationErrorAware(final Object action, final String currentResultName) { + String resultName = currentResultName; + if (action instanceof ValidationErrorAware) { + String validationErrorAwareResult = ((ValidationErrorAware) action).actionErrorOccurred(); + if (validationErrorAwareResult != null) { + if (LOG.isDebugEnabled()) { + LOG.debug("Changing result name from [#0] to [#1] because of processing interface [#2] on action [#3]", + currentResultName, resultName, ValidationErrorAware.class.getSimpleName(), action); + } + resultName = validationErrorAwareResult; + } + } + return resultName; } } Added: struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/interceptor/ValidationErrorAware.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/interceptor/ValidationErrorAware.java?rev=1485149&view=auto ============================================================================== --- struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/interceptor/ValidationErrorAware.java (added) +++ struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/interceptor/ValidationErrorAware.java Wed May 22 11:10:29 2013 @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2007,2009 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 com.opensymphony.xwork2.interceptor; + +/** + * ValidationErrorAware classes can be notified about validation errors + * before {@link com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor} will return 'inputResultName' result + * to allow change or not the result name + * + * This interface can be only applied to action which already implements {@link com.opensymphony.xwork2.ValidationAware} interface! + * + * @since 2.3.15 + */ +public interface ValidationErrorAware { + + /** + * Allows to notify action about occurred action/field errors + * + * @return new result name or null to keep result of {@link com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor} + */ + String actionErrorOccurred(); + +} Added: struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/interceptor/ValidationErrorAwareTest.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/interceptor/ValidationErrorAwareTest.java?rev=1485149&view=auto ============================================================================== --- struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/interceptor/ValidationErrorAwareTest.java (added) +++ struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/interceptor/ValidationErrorAwareTest.java Wed May 22 11:10:29 2013 @@ -0,0 +1,103 @@ +package com.opensymphony.xwork2.interceptor; + +import com.opensymphony.xwork2.Action; +import com.opensymphony.xwork2.ActionContext; +import com.opensymphony.xwork2.ActionInvocation; +import com.opensymphony.xwork2.ActionProxy; +import com.opensymphony.xwork2.ObjectFactory; +import com.opensymphony.xwork2.Validateable; +import com.opensymphony.xwork2.ValidationAware; +import com.opensymphony.xwork2.XWorkTestCase; +import com.opensymphony.xwork2.config.entities.ActionConfig; +import com.opensymphony.xwork2.config.entities.InterceptorConfig; +import com.opensymphony.xwork2.validator.ValidationInterceptor; +import junit.framework.Assert; +import org.easymock.EasyMock; +import org.easymock.IAnswer; + +import java.util.HashMap; + +public class ValidationErrorAwareTest extends XWorkTestCase { + + private DefaultWorkflowInterceptor interceptor; + private ActionInvocation invocation; + private String result = "testing123"; + private String actionResult = "action1234"; + + public void testChangeResultWhenNotifyAboutValidationErrors() throws Exception { + // given + ValidationInterceptor validationInterceptor = create(); + + // when + validationInterceptor.intercept(invocation); + + // then + assertEquals(actionResult, interceptor.intercept(invocation)); + } + + public void testNotChangeResultWhenNotifyAboutValidationError() throws Exception { + // given + actionResult = null; + ValidationInterceptor validationInterceptor = create(); + + // when + validationInterceptor.intercept(invocation); + + // then + Assert.assertEquals(Action.INPUT, interceptor.intercept(invocation)); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + ActionConfig config = new ActionConfig.Builder("", "name", "").build(); + ValidateErrorAction action = EasyMock.createNiceMock(ValidateErrorAction.class); + invocation = EasyMock.createNiceMock(ActionInvocation.class); + interceptor = new DefaultWorkflowInterceptor(); + ActionProxy proxy = EasyMock.createNiceMock(ActionProxy.class); + + EasyMock.expect(action.actionErrorOccurred()).andAnswer(new IAnswer<String>() { + public String answer() throws Throwable { + return actionResult; + } + }).anyTimes(); + EasyMock.expect(action.hasErrors()).andReturn(true).anyTimes(); + + EasyMock.expect(invocation.getProxy()).andReturn(proxy).anyTimes(); + EasyMock.expect(invocation.getAction()).andReturn(action).anyTimes(); + EasyMock.expect(invocation.invoke()).andAnswer(new IAnswer<String>() { + public String answer() throws Throwable { + return result; + } + }).anyTimes(); + + EasyMock.expect(proxy.getConfig()).andReturn(config).anyTimes(); + EasyMock.expect(proxy.getMethod()).andReturn("execute").anyTimes(); + + + EasyMock.replay(invocation); + EasyMock.replay(action); + EasyMock.replay(proxy); + + ActionContext contex = new ActionContext(new HashMap<String, Object>()); + ActionContext.setContext(contex); + contex.setActionInvocation(invocation); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + protected ValidationInterceptor create() { + ObjectFactory objectFactory = container.getInstance(ObjectFactory.class); + return (ValidationInterceptor) objectFactory.buildInterceptor( + new InterceptorConfig.Builder("model", ValidationInterceptor.class.getName()).build(), new HashMap<String, String>()); + } + + private interface ValidateErrorAction extends Action, Validateable, ValidationAware, ValidationErrorAware { + + String execute(); + + } +}