1. opensymphony
  2. xwork

Commits

mrdon  committed 672858c

Changing validation loading exceptions to throw located exceptions, turned off DTD
validation when no dtd mappings, added javadocs, added unit tests

Issue number: XW-383

git-svn-id: http://svn.opensymphony.com/svn/xwork/trunk/src@992e221344d-f017-0410-9bd5-d282ab1896d7

  • Participants
  • Parent commits bcff4c2
  • Branches master

Comments (0)

Files changed (9)

File java/com/opensymphony/xwork/XworkException.java

View file
  • Ignore whitespace
 
 
 /**
- * XworkException
+ * A generic runtime exception that optionally contains Location information 
  *
  * @author Jason Carreira
  *         Created Sep 7, 2003 12:15:03 AM
     
     /**
      * Constructs a <code>XworkException</code> with the specified
-     * detail message and location.
+     * detail message and target.
      *
      * @param s the detail message.
+     * @param target the target of the exception.
      */
     public XworkException(String s, Object target) {
         this(s, (Throwable) null, target);
     }
 
     /**
-     * Constructs a <code>XworkException</code> with no detail  message.
+     * Constructs a <code>XworkException</code> with the root cause
+     *
+     * @param cause The wrapped exception
      */
     public XworkException(Throwable cause) {
         this(null, cause, null);
     }
     
     /**
-     * Constructs a <code>XworkException</code> with no detail  message.
+     * Constructs a <code>XworkException</code> with the root cause and target
+     *
+     * @param cause The wrapped exception
+     * @param target The target of the exception
      */
     public XworkException(Throwable cause, Object target) {
         this(null, cause, target);
 
     /**
      * Constructs a <code>XworkException</code> with the specified
-     * detail message.
+     * detail message and exception cause.
      *
      * @param s the detail message.
+     * @param cause the wrapped exception
      */
     public XworkException(String s, Throwable cause) {
         this(s, cause, null);
     
      /**
      * Constructs a <code>XworkException</code> with the specified
-     * detail message.
+     * detail message, cause, and target
      *
      * @param s the detail message.
+     * @param cause The wrapped exception
+     * @param target The target of the exception
      */
     public XworkException(String s, Throwable cause, Object target) {
         super(s, cause);
     }
 
 
+    /**
+     *  Gets the underlying cause
+     * 
+     * @deprecated Use getCause()
+     */
     public Throwable getThrowable() {
         return getCause();
     }
-    
+
+
+    /**
+     *  Gets the location of the error, if available
+     */
     public Location getLocation() {
         return this.location;
     }
 
     /**
-     * Returns a short description of this throwable object.
-     * If this <code>Throwable</code> object was
-     * {@link #XworkException(String) created} with an error message string,
-     * then the result is the concatenation of three strings:
-     * <ul>
-     * <li>The name of the actual class of this object
-     * <li>": " (a colon and a space)
-     * <li>The result of the {@link #getMessage} method for this object
-     * </ul>
-     * If this <code>Throwable</code> object was {@link #XworkException() created}
-     * with no error message string, then the name of the actual class of
-     * this object is returned.
+     * Returns a short description of this throwable object, including the 
+     * location. If no detailed message is available, it will use the message
+     * of the underlying exception if available.
      *
      * @return a string representation of this <code>Throwable</code>.
      */

File java/com/opensymphony/xwork/util/DomHelper.java

View file
  • Ignore whitespace
 /**
  * Helper class to create and retrieve information from location-enabled
  * DOM-trees.
+ *
+ * @since 1.2
  */
 public class DomHelper {
 
      *
      * @param inputSource the inputSource to read the document from
      */
-    public static Document parse(InputSource inputSource) 
-        throws SAXException, SAXNotSupportedException, IOException {
+    public static Document parse(InputSource inputSource) {
         return parse(inputSource, null);
     }
     
      * using the {@link #getLocation(Element)} method.
      *
      * @param inputSource the inputSource to read the document from
+     * @param dtdMappings a map of DTD names and public ids
      */
-    public static Document parse(InputSource inputSource, Map dtdMappings)
-            throws SAXException, SAXNotSupportedException, IOException {
+    public static Document parse(InputSource inputSource, Map dtdMappings) {
                 
         SAXParserFactory factory = SAXParserFactory.newInstance();
-        factory.setValidating(true);
+        factory.setValidating((dtdMappings != null));
         factory.setNamespaceAware(true);
         
         SAXParser parser = null;
         try {
             parser = factory.newSAXParser();
-        } catch (javax.xml.parsers.ParserConfigurationException ex) {
+        } catch (Exception ex) {
             throw new XworkException("Unable to create SAX parser", ex);
         }
         

File java/com/opensymphony/xwork/validator/ValidatorFactory.java

View file
  • Ignore whitespace
             LOG.debug("Loading validator definitions.");
         }
 
-        InputStream is = ClassLoaderUtil.getResourceAsStream("validators.xml", ValidatorFactory.class);
+        String resourceName = "validators.xml";
+        InputStream is = ClassLoaderUtil.getResourceAsStream(resourceName, ValidatorFactory.class);
         if (is == null) {
-            is = ClassLoaderUtil.getResourceAsStream("com/opensymphony/xwork/validator/validators/default.xml",
-                    ValidatorFactory.class);
+            resourceName = "com/opensymphony/xwork/validator/validators/default.xml";
+            is = ClassLoaderUtil.getResourceAsStream(resourceName, ValidatorFactory.class);
         }
 
         if (is != null) {
-            ValidatorFileParser.parseValidatorDefinitions(is);
+            ValidatorFileParser.parseValidatorDefinitions(is, resourceName);
         }
     }
 }

File java/com/opensymphony/xwork/validator/ValidatorFileParser.java

View file
  • Ignore whitespace
 
 import com.opensymphony.xwork.ObjectFactory;
 import com.opensymphony.xwork.util.DomHelper;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+import com.opensymphony.xwork.XworkException;
 import org.w3c.dom.*;
 import org.xml.sax.EntityResolver;
 import org.xml.sax.ErrorHandler;
  */
 public class ValidatorFileParser {
 
-    private static final Log log = LogFactory.getLog(ValidatorFileParser.class);
-
     static final String MULTI_TEXTVALUE_SEPARATOR = " ";
 
     /**
         List validatorCfgs = new ArrayList();
         Document doc = null;
 
-        try {
-            InputSource in = new InputSource(is);
-            in.setSystemId(resourceName);
-                
-            Map dtdMappings = new HashMap();
-            dtdMappings.put("-//OpenSymphony Group//XWork Validator 1.0//EN", "xwork-validator-1.0.dtd");
-            dtdMappings.put("-//OpenSymphony Group//XWork Validator 1.0.2//EN", "xwork-validator-1.0.2.dtd");
+        InputSource in = new InputSource(is);
+        in.setSystemId(resourceName);
             
-            doc = DomHelper.parse(in, dtdMappings);
-        } catch (Exception e) {
-            log.fatal("Caught exception while attempting to load validation configuration file '" + resourceName + "'.", e);
-        }
+        Map dtdMappings = new HashMap();
+        dtdMappings.put("-//OpenSymphony Group//XWork Validator 1.0//EN", "xwork-validator-1.0.dtd");
+        dtdMappings.put("-//OpenSymphony Group//XWork Validator 1.0.2//EN", "xwork-validator-1.0.2.dtd");
+        
+        doc = DomHelper.parse(in, dtdMappings);
 
         if (doc != null) {
             NodeList fieldNodes = doc.getElementsByTagName("field");
         return validatorCfgs;
     }
 
+    
+    /**
+     *  Parses validator definitions
+     *
+     * @deprecated Use parseValidatorDefinitions(InputStream, String)
+     * @param is The input stream
+     */
     public static void parseValidatorDefinitions(InputStream is) {
-        try {
-            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
-            DocumentBuilder builder = dbf.newDocumentBuilder();
-            Document doc = builder.parse(is);
-            NodeList nodes = doc.getElementsByTagName("validator");
-
-            for (int i = 0; i < nodes.getLength(); i++) {
-                Element validatorElement = (Element) nodes.item(i);
-                String name = validatorElement.getAttribute("name");
-                String className = validatorElement.getAttribute("class");
-
-                try {
-                    // catch any problems here
-                    ObjectFactory.getObjectFactory().buildValidator(className, new HashMap(), null);
-                    ValidatorFactory.registerValidator(name, className);
-                } catch (Exception e) {
-                    log.error("Unable to load validator class " + className);
-                }
+        parseValidatorDefinitions(is, null);
+    }
+    
+    
+    /**
+     *  Parses validator definitions
+     *
+     * @since 1.2
+     * @param is The input stream
+     * @param resourceName The location of the input stream
+     */
+    public static void parseValidatorDefinitions(InputStream is, String resourceName) {
+        
+        InputSource in = new InputSource(is);
+        in.setSystemId(resourceName);
+            
+        Document doc = DomHelper.parse(in);
+        
+        NodeList nodes = doc.getElementsByTagName("validator");
+
+        for (int i = 0; i < nodes.getLength(); i++) {
+            Element validatorElement = (Element) nodes.item(i);
+            String name = validatorElement.getAttribute("name");
+            String className = validatorElement.getAttribute("class");
+
+            try {
+                // catch any problems here
+                ObjectFactory.getObjectFactory().buildValidator(className, new HashMap(), null);
+                ValidatorFactory.registerValidator(name, className);
+            } catch (Exception e) {
+                throw new XworkException("Unable to load validator class " + className, e, validatorElement);
             }
-        } catch (Exception e) {
-            log.error("Caught exception while parsing validator definitions.");
         }
     }
 

File test/com/opensymphony/xwork/validator/ValidatorFileParserTest.java

View file
  • Ignore whitespace
 import com.opensymphony.xwork.config.ConfigurationManager;
 import com.opensymphony.xwork.config.providers.MockConfigurationProvider;
 import junit.framework.TestCase;
+import com.opensymphony.xwork.XworkException;
 
 import java.io.InputStream;
 import java.util.List;
 
     private static final String testFileName = "com/opensymphony/xwork/validator/validator-parser-test.xml";
     private static final String testFileName2 = "com/opensymphony/xwork/validator/validator-parser-test2.xml";
+    private static final String testFileName3 = "com/opensymphony/xwork/validator/validator-parser-test3.xml";
+    private static final String testFileName4 = "com/opensymphony/xwork/validator/validator-parser-test4.xml";
+    private static final String testFileName5 = "com/opensymphony/xwork/validator/validator-parser-test5.xml";
 
     public void testParserActionLevelValidatorsShouldBeBeforeFieldLevelValidators() throws Exception {
     	InputStream is = ClassLoaderUtil.getResourceAsStream(testFileName2, this.getClass());
         assertEquals("([aAbBcCdD][123][eEfFgG][456])", cfg.getParams().get("expression"));
     }
 
+    public void testParserWithBadValidation() {
+        InputStream is = ClassLoaderUtil.getResourceAsStream(testFileName3, this.getClass());
+
+        boolean pass = false;
+        try {
+            ValidatorFileParser.parseActionValidatorConfigs(is, testFileName3);
+        } catch (XworkException ex) {
+            assertTrue("Wrong line number", 3==ex.getLocation().getLineNumber());
+            pass = true;
+        } 
+        assertTrue("Validation file should have thrown exception", pass);
+    }
+
+    public void testParserWithBadXML() {
+        InputStream is = ClassLoaderUtil.getResourceAsStream(testFileName4, this.getClass());
+
+        boolean pass = false;
+        try {
+            ValidatorFileParser.parseActionValidatorConfigs(is, testFileName4);
+        } catch (XworkException ex) {
+            assertTrue("Wrong line number: "+ex.getLocation(), 13==ex.getLocation().getLineNumber());
+            pass = true;
+        } 
+        assertTrue("Validation file should have thrown exception", pass);
+    }
+
+    public void testValidatorDefinitionsWithBadClassName() {
+        InputStream is = ClassLoaderUtil.getResourceAsStream(testFileName5, this.getClass());
+
+        boolean pass = false;
+        try {
+            ValidatorFileParser.parseValidatorDefinitions(is, testFileName5);
+        } catch (XworkException ex) {
+            assertTrue("Wrong line number", 3==ex.getLocation().getLineNumber());
+            pass = true;
+        } 
+        assertTrue("Validation file should have thrown exception", pass);
+    }
+
+
+
     protected void setUp() throws Exception {
         super.setUp();
         ConfigurationManager.clearConfigurationProviders();

File test/com/opensymphony/xwork/validator/validator-parser-test3.xml

View file
  • Ignore whitespace
+<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN" "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
+<validators>
+    <validator type="expression" bar="die">
+        <param name="expression">email.equals(email2)</param>
+        <message>Email not the same as email2</message>
+    </validator>
+    <validator type="expression" short-circuit="true">
+        <param name="expression">email.startsWith('mark')</param>
+        <message>Email does not start with mark</message>
+    </validator>
+</validators>

File test/com/opensymphony/xwork/validator/validator-parser-test4.xml

View file
  • Ignore whitespace
+<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN" "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
+
+<validators>
+    <validator type="expression">
+        <param name="expression">email.equals(email2)</param>
+        <message>Email not the same as email2</message>
+    </validator>
+    <validator type="expression" short-circuit="true">
+        <param name="expression">email.startsWith('mark')</param>
+        <message>Email does not start with mark</message>
+    </validator>
+/validators>

File test/com/opensymphony/xwork/validator/validator-parser-test5.xml

View file
  • Ignore whitespace
+<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN" "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
+<validators>
+    <validator name="foo" class="bar" />
+</validators>

File test/validators.xml

View file
  • Ignore whitespace
+<!DOCTYPE validators PUBLIC 
+  		"-//OpenSymphony Group//XWork Validator 1.0.2//EN" 
+  		"http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
 <validators>
     <validator name="required" class="com.opensymphony.xwork.validator.validators.RequiredFieldValidator"/>
     <validator name="requiredstring" class="com.opensymphony.xwork.validator.validators.RequiredStringValidator"/>