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/>
+ *
  * &lt;action name="someAction" class="com.examples.SomeAction"&gt;
  *     &lt;interceptor-ref name="params"/&gt;
  *     &lt;interceptor-ref name="validation"/&gt;
  *     &lt;interceptor-ref name="workflow"/&gt;
  *     &lt;result name="success"&gt;good_result.ftl&lt;/result&gt;
  * &lt;/action&gt;
- * <p/>
+ *
  * &lt;-- In this case myMethod as well as mySecondMethod of the action class
  *        will not pass through the workflow process --&gt;
  * &lt;action name="someAction" class="com.examples.SomeAction"&gt;
@@ -89,7 +89,7 @@ import java.lang.reflect.Method;
  *     &lt;/interceptor-ref name="workflow"&gt;
  *     &lt;result name="success"&gt;good_result.ftl&lt;/result&gt;
  * &lt;/action&gt;
- * <p/>
+ *
  * &lt;-- In this case, the result named "error" will be used when
  *        an action / field error is found --&gt;
  * &lt;-- The Interceptor will only be applied for myWorkflowMethod method of 
action
@@ -104,7 +104,7 @@ import java.lang.reflect.Method;
  *     &lt;/interceptor-ref&gt;
  *     &lt;result name="success"&gt;good_result.ftl&lt;/result&gt;
  * &lt;/action&gt;
- * <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();
+
+    }
+}


Reply via email to