Author: musachy Date: Mon Mar 30 00:15:50 2009 New Revision: 759802 URL: http://svn.apache.org/viewvc?rev=759802&view=rev Log: Add XML support
Added: struts/sandbox/trunk/struts2-oval-plugin/src/main/java/org/apache/struts2/interceptor/DefaultOValValidationManager.java struts/sandbox/trunk/struts2-oval-plugin/src/main/java/org/apache/struts2/interceptor/OValValidationManager.java struts/sandbox/trunk/struts2-oval-plugin/src/test/java/org/apache/struts2/interceptor/SimpleFieldsXml.java struts/sandbox/trunk/struts2-oval-plugin/src/test/resources/org/apache/struts2/interceptor/SimpleFieldsXml-validation.xml Modified: struts/sandbox/trunk/struts2-oval-plugin/pom.xml struts/sandbox/trunk/struts2-oval-plugin/src/main/java/org/apache/struts2/interceptor/OValValidationInterceptor.java struts/sandbox/trunk/struts2-oval-plugin/src/main/resources/struts-plugin.xml struts/sandbox/trunk/struts2-oval-plugin/src/test/java/org/apache/struts2/interceptor/OValValidationInterceptorTest.java struts/sandbox/trunk/struts2-oval-plugin/src/test/resources/oval-test.xml Modified: struts/sandbox/trunk/struts2-oval-plugin/pom.xml URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-oval-plugin/pom.xml?rev=759802&r1=759801&r2=759802&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-oval-plugin/pom.xml (original) +++ struts/sandbox/trunk/struts2-oval-plugin/pom.xml Mon Mar 30 00:15:50 2009 @@ -50,8 +50,14 @@ <version>1.31</version> </dependency> + <dependency> + <groupId>com.thoughtworks.xstream</groupId> + <artifactId>xstream</artifactId> + <version>1.3.1</version> + </dependency> + <!-- Testing --> - <dependency> + <dependency> <groupId>org.easymock</groupId> <artifactId>easymock</artifactId> <version>2.0</version> Added: struts/sandbox/trunk/struts2-oval-plugin/src/main/java/org/apache/struts2/interceptor/DefaultOValValidationManager.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-oval-plugin/src/main/java/org/apache/struts2/interceptor/DefaultOValValidationManager.java?rev=759802&view=auto ============================================================================== --- struts/sandbox/trunk/struts2-oval-plugin/src/main/java/org/apache/struts2/interceptor/DefaultOValValidationManager.java (added) +++ struts/sandbox/trunk/struts2-oval-plugin/src/main/java/org/apache/struts2/interceptor/DefaultOValValidationManager.java Mon Mar 30 00:15:50 2009 @@ -0,0 +1,139 @@ +package org.apache.struts2.interceptor; + +import com.opensymphony.xwork2.ActionContext; +import com.opensymphony.xwork2.util.FileManager; +import com.opensymphony.xwork2.util.logging.Logger; +import com.opensymphony.xwork2.util.logging.LoggerFactory; +import net.sf.oval.configuration.xml.XMLConfigurer; +import net.sf.oval.configuration.Configurer; + +import java.util.List; +import java.util.Map; +import java.util.ArrayList; +import java.util.Set; +import java.util.TreeSet; +import java.util.HashMap; + + +public class DefaultOValValidationManager implements OValValidationManager { + private static final Logger LOG = LoggerFactory.getLogger(DefaultOValValidationManager.class); + + private static final String VALIDATION_CONFIG_SUFFIX = "-validation.xml"; + private final Map<String, List<Configurer>> validatorCache = new HashMap<String, List<Configurer>>(); + private final Map<String, Configurer> validatorFileCache = new HashMap<String, Configurer>(); + + public synchronized List<Configurer> getConfigurers(Class clazz, String context) { + final String validatorKey = buildValidatorKey(clazz, context); + + if (validatorCache.containsKey(validatorKey)) { + if (FileManager.isReloadingConfigs()) { + validatorCache.put(validatorKey, buildXMLConfigurers(clazz, context, true, null)); + } + } else { + validatorCache.put(validatorKey, buildXMLConfigurers(clazz, context, false, null)); + } + + // get the set of validator configs + return validatorCache.get(validatorKey); + } + + protected static String buildValidatorKey(Class clazz, String context) { + StringBuilder sb = new StringBuilder(clazz.getName()); + sb.append("/"); + sb.append(context); + return sb.toString(); + } + + private List<Configurer> buildXMLConfigurers(Class clazz, String context, boolean checkFile, Set<String> checked) { + List<Configurer> xmlConfigurers = new ArrayList<Configurer>(); + + if (checked == null) { + checked = new TreeSet<String>(); + } else if (checked.contains(clazz.getName())) { + return xmlConfigurers; + } + + if (clazz.isInterface()) { + for (Class anInterface : clazz.getInterfaces()) { + xmlConfigurers.addAll(buildXMLConfigurers(anInterface, context, checkFile, checked)); + } + } else { + if (!clazz.equals(Object.class)) { + xmlConfigurers.addAll(buildXMLConfigurers(clazz.getSuperclass(), context, checkFile, checked)); + } + } + + // look for validators for implemented interfaces + for (Class anInterface1 : clazz.getInterfaces()) { + if (checked.contains(anInterface1.getName())) { + continue; + } + + addIfNotNull(xmlConfigurers, buildClassValidatorConfigs(anInterface1, checkFile)); + + if (context != null) { + addIfNotNull(xmlConfigurers, buildAliasValidatorConfigs(anInterface1, context, checkFile)); + } + + checked.add(anInterface1.getName()); + } + + addIfNotNull(xmlConfigurers, buildClassValidatorConfigs(clazz, checkFile)); + + if (context != null) { + addIfNotNull(xmlConfigurers, buildAliasValidatorConfigs(clazz, context, checkFile)); + } + + checked.add(clazz.getName()); + + return xmlConfigurers; + } + + protected void addIfNotNull(List<Configurer> configurers, Configurer configurer) { + if (configurer != null) + configurers.add(configurer); + } + + + protected XMLConfigurer buildAliasValidatorConfigs(Class aClass, String context, boolean checkFile) { + String fileName = aClass.getName().replace('.', '/') + "-" + context + VALIDATION_CONFIG_SUFFIX; + + return loadFile(fileName, aClass, checkFile); + } + + protected XMLConfigurer buildClassValidatorConfigs(Class aClass, boolean checkFile) { + String fileName = aClass.getName().replace('.', '/') + VALIDATION_CONFIG_SUFFIX; + + return loadFile(fileName, aClass, checkFile); + } + + protected XMLConfigurer loadFile(String fileName, Class clazz, boolean checkFile) { + if ((checkFile && FileManager.fileNeedsReloading(fileName, clazz)) || !validatorFileCache.containsKey(fileName)) { + java.io.InputStream is = null; + + try { + is = FileManager.loadFile(fileName, clazz); + + if (is != null) { + if (LOG.isDebugEnabled()) + LOG.debug("Loading validation xml file [#0]", fileName); + XMLConfigurer configurer = new XMLConfigurer(); + configurer.fromXML(is); + validatorFileCache.put(fileName, configurer); + } + } finally { + if (is != null) { + try { + is.close(); + } catch (java.io.IOException e) { + LOG.error("Unable to close input stream for [#0] ", e, fileName); + } + } + } + } else { + return (XMLConfigurer) validatorFileCache.get(fileName); + } + + return null; + } +} \ No newline at end of file Modified: struts/sandbox/trunk/struts2-oval-plugin/src/main/java/org/apache/struts2/interceptor/OValValidationInterceptor.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-oval-plugin/src/main/java/org/apache/struts2/interceptor/OValValidationInterceptor.java?rev=759802&r1=759801&r2=759802&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-oval-plugin/src/main/java/org/apache/struts2/interceptor/OValValidationInterceptor.java (original) +++ struts/sandbox/trunk/struts2-oval-plugin/src/main/java/org/apache/struts2/interceptor/OValValidationInterceptor.java Mon Mar 30 00:15:50 2009 @@ -31,9 +31,10 @@ import com.opensymphony.xwork2.util.logging.Logger; import com.opensymphony.xwork2.util.logging.LoggerFactory; import com.opensymphony.xwork2.util.ValueStack; -import com.opensymphony.xwork2.util.reflection.ReflectionProvider; import net.sf.oval.Validator; import net.sf.oval.ConstraintViolation; +import net.sf.oval.configuration.xml.XMLConfigurer; +import net.sf.oval.configuration.Configurer; import net.sf.oval.context.FieldContext; import net.sf.oval.context.OValContext; import net.sf.oval.context.MethodReturnValueContext; @@ -50,11 +51,17 @@ public class OValValidationInterceptor extends MethodFilterInterceptor { private static final Logger LOG = LoggerFactory.getLogger(OValValidationInterceptor.class); - private final static String VALIDATE_PREFIX = "validate"; - private final static String ALT_VALIDATE_PREFIX = "validateDo"; + protected final static String VALIDATE_PREFIX = "validate"; + protected final static String ALT_VALIDATE_PREFIX = "validateDo"; - private boolean alwaysInvokeValidate = true; - private boolean programmatic = true; + protected boolean alwaysInvokeValidate = true; + protected boolean programmatic = true; + protected OValValidationManager validationManager; + + @Inject + public void setValidationManager(OValValidationManager validationManager) { + this.validationManager = validationManager; + } /** * Determines if {...@link com.opensymphony.xwork2.Validateable}'s <code>validate()</code> should be called, @@ -81,13 +88,14 @@ ActionProxy proxy = invocation.getProxy(); ValueStack valueStack = invocation.getStack(); String methodName = proxy.getMethod(); + String context = proxy.getActionName(); if (LOG.isDebugEnabled()) { LOG.debug("Validating [#0/#1] with method [#2]", invocation.getProxy().getNamespace(), invocation.getProxy().getActionName(), methodName); } //OVal vallidatio (no XML yet) - performOValValidation(action, valueStack, methodName); + performOValValidation(action, valueStack, methodName, context); //Validatable.valiedate() and validateX() performProgrammaticValidation(invocation, action); @@ -109,15 +117,13 @@ PrefixMethodInvocationUtil.invokePrefixMethod( invocation, new String[]{VALIDATE_PREFIX, ALT_VALIDATE_PREFIX}); - } - catch (Exception e) { + } catch (Exception e) { // If any exception occurred while doing reflection, we want // validate() to be executed LOG.warn("An exception occured while executing the prefix method", e); exception = e; } - if (alwaysInvokeValidate) { validateable.validate(); } @@ -129,10 +135,14 @@ } } - protected void performOValValidation(Object action, ValueStack valueStack, String methodName) throws NoSuchMethodException { - Validator validator = new Validator(); + protected void performOValValidation(Object action, ValueStack valueStack, String methodName, String context) throws NoSuchMethodException { + Class clazz = action.getClass(); + //read validation from xmls + List<Configurer> configurers = validationManager.getConfigurers(clazz, context); + + Validator validator = configurers.isEmpty() ? new Validator() : new Validator(configurers); //if the method is annotated with a @Profiles annotation, use those profiles - Method method = action.getClass().getMethod(methodName, new Class[0]); + Method method = clazz.getMethod(methodName, new Class[0]); if (method != null) { Profiles profiles = method.getAnnotation(Profiles.class); if (profiles != null) { @@ -167,7 +177,7 @@ if (isActionError(violation)) validatorContext.addActionError(message); else { - String className = action.getClass().getName(); + String className = clazz.getName(); //the default OVal message shows the field name as ActionClass.fieldName message = StringUtils.removeStart(message, className + "."); validatorContext.addFieldError(extractFieldName(violation), message); @@ -176,6 +186,7 @@ } } + /** * Get field name, used to add the validation error to fieldErrors */ Added: struts/sandbox/trunk/struts2-oval-plugin/src/main/java/org/apache/struts2/interceptor/OValValidationManager.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-oval-plugin/src/main/java/org/apache/struts2/interceptor/OValValidationManager.java?rev=759802&view=auto ============================================================================== --- struts/sandbox/trunk/struts2-oval-plugin/src/main/java/org/apache/struts2/interceptor/OValValidationManager.java (added) +++ struts/sandbox/trunk/struts2-oval-plugin/src/main/java/org/apache/struts2/interceptor/OValValidationManager.java Mon Mar 30 00:15:50 2009 @@ -0,0 +1,51 @@ +package org.apache.struts2.interceptor; + +import net.sf.oval.configuration.xml.XMLConfigurer; +import net.sf.oval.configuration.Configurer; + +import java.util.List; + + +public interface OValValidationManager { + /** + * <p>This method 'collects' all the validator configurations for a given + * action invocation.</p> + * <p/> + * <p>It will traverse up the class hierarchy looking for validators for every super class + * and directly implemented interface of the current action, as well as adding validators for + * any alias of this invocation. Nifty!</p> + * <p/> + * <p>Given the following class structure: + * <pre> + * interface Thing; + * interface Animal extends Thing; + * interface Quadraped extends Animal; + * class AnimalImpl implements Animal; + * class QuadrapedImpl extends AnimalImpl implements Quadraped; + * class Dog extends QuadrapedImpl; + * </pre></p> + * <p/> + * <p>This method will look for the following config files for Dog: + * <pre> + * Animal + * Animal-context + * AnimalImpl + * AnimalImpl-context + * Quadraped + * Quadraped-context + * QuadrapedImpl + * QuadrapedImpl-context + * Dog + * Dog-context + * </pre></p> + * <p/> + * <p>Note that the validation rules for Thing is never looked for because no class in the + * hierarchy directly implements Thing.</p> + * + * @param clazz the Class to look up validators for. + * @param context the context to use when looking up validators. + * updated. + * @return a list of xml configurers for the given class and context. + */ + List<Configurer> getConfigurers(Class clazz, String context); +} Modified: struts/sandbox/trunk/struts2-oval-plugin/src/main/resources/struts-plugin.xml URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-oval-plugin/src/main/resources/struts-plugin.xml?rev=759802&r1=759801&r2=759802&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-oval-plugin/src/main/resources/struts-plugin.xml (original) +++ struts/sandbox/trunk/struts2-oval-plugin/src/main/resources/struts-plugin.xml Mon Mar 30 00:15:50 2009 @@ -26,6 +26,8 @@ "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> + <bean type="org.apache.struts2.interceptor.OValValidationManager" class="org.apache.struts2.interceptor.DefaultOValValidationManager" /> + <package name="oval-default" extends="struts-default"> <interceptors> <interceptor name="ovalValidation" class="org.apache.struts2.interceptor.OValValidationInterceptor" /> Modified: struts/sandbox/trunk/struts2-oval-plugin/src/test/java/org/apache/struts2/interceptor/OValValidationInterceptorTest.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-oval-plugin/src/test/java/org/apache/struts2/interceptor/OValValidationInterceptorTest.java?rev=759802&r1=759801&r2=759802&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-oval-plugin/src/test/java/org/apache/struts2/interceptor/OValValidationInterceptorTest.java (original) +++ struts/sandbox/trunk/struts2-oval-plugin/src/test/java/org/apache/struts2/interceptor/OValValidationInterceptorTest.java Mon Mar 30 00:15:50 2009 @@ -30,6 +30,17 @@ import java.util.Map; public class OValValidationInterceptorTest extends XWorkTestCase { + public void testSimpleFieldsXML() throws Exception { + ActionProxy baseActionProxy = actionProxyFactory.createActionProxy("oval", "simpleFieldsXML", null, null); + baseActionProxy.execute(); + + Map<String, List<String>> fieldErrors = ((ValidationAware) baseActionProxy.getAction()).getFieldErrors(); + assertNotNull(fieldErrors); + assertEquals(2, fieldErrors.size()); + assertValue(fieldErrors, "firstName", Arrays.asList("firstName cannot be null")); + assertValue(fieldErrors, "lastName", Arrays.asList("lastName cannot be empty")); + } + public void testSimpleField() throws Exception { ActionProxy baseActionProxy = actionProxyFactory.createActionProxy("oval", "simpleField", null, null); baseActionProxy.execute(); Added: struts/sandbox/trunk/struts2-oval-plugin/src/test/java/org/apache/struts2/interceptor/SimpleFieldsXml.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-oval-plugin/src/test/java/org/apache/struts2/interceptor/SimpleFieldsXml.java?rev=759802&view=auto ============================================================================== --- struts/sandbox/trunk/struts2-oval-plugin/src/test/java/org/apache/struts2/interceptor/SimpleFieldsXml.java (added) +++ struts/sandbox/trunk/struts2-oval-plugin/src/test/java/org/apache/struts2/interceptor/SimpleFieldsXml.java Mon Mar 30 00:15:50 2009 @@ -0,0 +1,29 @@ +package org.apache.struts2.interceptor; + +import com.opensymphony.xwork2.ActionSupport; +import net.sf.oval.constraint.NotEmpty; +import net.sf.oval.constraint.NotNull; + +public class SimpleFieldsXml extends ActionSupport { + @NotNull + private String firstName; + + @NotEmpty + private String lastName = ""; + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } +} Added: struts/sandbox/trunk/struts2-oval-plugin/src/test/resources/org/apache/struts2/interceptor/SimpleFieldsXml-validation.xml URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-oval-plugin/src/test/resources/org/apache/struts2/interceptor/SimpleFieldsXml-validation.xml?rev=759802&view=auto ============================================================================== --- struts/sandbox/trunk/struts2-oval-plugin/src/test/resources/org/apache/struts2/interceptor/SimpleFieldsXml-validation.xml (added) +++ struts/sandbox/trunk/struts2-oval-plugin/src/test/resources/org/apache/struts2/interceptor/SimpleFieldsXml-validation.xml Mon Mar 30 00:15:50 2009 @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +<!DOCTYPE oval PUBLIC + "-//OVal/OVal Configuration DTD 1.3//EN" + "http://oval.sourceforge.net/oval-configuration-1.3.dtd"> +--> +<oval xmlns="http://oval.sf.net/oval-configuration" xmlns:xsi="http://http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://oval.sf.net/oval-configuration http://oval.sourceforge.net/oval-configuration-1.3.xsd" +> + <!-- define a constraint set --> + <constraintSet id="firstName"> + <notNull message="{context} is null" /> + </constraintSet> +</oval> \ No newline at end of file Modified: struts/sandbox/trunk/struts2-oval-plugin/src/test/resources/oval-test.xml URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-oval-plugin/src/test/resources/oval-test.xml?rev=759802&r1=759801&r2=759802&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-oval-plugin/src/test/resources/oval-test.xml (original) +++ struts/sandbox/trunk/struts2-oval-plugin/src/test/resources/oval-test.xml Mon Mar 30 00:15:50 2009 @@ -4,6 +4,7 @@ > <xwork> + <bean type="org.apache.struts2.interceptor.OValValidationManager" class="org.apache.struts2.interceptor.DefaultOValValidationManager" /> <package namespace="oval" name="oval-test"> <result-types> <result-type name="void" class="org.apache.struts2.interceptor.VoidResult"/> @@ -12,6 +13,10 @@ <interceptor name="ovalValidation" class="org.apache.struts2.interceptor.OValValidationInterceptor"/> </interceptors> + <action name="simpleFieldsXML" class="org.apache.struts2.interceptor.SimpleFieldsXml"> + <interceptor-ref name="ovalValidation"/> + <result type="void"></result> + </action> <action name="simpleField" class="org.apache.struts2.interceptor.SimpleField"> <interceptor-ref name="ovalValidation"/> <result type="void"></result>