You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by mu...@apache.org on 2007/04/27 03:51:08 UTC
svn commit: r532928 - in /struts/struts2/trunk/core/src:
main/java/org/apache/struts2/interceptor/validation/ main/resources/
main/resources/org/apache/struts2/static/
main/resources/template/css_xhtml/ main/resources/template/xhtml/
test/java/org/apac...
Author: musachy
Date: Thu Apr 26 18:51:07 2007
New Revision: 532928
URL: http://svn.apache.org/viewvc?view=rev&rev=532928
Log:
WW-1897 Create JSONValidationInterceptor
Added:
struts/struts2/trunk/core/src/main/java/org/apache/struts2/interceptor/validation/JSONValidationInterceptor.java
struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/utils.js
struts/struts2/trunk/core/src/test/java/org/apache/struts2/TestUtils.java
struts/struts2/trunk/core/src/test/java/org/apache/struts2/interceptor/validation/JSONValidationInterceptorTest.java
Removed:
struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/validationClient.js
Modified:
struts/struts2/trunk/core/src/main/resources/struts-default.xml
struts/struts2/trunk/core/src/main/resources/template/css_xhtml/validation.js
struts/struts2/trunk/core/src/main/resources/template/xhtml/validation.js
Added: struts/struts2/trunk/core/src/main/java/org/apache/struts2/interceptor/validation/JSONValidationInterceptor.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/interceptor/validation/JSONValidationInterceptor.java?view=auto&rev=532928
==============================================================================
--- struts/struts2/trunk/core/src/main/java/org/apache/struts2/interceptor/validation/JSONValidationInterceptor.java (added)
+++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/interceptor/validation/JSONValidationInterceptor.java Thu Apr 26 18:51:07 2007
@@ -0,0 +1,207 @@
+/*
+ * $Id$
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.struts2.interceptor.validation;
+
+import java.text.CharacterIterator;
+import java.text.StringCharacterIterator;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.struts2.ServletActionContext;
+
+import com.opensymphony.xwork2.Action;
+import com.opensymphony.xwork2.ActionInvocation;
+import com.opensymphony.xwork2.ValidationAware;
+
+/**
+ * <p>Extends the annotations validator and returns a JSON string with the
+ * validation errors. If validation succeeds the action is invoked.</p>
+ *
+ * <p>If 'validationFailedStatus' is set it will be used as the Response status
+ * when validation fails.</p>
+ *
+ * <p>If the request has a parameter 'validateOnly' execution will return after
+ * validation (action won't be executed).</p>
+ */
+public class JSONValidationInterceptor extends AnnotationValidationInterceptor {
+ private static final Log LOG = LogFactory
+ .getLog(JSONValidationInterceptor.class);
+ static char[] hex = "0123456789ABCDEF".toCharArray();
+
+ private int validationFailedStatus = -1;
+
+ /**
+ * HTTP status that will be set in the response if validation fails
+ * @param validationFailedStatus
+ */
+ public void setValidationFailedStatus(int validationFailedStatus) {
+ this.validationFailedStatus = validationFailedStatus;
+ }
+
+ @Override
+ protected String doIntercept(ActionInvocation invocation) throws Exception {
+ //validate
+ doBeforeInvocation(invocation);
+
+ HttpServletResponse response = ServletActionContext.getResponse();
+ HttpServletRequest request = ServletActionContext.getRequest();
+
+ Object action = invocation.getAction();
+
+ if (action instanceof ValidationAware) {
+ // generate json
+ ValidationAware validationAware = (ValidationAware) action;
+ if (validationAware.hasErrors()) {
+ if (validationFailedStatus >= 0)
+ response.setStatus(validationFailedStatus);
+ response.getWriter().print(buildResponse(validationAware));
+ return Action.NONE;
+ }
+ }
+
+ String validateOnly = request.getParameter("validateOnly");
+ if (validateOnly != null && "true".equals(validateOnly)) {
+ return Action.NONE;
+ } else {
+ return invocation.invoke();
+ }
+ }
+
+ /**
+ * @return JSON string that contains the errors and field errors
+ */
+ @SuppressWarnings("unchecked")
+ protected String buildResponse(ValidationAware validationAware) {
+ //should we use FreeMarker here?
+ StringBuilder sb = new StringBuilder();
+ sb.append("/* { ");
+
+ if (validationAware.hasErrors()) {
+ //action errors
+ if (validationAware.hasActionErrors()) {
+ sb.append("\"errors\":");
+ sb.append(buildArray(validationAware.getActionErrors()));
+ sb.append(",");
+ }
+
+ //field errors
+ if (validationAware.hasFieldErrors()) {
+ sb.append("\"fieldErrors\": {");
+ Map<String, List<String>> fieldErrors = validationAware
+ .getFieldErrors();
+ for (Map.Entry<String, List<String>> fieldError : fieldErrors
+ .entrySet()) {
+ sb.append("\"");
+ sb.append(fieldError.getKey());
+ sb.append("\":");
+ sb.append(buildArray(fieldError.getValue()));
+ sb.append(",");
+ }
+ //remove trailing comma, IE creates an empty object, duh
+ sb.deleteCharAt(sb.length() - 1);
+ sb.append("}");
+ }
+ }
+
+ sb.append("} */");
+ /*response should be something like:
+ * {
+ * "errors": ["this", "that"],
+ * "fieldErrors": {
+ * field1: "this",
+ * field2: "that"
+ * }
+ * }
+ */
+ return sb.toString();
+ }
+
+ private String buildArray(Collection<String> values) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("[");
+ for (String value : values) {
+ sb.append("\"");
+ sb.append(escapeJSON(value));
+ sb.append("\",");
+ }
+ if (values.size() > 0)
+ sb.deleteCharAt(sb.length() - 1);
+ sb.append("]");
+ return sb.toString();
+ }
+
+ private String escapeJSON(Object obj) {
+ StringBuilder sb = new StringBuilder();
+
+ CharacterIterator it = new StringCharacterIterator(obj.toString());
+
+ for (char c = it.first(); c != CharacterIterator.DONE; c = it.next()) {
+ if (c == '"') {
+ sb.append("\\\"");
+ } else if (c == '\\') {
+ sb.append("\\\\");
+ } else if (c == '/') {
+ sb.append("\\/");
+ } else if (c == '\b') {
+ sb.append("\\b");
+ } else if (c == '\f') {
+ sb.append("\\f");
+ } else if (c == '\n') {
+ sb.append("\\n");
+ } else if (c == '\r') {
+ sb.append("\\r");
+ } else if (c == '\t') {
+ sb.append("\\t");
+ } else if (Character.isISOControl(c)) {
+ sb.append(unicode(c));
+ } else {
+ sb.append(c);
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Represent as unicode
+ * @param c character to be encoded
+ */
+ private String unicode(char c) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("\\u");
+
+ int n = c;
+
+ for (int i = 0; i < 4; ++i) {
+ int digit = (n & 0xf000) >> 12;
+
+ sb.append(hex[digit]);
+ n <<= 4;
+ }
+ return sb.toString();
+ }
+
+}
Added: struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/utils.js
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/utils.js?view=auto&rev=532928
==============================================================================
--- struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/utils.js (added)
+++ struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/utils.js Thu Apr 26 18:51:07 2007
@@ -0,0 +1,68 @@
+var StrutsUtils = {};
+
+// gets an object with validation errors from string returned by
+// the ajaxValidation interceptor
+StrutsUtils.getValidationErrors = function(data) {
+ if(data.indexOf("/* {") == 0) {
+ return eval("( " + data.substring(2, data.length - 2) + " )");
+ } else {
+ return null;
+ }
+};
+
+StrutsUtils.clearValidationErrors = function(form) {
+ var firstNode = StrutsUtils.firstElement(form);
+ var xhtml = firstNode.tagName.toLowerCase() == "table";
+
+ if(xhtml) {
+ clearErrorMessagesXHTML(form);
+ clearErrorLabelsXHTML(form);
+ } else {
+ clearErrorMessagesCSS(form);
+ clearErrorLabelsCSS(form);
+ }
+};
+
+// shows validation errors using functions from xhtml/validation.js
+// or css_xhtml/validation.js
+StrutsUtils.showValidationErrors = function(form, errors) {
+ StrutsUtils.clearValidationErrors(form, errors);
+
+ var firstNode = StrutsUtils.firstElement(form);
+ var xhtml = firstNode.tagName.toLowerCase() == "table";
+ if(errors.fieldErrors) {
+ for(var fieldName in errors.fieldErrors) {
+ for(var i = 0; i < errors.fieldErrors[fieldName].length; i++) {
+ if(xhtml) {
+ addErrorXHTML(form.elements[fieldName], errors.fieldErrors[fieldName][i]);
+ } else {
+ addErrorCSS(form.elements[fieldName], errors.fieldErrors[fieldName][i]);
+ }
+ }
+ }
+ }
+};
+
+
+StrutsUtils.firstElement = function(parentNode, tagName) {
+ var node = parentNode.firstChild;
+ while(node && node.nodeType != 1){
+ node = node.nextSibling;
+ }
+ if(tagName && node && node.tagName && node.tagName.toLowerCase() != tagName.toLowerCase()) {
+ node = dojo.dom.nextElement(node, tagName);
+ }
+ return node;
+};
+
+StrutsUtils.nextElement = function(node, tagName){
+ if(!node) { return null; }
+ do {
+ node = node.nextSibling;
+ } while(node && node.nodeType != 1);
+
+ if(node && tagName && tagName.toLowerCase() != node.tagName.toLowerCase()) {
+ return StrutsUtils.nextElement(node, tagName);
+ }
+ return node;
+}
Modified: struts/struts2/trunk/core/src/main/resources/struts-default.xml
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/resources/struts-default.xml?view=diff&rev=532928&r1=532927&r2=532928
==============================================================================
--- struts/struts2/trunk/core/src/main/resources/struts-default.xml (original)
+++ struts/struts2/trunk/core/src/main/resources/struts-default.xml Thu Apr 26 18:51:07 2007
@@ -93,6 +93,7 @@
<interceptor name="checkbox" class="org.apache.struts2.interceptor.CheckboxInterceptor" />
<interceptor name="profiling" class="org.apache.struts2.interceptor.ProfilingActivationInterceptor" />
<interceptor name="roles" class="org.apache.struts2.interceptor.RolesInterceptor" />
+ <interceptor name="jsonValidation" class="org.apache.struts2.interceptor.validation.JSONValidationInterceptor" />
<!-- Basic stack -->
<interceptor-stack name="basicStack">
@@ -108,6 +109,15 @@
<interceptor-stack name="validationWorkflowStack">
<interceptor-ref name="basicStack"/>
<interceptor-ref name="validation"/>
+ <interceptor-ref name="workflow"/>
+ </interceptor-stack>
+
+ <!-- Sample JSON validation stack -->
+ <interceptor-stack name="jsonValidationWorkflowStack">
+ <interceptor-ref name="basicStack"/>
+ <interceptor-ref name="jsonValidation">
+ <param name="excludeMethods">input,back,cancel</param>
+ </interceptor-ref>
<interceptor-ref name="workflow"/>
</interceptor-stack>
Modified: struts/struts2/trunk/core/src/main/resources/template/css_xhtml/validation.js
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/resources/template/css_xhtml/validation.js?view=diff&rev=532928&r1=532927&r2=532928
==============================================================================
--- struts/struts2/trunk/core/src/main/resources/template/css_xhtml/validation.js (original)
+++ struts/struts2/trunk/core/src/main/resources/template/css_xhtml/validation.js Thu Apr 26 18:51:07 2007
@@ -1,4 +1,8 @@
function clearErrorMessages(form) {
+ clearErrorMessagesCSS(form);
+}
+
+function clearErrorMessagesCSS(form) {
// clear out any rows with an "errorFor" attribute
var divs = form.getElementsByTagName("div");
var paragraphsToDelete = new Array();
@@ -19,6 +23,10 @@
}
function clearErrorLabels(form) {
+ clearErrorLabelsCSS(form);
+}
+
+function clearErrorLabelsCSS(form) {
// set all labels back to the normal class
var labels = form.getElementsByTagName("label");
for (var i = 0; i < labels.length; i++) {
@@ -34,6 +42,10 @@
}
function addError(e, errorText) {
+ addErrorCSS(e, errorText);
+}
+
+function addErrorCSS(e, errorText) {
try {
var ctrlDiv = e.parentNode; // wwctrl_ div or span
var enclosingDiv = ctrlDiv.parentNode; // wwgrp_ div
Modified: struts/struts2/trunk/core/src/main/resources/template/xhtml/validation.js
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/resources/template/xhtml/validation.js?view=diff&rev=532928&r1=532927&r2=532928
==============================================================================
--- struts/struts2/trunk/core/src/main/resources/template/xhtml/validation.js (original)
+++ struts/struts2/trunk/core/src/main/resources/template/xhtml/validation.js Thu Apr 26 18:51:07 2007
@@ -1,4 +1,8 @@
function clearErrorMessages(form) {
+ clearErrorMessagesXHTML(form);
+}
+
+function clearErrorMessagesXHTML(form) {
var table = form.childNodes[1];
if( typeof table == "undefined" ) {
@@ -28,6 +32,10 @@
}
function clearErrorLabels(form) {
+ clearErrorLabelsXHTML(form);
+}
+
+function clearErrorLabelsXHTML(form) {
// set all labels back to the normal class
var elements = form.elements;
for (var i = 0; i < elements.length; i++) {
@@ -45,6 +53,10 @@
}
function addError(e, errorText) {
+ addErrorXHTML(e, errorText);
+}
+
+function addErrorXHTML(e, errorText) {
try {
// clear out any rows with an "errorFor" of e.id
var row = e.parentNode.parentNode;
Added: struts/struts2/trunk/core/src/test/java/org/apache/struts2/TestUtils.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/test/java/org/apache/struts2/TestUtils.java?view=auto&rev=532928
==============================================================================
--- struts/struts2/trunk/core/src/test/java/org/apache/struts2/TestUtils.java (added)
+++ struts/struts2/trunk/core/src/test/java/org/apache/struts2/TestUtils.java Thu Apr 26 18:51:07 2007
@@ -0,0 +1,96 @@
+/*
+ * $Id: TestResult.java 471756 2006-11-06 15:01:43Z husted $
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.struts2;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.util.StringTokenizer;
+
+/**
+ * Utility methods for test classes
+ *
+ */
+public class TestUtils {
+ /**
+ * normalizes a string so that strings generated on different platforms can be compared. any group of one or more
+ * space, tab, \r, and \n characters are converted to a single space character
+ *
+ * @param obj the object to be normalized. normalize will perform its operation on obj.toString().trim() ;
+ * @param appendSpace
+ * @return the normalized string
+ */
+ public static String normalize(Object obj, boolean appendSpace) {
+ StringTokenizer st =
+ new StringTokenizer(obj.toString().trim(), " \t\r\n");
+ StringBuffer buffer = new StringBuffer(128);
+
+ while(st.hasMoreTokens()) {
+ buffer.append(st.nextToken());
+ }
+
+ return buffer.toString();
+ }
+
+
+ public static String normalize(URL url) throws Exception {
+ return normalize(readContent(url), true);
+ }
+ /**
+ * Attempt to verify the contents of text against the contents of the URL specified. Performs a
+ * trim on both ends
+ *
+ * @param url the HTML snippet that we want to validate against
+ * @throws Exception if the validation failed
+ */
+ public static boolean compare(URL url, String text)
+ throws Exception {
+ /**
+ * compare the trimmed values of each buffer and make sure they're equivalent. however, let's make sure to
+ * normalize the strings first to account for line termination differences between platforms.
+ */
+ String writerString = TestUtils.normalize(text, true);
+ String bufferString = TestUtils.normalize(readContent(url), true);
+
+ return bufferString.equals(writerString);
+ }
+
+
+
+ public static String readContent(URL url)
+ throws Exception {
+ if(url == null) {
+ throw new Exception("unable to verify a null URL");
+ }
+
+ StringBuffer buffer = new StringBuffer(128);
+ InputStream in = url.openStream();
+ byte[] buf = new byte[4096];
+ int nbytes;
+
+ while((nbytes = in.read(buf)) > 0) {
+ buffer.append(new String(buf, 0, nbytes));
+ }
+
+ in.close();
+
+ return buffer.toString();
+ }
+}
Added: struts/struts2/trunk/core/src/test/java/org/apache/struts2/interceptor/validation/JSONValidationInterceptorTest.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/test/java/org/apache/struts2/interceptor/validation/JSONValidationInterceptorTest.java?view=auto&rev=532928
==============================================================================
--- struts/struts2/trunk/core/src/test/java/org/apache/struts2/interceptor/validation/JSONValidationInterceptorTest.java (added)
+++ struts/struts2/trunk/core/src/test/java/org/apache/struts2/interceptor/validation/JSONValidationInterceptorTest.java Thu Apr 26 18:51:07 2007
@@ -0,0 +1,184 @@
+/*
+ * $Id$
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.struts2.interceptor.validation;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.struts2.StrutsStatics;
+import org.apache.struts2.StrutsTestCase;
+import org.apache.struts2.TestUtils;
+import org.apache.struts2.views.jsp.StrutsMockHttpServletRequest;
+import org.apache.struts2.views.jsp.StrutsMockHttpServletResponse;
+import org.apache.struts2.views.jsp.StrutsMockServletContext;
+
+import com.opensymphony.xwork2.Action;
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.ActionSupport;
+import com.opensymphony.xwork2.mock.MockActionInvocation;
+import com.opensymphony.xwork2.mock.MockActionProxy;
+import com.opensymphony.xwork2.util.ValueStack;
+import com.opensymphony.xwork2.util.ValueStackFactory;
+import com.opensymphony.xwork2.validator.annotations.EmailValidator;
+import com.opensymphony.xwork2.validator.annotations.IntRangeFieldValidator;
+import com.opensymphony.xwork2.validator.annotations.StringLengthFieldValidator;
+import com.opensymphony.xwork2.validator.annotations.Validation;
+
+public class JSONValidationInterceptorTest extends StrutsTestCase {
+ private MockActionInvocation invocation;
+ private StringWriter stringWriter;
+ private TestAction action;
+ private StrutsMockHttpServletResponse response;
+ private JSONValidationInterceptor interceptor;
+ private StrutsMockHttpServletRequest request;
+
+ public void testValidationFails() throws Exception {
+
+ action.addActionError("General error");
+ interceptor.setValidationFailedStatus(HttpServletResponse.SC_BAD_REQUEST);
+ interceptor.intercept(invocation);
+
+ String json = stringWriter.toString();
+
+ String normalizedActual = TestUtils.normalize(json, true);
+ String normalizedExpected = TestUtils
+ .normalize(JSONValidationInterceptorTest.class.getResource("json-1.txt"));
+ //json
+ assertEquals(normalizedExpected, normalizedActual);
+ //execution
+ assertFalse(invocation.isExecuted());
+ //http status
+ assertEquals(HttpServletResponse.SC_BAD_REQUEST, response.getStatus());
+ }
+
+ public void testValidationSucceeds() throws Exception {
+ JSONValidationInterceptor interceptor = new JSONValidationInterceptor();
+
+ action.setText("abcd@ggg.com");
+ action.setValue(10);
+
+ interceptor.intercept(invocation);
+
+ String json = stringWriter.toString();
+
+ String normalizedActual = TestUtils.normalize(json, true);
+ assertEquals("", normalizedActual);
+ assertTrue(invocation.isExecuted());
+ }
+
+ public void testValidationSucceedsValidateOnly() throws Exception {
+ JSONValidationInterceptor interceptor = new JSONValidationInterceptor();
+
+ action.setText("abcd@ggg.com");
+ action.setValue(10);
+
+ //just validate
+ Map parameters = new HashMap();
+ parameters.put("validateOnly", "true");
+ request.setParameterMap(parameters);
+
+ interceptor.intercept(invocation);
+
+ String json = stringWriter.toString();
+
+ String normalizedActual = TestUtils.normalize(json, true);
+ assertEquals("", normalizedActual);
+ assertFalse(invocation.isExecuted());
+ }
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ this.action = new TestAction();
+ this.interceptor = new JSONValidationInterceptor();
+
+ this.request = new StrutsMockHttpServletRequest();
+ stringWriter = new StringWriter();
+ PrintWriter writer = new PrintWriter(stringWriter);
+ this.response = new StrutsMockHttpServletResponse();
+ response.setWriter(writer);
+
+ ValueStack stack = ValueStackFactory.getFactory().createValueStack();
+ ActionContext context = new ActionContext(stack.getContext());
+
+ ActionContext.setContext(context);
+ context.put(StrutsStatics.HTTP_REQUEST, request);
+ context.put(StrutsStatics.HTTP_RESPONSE, response);
+
+ StrutsMockServletContext servletContext = new StrutsMockServletContext();
+
+ context.put(StrutsStatics.SERVLET_CONTEXT, servletContext);
+ invocation = new MockActionInvocation() {
+ private boolean executed;
+
+ public String invoke() throws Exception {
+ executed = true;
+ return "success";
+ }
+
+ public boolean isExecuted() {
+ return executed;
+ }
+ };
+ invocation.setAction(action);
+ invocation.setInvocationContext(context);
+ MockActionProxy proxy = new MockActionProxy();
+ proxy.setAction(action);
+ invocation.setProxy(proxy);
+ }
+
+ @Validation
+ public static class TestAction extends ActionSupport {
+ private String text = "x";
+ private int value = -10;
+
+ public String execute() {
+ return Action.SUCCESS;
+ }
+
+ @SkipValidation
+ public String skipMe() {
+ return "skipme";
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ @StringLengthFieldValidator(minLength = "2", message = "Too short")
+ @EmailValidator(message = "This is no email")
+ public void setText(String text) {
+ this.text = text;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ @IntRangeFieldValidator(min = "-1", message = "Min value is -1")
+ public void setValue(int value) {
+ this.value = value;
+ }
+ }
+}