Coverage Report - org.apache.commons.validator.ValidatorAction
 
Classes in this File Line Coverage Branch Coverage Complexity
ValidatorAction
62%
134/213
55%
43/78
2.838
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  * contributor license agreements.  See the NOTICE file distributed with
 4  
  * this work for additional information regarding copyright ownership.
 5  
  * The ASF licenses this file to You under the Apache License, Version 2.0
 6  
  * (the "License"); you may not use this file except in compliance with
 7  
  * the License.  You may obtain a copy of the License at
 8  
  *
 9  
  *      http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 package org.apache.commons.validator;
 18  
 
 19  
 import java.io.BufferedReader;
 20  
 import java.io.IOException;
 21  
 import java.io.InputStream;
 22  
 import java.io.InputStreamReader;
 23  
 import java.io.Serializable;
 24  
 import java.lang.reflect.InvocationTargetException;
 25  
 import java.lang.reflect.Method;
 26  
 import java.lang.reflect.Modifier;
 27  
 import java.util.ArrayList;
 28  
 import java.util.Collections;
 29  
 import java.util.List;
 30  
 import java.util.Map;
 31  
 import java.util.StringTokenizer;
 32  
 
 33  
 import org.apache.commons.logging.Log;
 34  
 import org.apache.commons.logging.LogFactory;
 35  
 import org.apache.commons.validator.util.ValidatorUtils;
 36  
 
 37  
 /**
 38  
  * Contains the information to dynamically create and run a validation
 39  
  * method.  This is the class representation of a pluggable validator that can
 40  
  * be defined in an xml file with the <validator> element.
 41  
  *
 42  
  * <strong>Note</strong>: The validation method is assumed to be thread safe.
 43  
  *
 44  
  * @version $Revision: 1739361 $
 45  
  */
 46  384
 public class ValidatorAction implements Serializable {
 47  
 
 48  
     private static final long serialVersionUID = 1339713700053204597L;
 49  
 
 50  
     /**
 51  
      * Logger.
 52  
      */
 53  384
     private transient Log log = LogFactory.getLog(ValidatorAction.class);
 54  
 
 55  
     /**
 56  
      * The name of the validation.
 57  
      */
 58  384
     private String name = null;
 59  
 
 60  
     /**
 61  
      * The full class name of the class containing
 62  
      * the validation method associated with this action.
 63  
      */
 64  384
     private String classname = null;
 65  
 
 66  
     /**
 67  
      * The Class object loaded from the classname.
 68  
      */
 69  384
     private Class<?> validationClass = null;
 70  
 
 71  
     /**
 72  
      * The full method name of the validation to be performed.  The method
 73  
      * must be thread safe.
 74  
      */
 75  384
     private String method = null;
 76  
 
 77  
     /**
 78  
      * The Method object loaded from the method name.
 79  
      */
 80  384
     private Method validationMethod = null;
 81  
 
 82  
     /**
 83  
      * <p>
 84  
      * The method signature of the validation method.  This should be a comma
 85  
      * delimited list of the full class names of each parameter in the correct
 86  
      * order that the method takes.
 87  
      * </p>
 88  
      * <p>
 89  
      * Note: <code>java.lang.Object</code> is reserved for the
 90  
      * JavaBean that is being validated.  The <code>ValidatorAction</code>
 91  
      * and <code>Field</code> that are associated with a field's
 92  
      * validation will automatically be populated if they are
 93  
      * specified in the method signature.
 94  
      * </p>
 95  
      */
 96  384
     private String methodParams =
 97  
             Validator.BEAN_PARAM
 98  
             + ","
 99  
             + Validator.VALIDATOR_ACTION_PARAM
 100  
             + ","
 101  
             + Validator.FIELD_PARAM;
 102  
 
 103  
     /**
 104  
      * The Class objects for each entry in methodParameterList.
 105  
      */
 106  384
     private Class<?>[] parameterClasses = null;
 107  
 
 108  
     /**
 109  
      * The other <code>ValidatorAction</code>s that this one depends on.  If
 110  
      * any errors occur in an action that this one depends on, this action will
 111  
      * not be processsed.
 112  
      */
 113  384
     private String depends = null;
 114  
 
 115  
     /**
 116  
      * The default error message associated with this action.
 117  
      */
 118  384
     private String msg = null;
 119  
 
 120  
     /**
 121  
      * An optional field to contain the name to be used if JavaScript is
 122  
      * generated.
 123  
      */
 124  384
     private String jsFunctionName = null;
 125  
 
 126  
     /**
 127  
      * An optional field to contain the class path to be used to retrieve the
 128  
      * JavaScript function.
 129  
      */
 130  384
     private String jsFunction = null;
 131  
 
 132  
     /**
 133  
      * An optional field to containing a JavaScript representation of the
 134  
      * java method assocated with this action.
 135  
      */
 136  384
     private String javascript = null;
 137  
 
 138  
     /**
 139  
      * If the java method matching the correct signature isn't static, the
 140  
      * instance is stored in the action.  This assumes the method is thread
 141  
      * safe.
 142  
      */
 143  384
     private Object instance = null;
 144  
 
 145  
     /**
 146  
      * An internal List representation of the other <code>ValidatorAction</code>s
 147  
      * this one depends on (if any).  This List gets updated
 148  
      * whenever setDepends() gets called.  This is synchronized so a call to
 149  
      * setDepends() (which clears the List) won't interfere with a call to
 150  
      * isDependency().
 151  
      */
 152  384
     private final List<String> dependencyList = Collections.synchronizedList(new ArrayList<String>());
 153  
 
 154  
     /**
 155  
      * An internal List representation of all the validation method's
 156  
      * parameters defined in the methodParams String.
 157  
      */
 158  384
     private final List<String> methodParameterList = new ArrayList<String>();
 159  
 
 160  
     /**
 161  
      * Gets the name of the validator action.
 162  
      * @return Validator Action name.
 163  
      */
 164  
     public String getName() {
 165  398
         return name;
 166  
     }
 167  
 
 168  
     /**
 169  
      * Sets the name of the validator action.
 170  
      * @param name Validator Action name.
 171  
      */
 172  
     public void setName(String name) {
 173  384
         this.name = name;
 174  384
     }
 175  
 
 176  
     /**
 177  
      * Gets the class of the validator action.
 178  
      * @return Class name of the validator Action.
 179  
      */
 180  
     public String getClassname() {
 181  0
         return classname;
 182  
     }
 183  
 
 184  
     /**
 185  
      * Sets the class of the validator action.
 186  
      * @param classname Class name of the validator Action.
 187  
      */
 188  
     public void setClassname(String classname) {
 189  384
         this.classname = classname;
 190  384
     }
 191  
 
 192  
     /**
 193  
      * Gets the name of method being called for the validator action.
 194  
      * @return The method name.
 195  
      */
 196  
     public String getMethod() {
 197  0
         return method;
 198  
     }
 199  
 
 200  
     /**
 201  
      * Sets the name of method being called for the validator action.
 202  
      * @param method The method name.
 203  
      */
 204  
     public void setMethod(String method) {
 205  384
         this.method = method;
 206  384
     }
 207  
 
 208  
     /**
 209  
      * Gets the method parameters for the method.
 210  
      * @return Method's parameters.
 211  
      */
 212  
     public String getMethodParams() {
 213  0
         return methodParams;
 214  
     }
 215  
 
 216  
     /**
 217  
      * Sets the method parameters for the method.
 218  
      * @param methodParams A comma separated list of parameters.
 219  
      */
 220  
     public void setMethodParams(String methodParams) {
 221  384
         this.methodParams = methodParams;
 222  
 
 223  384
         this.methodParameterList.clear();
 224  
 
 225  384
         StringTokenizer st = new StringTokenizer(methodParams, ",");
 226  1186
         while (st.hasMoreTokens()) {
 227  802
             String value = st.nextToken().trim();
 228  
 
 229  802
             if (value != null && value.length() > 0) {
 230  802
                 this.methodParameterList.add(value);
 231  
             }
 232  802
         }
 233  384
     }
 234  
 
 235  
     /**
 236  
      * Gets the dependencies of the validator action as a comma separated list
 237  
      * of validator names.
 238  
      * @return The validator action's dependencies.
 239  
      */
 240  
     public String getDepends() {
 241  0
         return this.depends;
 242  
     }
 243  
 
 244  
     /**
 245  
      * Sets the dependencies of the validator action.
 246  
      * @param depends A comma separated list of validator names.
 247  
      */
 248  
     public void setDepends(String depends) {
 249  10
         this.depends = depends;
 250  
 
 251  10
         this.dependencyList.clear();
 252  
 
 253  10
         StringTokenizer st = new StringTokenizer(depends, ",");
 254  28
         while (st.hasMoreTokens()) {
 255  18
             String depend = st.nextToken().trim();
 256  
 
 257  18
             if (depend != null && depend.length() > 0) {
 258  18
                 this.dependencyList.add(depend);
 259  
             }
 260  18
         }
 261  10
     }
 262  
 
 263  
     /**
 264  
      * Gets the message associated with the validator action.
 265  
      * @return The message for the validator action.
 266  
      */
 267  
     public String getMsg() {
 268  0
         return msg;
 269  
     }
 270  
 
 271  
     /**
 272  
      * Sets the message associated with the validator action.
 273  
      * @param msg The message for the validator action.
 274  
      */
 275  
     public void setMsg(String msg) {
 276  380
         this.msg = msg;
 277  380
     }
 278  
 
 279  
     /**
 280  
      * Gets the Javascript function name.  This is optional and can
 281  
      * be used instead of validator action name for the name of the
 282  
      * Javascript function/object.
 283  
      * @return The Javascript function name.
 284  
      */
 285  
     public String getJsFunctionName() {
 286  0
         return jsFunctionName;
 287  
     }
 288  
 
 289  
     /**
 290  
      * Sets the Javascript function name.  This is optional and can
 291  
      * be used instead of validator action name for the name of the
 292  
      * Javascript function/object.
 293  
      * @param jsFunctionName The Javascript function name.
 294  
      */
 295  
     public void setJsFunctionName(String jsFunctionName) {
 296  0
         this.jsFunctionName = jsFunctionName;
 297  0
     }
 298  
 
 299  
     /**
 300  
      * Sets the fully qualified class path of the Javascript function.
 301  
      * <p>
 302  
      * This is optional and can be used <strong>instead</strong> of the setJavascript().
 303  
      * Attempting to call both <code>setJsFunction</code> and <code>setJavascript</code>
 304  
      * will result in an <code>IllegalStateException</code> being thrown. </p>
 305  
      * <p>
 306  
      * If <strong>neither</strong> setJsFunction or setJavascript is set then
 307  
      * validator will attempt to load the default javascript definition.
 308  
      * </p>
 309  
      * <pre>
 310  
      * <b>Examples</b>
 311  
      *   If in the validator.xml :
 312  
      * #1:
 313  
      *      &lt;validator name="tire"
 314  
      *            jsFunction="com.yourcompany.project.tireFuncion"&gt;
 315  
      *     Validator will attempt to load com.yourcompany.project.validateTireFunction.js from
 316  
      *     its class path.
 317  
      * #2:
 318  
      *    &lt;validator name="tire"&gt;
 319  
      *      Validator will use the name attribute to try and load
 320  
      *         org.apache.commons.validator.javascript.validateTire.js
 321  
      *      which is the default javascript definition.
 322  
      * </pre>
 323  
      * @param jsFunction The Javascript function's fully qualified class path.
 324  
      */
 325  
     public void setJsFunction(String jsFunction) {
 326  0
         if (javascript != null) {
 327  0
             throw new IllegalStateException("Cannot call setJsFunction() after calling setJavascript()");
 328  
         }
 329  
 
 330  0
         this.jsFunction = jsFunction;
 331  0
     }
 332  
 
 333  
     /**
 334  
      * Gets the Javascript equivalent of the java class and method
 335  
      * associated with this action.
 336  
      * @return The Javascript validation.
 337  
      */
 338  
     public String getJavascript() {
 339  0
         return javascript;
 340  
     }
 341  
 
 342  
     /**
 343  
      * Sets the Javascript equivalent of the java class and method
 344  
      * associated with this action.
 345  
      * @param javascript The Javascript validation.
 346  
      */
 347  
     public void setJavascript(String javascript) {
 348  0
         if (jsFunction != null) {
 349  0
             throw new IllegalStateException("Cannot call setJavascript() after calling setJsFunction()");
 350  
         }
 351  
 
 352  0
         this.javascript = javascript;
 353  0
     }
 354  
 
 355  
     /**
 356  
      * Initialize based on set.
 357  
      */
 358  
     protected void init() {
 359  384
         this.loadJavascriptFunction();
 360  384
     }
 361  
 
 362  
     /**
 363  
      * Load the javascript function specified by the given path.  For this
 364  
      * implementation, the <code>jsFunction</code> property should contain a
 365  
      * fully qualified package and script name, separated by periods, to be
 366  
      * loaded from the class loader that created this instance.
 367  
      *
 368  
      * TODO if the path begins with a '/' the path will be intepreted as
 369  
      * absolute, and remain unchanged.  If this fails then it will attempt to
 370  
      * treat the path as a file path.  It is assumed the script ends with a
 371  
      * '.js'.
 372  
      */
 373  
     protected synchronized void loadJavascriptFunction() {
 374  
 
 375  384
         if (this.javascriptAlreadyLoaded()) {
 376  0
             return;
 377  
         }
 378  
 
 379  384
         if (getLog().isTraceEnabled()) {
 380  0
             getLog().trace("  Loading function begun");
 381  
         }
 382  
 
 383  384
         if (this.jsFunction == null) {
 384  384
             this.jsFunction = this.generateJsFunction();
 385  
         }
 386  
 
 387  384
         String javascriptFileName = this.formatJavascriptFileName();
 388  
 
 389  384
         if (getLog().isTraceEnabled()) {
 390  0
             getLog().trace("  Loading js function '" + javascriptFileName + "'");
 391  
         }
 392  
 
 393  384
         this.javascript = this.readJavascriptFile(javascriptFileName);
 394  
 
 395  384
         if (getLog().isTraceEnabled()) {
 396  0
             getLog().trace("  Loading javascript function completed");
 397  
         }
 398  
 
 399  384
     }
 400  
 
 401  
     /**
 402  
      * Read a javascript function from a file.
 403  
      * @param javascriptFileName The file containing the javascript.
 404  
      * @return The javascript function or null if it could not be loaded.
 405  
      */
 406  
     private String readJavascriptFile(String javascriptFileName) {
 407  384
         ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
 408  384
         if (classLoader == null) {
 409  0
             classLoader = this.getClass().getClassLoader();
 410  
         }
 411  
 
 412  384
         InputStream is = classLoader.getResourceAsStream(javascriptFileName);
 413  384
         if (is == null) {
 414  384
             is = this.getClass().getResourceAsStream(javascriptFileName);
 415  
         }
 416  
 
 417  384
         if (is == null) {
 418  384
             getLog().debug("  Unable to read javascript name "+javascriptFileName);
 419  384
             return null;
 420  
         }
 421  
 
 422  0
         StringBuilder buffer = new StringBuilder();
 423  0
         BufferedReader reader = new BufferedReader(new InputStreamReader(is)); // TODO encoding
 424  
         try {
 425  0
             String line = null;
 426  0
             while ((line = reader.readLine()) != null) {
 427  0
                 buffer.append(line).append("\n");
 428  
             }
 429  
 
 430  0
         } catch(IOException e) {
 431  0
             getLog().error("Error reading javascript file.", e);
 432  
 
 433  
         } finally {
 434  0
             try {
 435  0
                 reader.close();
 436  0
             } catch(IOException e) {
 437  0
                 getLog().error("Error closing stream to javascript file.", e);
 438  0
             }
 439  0
         }
 440  
 
 441  0
         String function = buffer.toString();
 442  0
         return function.equals("") ? null : function;
 443  
     }
 444  
 
 445  
     /**
 446  
      * @return A filename suitable for passing to a
 447  
      * ClassLoader.getResourceAsStream() method.
 448  
      */
 449  
     private String formatJavascriptFileName() {
 450  384
         String name = this.jsFunction.substring(1);
 451  
 
 452  384
         if (!this.jsFunction.startsWith("/")) {
 453  384
             name = jsFunction.replace('.', '/') + ".js";
 454  
         }
 455  
 
 456  384
         return name;
 457  
     }
 458  
 
 459  
     /**
 460  
      * @return true if the javascript for this action has already been loaded.
 461  
      */
 462  
     private boolean javascriptAlreadyLoaded() {
 463  384
         return (this.javascript != null);
 464  
     }
 465  
 
 466  
     /**
 467  
      * Used to generate the javascript name when it is not specified.
 468  
      */
 469  
     private String generateJsFunction() {
 470  384
         StringBuilder jsName =
 471  
                 new StringBuilder("org.apache.commons.validator.javascript");
 472  
 
 473  384
         jsName.append(".validate");
 474  384
         jsName.append(name.substring(0, 1).toUpperCase());
 475  384
         jsName.append(name.substring(1, name.length()));
 476  
 
 477  384
         return jsName.toString();
 478  
     }
 479  
 
 480  
     /**
 481  
      * Checks whether or not the value passed in is in the depends field.
 482  
      * @param validatorName Name of the dependency to check.
 483  
      * @return Whether the named validator is a dependant.
 484  
      */
 485  
     public boolean isDependency(String validatorName) {
 486  0
         return this.dependencyList.contains(validatorName);
 487  
     }
 488  
 
 489  
     /**
 490  
      * Returns the dependent validator names as an unmodifiable
 491  
      * <code>List</code>.
 492  
      * @return List of the validator action's depedents.
 493  
      */
 494  
     public List<String> getDependencyList() {
 495  208
         return Collections.unmodifiableList(this.dependencyList);
 496  
     }
 497  
 
 498  
     /**
 499  
      * Returns a string representation of the object.
 500  
      * @return a string representation.
 501  
      */
 502  
     @Override
 503  
     public String toString() {
 504  0
         StringBuilder results = new StringBuilder("ValidatorAction: ");
 505  0
         results.append(name);
 506  0
         results.append("\n");
 507  
 
 508  0
         return results.toString();
 509  
     }
 510  
 
 511  
     /**
 512  
      * Dynamically runs the validation method for this validator and returns
 513  
      * true if the data is valid.
 514  
      * @param field
 515  
      * @param params A Map of class names to parameter values.
 516  
      * @param results
 517  
      * @param pos The index of the list property to validate if it's indexed.
 518  
      * @throws ValidatorException
 519  
      */
 520  
     boolean executeValidationMethod(
 521  
         Field field,
 522  
         // TODO What is this the correct value type?
 523  
         // both ValidatorAction and Validator are added as parameters
 524  
         Map<String, Object> params,
 525  
         ValidatorResults results,
 526  
         int pos)
 527  
         throws ValidatorException {
 528  
 
 529  201
         params.put(Validator.VALIDATOR_ACTION_PARAM, this);
 530  
 
 531  
         try {
 532  201
             if (this.validationMethod == null) {
 533  131
                 synchronized(this) {
 534  131
                     ClassLoader loader = this.getClassLoader(params);
 535  131
                     this.loadValidationClass(loader);
 536  131
                     this.loadParameterClasses(loader);
 537  131
                     this.loadValidationMethod();
 538  131
                 }
 539  
             }
 540  
 
 541  201
             Object[] paramValues = this.getParameterValues(params);
 542  
 
 543  201
             if (field.isIndexed()) {
 544  0
                 this.handleIndexedField(field, pos, paramValues);
 545  
             }
 546  
 
 547  201
             Object result = null;
 548  
             try {
 549  201
                 result =
 550  
                     validationMethod.invoke(
 551  
                         getValidationClassInstance(),
 552  
                         paramValues);
 553  
 
 554  0
             } catch (IllegalArgumentException e) {
 555  0
                 throw new ValidatorException(e.getMessage());
 556  0
             } catch (IllegalAccessException e) {
 557  0
                 throw new ValidatorException(e.getMessage());
 558  1
             } catch (InvocationTargetException e) {
 559  
 
 560  1
                 if (e.getTargetException() instanceof Exception) {
 561  1
                     throw (Exception) e.getTargetException();
 562  
 
 563  0
                 } else if (e.getTargetException() instanceof Error) {
 564  0
                     throw (Error) e.getTargetException();
 565  
                 }
 566  200
             }
 567  
 
 568  200
             boolean valid = this.isValid(result);
 569  200
             if (!valid || (valid && !onlyReturnErrors(params))) {
 570  199
                 results.add(field, this.name, valid, result);
 571  
             }
 572  
 
 573  200
             if (!valid) {
 574  95
                 return false;
 575  
             }
 576  
 
 577  
             // TODO This catch block remains for backward compatibility.  Remove
 578  
             // this for Validator 2.0 when exception scheme changes.
 579  1
         } catch (Exception e) {
 580  1
             if (e instanceof ValidatorException) {
 581  1
                 throw (ValidatorException) e;
 582  
             }
 583  
 
 584  0
             getLog().error(
 585  
                 "Unhandled exception thrown during validation: " + e.getMessage(),
 586  
                 e);
 587  
 
 588  0
             results.add(field, this.name, false);
 589  0
             return false;
 590  105
         }
 591  
 
 592  105
         return true;
 593  
     }
 594  
 
 595  
     /**
 596  
      * Load the Method object for the configured validation method name.
 597  
      * @throws ValidatorException
 598  
      */
 599  
     private void loadValidationMethod() throws ValidatorException {
 600  131
         if (this.validationMethod != null) {
 601  0
             return;
 602  
         }
 603  
 
 604  
         try {
 605  131
             this.validationMethod =
 606  
                 this.validationClass.getMethod(this.method, this.parameterClasses);
 607  
 
 608  0
         } catch (NoSuchMethodException e) {
 609  0
             throw new ValidatorException("No such validation method: " +
 610  
                 e.getMessage());
 611  131
         }
 612  131
     }
 613  
 
 614  
     /**
 615  
      * Load the Class object for the configured validation class name.
 616  
      * @param loader The ClassLoader used to load the Class object.
 617  
      * @throws ValidatorException
 618  
      */
 619  
     private void loadValidationClass(ClassLoader loader)
 620  
         throws ValidatorException {
 621  
 
 622  131
         if (this.validationClass != null) {
 623  0
             return;
 624  
         }
 625  
 
 626  
         try {
 627  131
             this.validationClass = loader.loadClass(this.classname);
 628  0
         } catch (ClassNotFoundException e) {
 629  0
             throw new ValidatorException(e.toString());
 630  131
         }
 631  131
     }
 632  
 
 633  
     /**
 634  
      * Converts a List of parameter class names into their Class objects.
 635  
      * Stores the output in {@link parameterClasses}.  This
 636  
      * array is in the same order as the given List and is suitable for passing
 637  
      * to the validation method.
 638  
      * @throws ValidatorException if a class cannot be loaded.
 639  
      */
 640  
     private void loadParameterClasses(ClassLoader loader)
 641  
         throws ValidatorException {
 642  
 
 643  131
         if (this.parameterClasses != null) {
 644  0
             return;
 645  
         }
 646  
 
 647  131
         Class<?>[] parameterClasses = new Class[this.methodParameterList.size()];
 648  
 
 649  418
         for (int i = 0; i < this.methodParameterList.size(); i++) {
 650  287
             String paramClassName = this.methodParameterList.get(i);
 651  
 
 652  
             try {
 653  287
                 parameterClasses[i] = loader.loadClass(paramClassName);
 654  
 
 655  0
             } catch (ClassNotFoundException e) {
 656  0
                 throw new ValidatorException(e.getMessage());
 657  287
             }
 658  
         }
 659  
 
 660  131
         this.parameterClasses = parameterClasses;
 661  131
     }
 662  
 
 663  
     /**
 664  
      * Converts a List of parameter class names into their values contained in
 665  
      * the parameters Map.
 666  
      * @param params A Map of class names to parameter values.
 667  
      * @return An array containing the value object for each parameter.  This
 668  
      * array is in the same order as the given List and is suitable for passing
 669  
      * to the validation method.
 670  
      */
 671  
     private Object[] getParameterValues(Map<String, ? super Object> params) {
 672  
 
 673  201
         Object[] paramValue = new Object[this.methodParameterList.size()];
 674  
 
 675  634
         for (int i = 0; i < this.methodParameterList.size(); i++) {
 676  433
             String paramClassName = this.methodParameterList.get(i);
 677  433
             paramValue[i] = params.get(paramClassName);
 678  
         }
 679  
 
 680  201
         return paramValue;
 681  
     }
 682  
 
 683  
     /**
 684  
      * Return an instance of the validation class or null if the validation
 685  
      * method is static so does not require an instance to be executed.
 686  
      */
 687  
     private Object getValidationClassInstance() throws ValidatorException {
 688  201
         if (Modifier.isStatic(this.validationMethod.getModifiers())) {
 689  201
             this.instance = null;
 690  
 
 691  
         } else {
 692  0
             if (this.instance == null) {
 693  
                 try {
 694  0
                     this.instance = this.validationClass.newInstance();
 695  0
                 } catch (InstantiationException e) {
 696  0
                     String msg =
 697  
                         "Couldn't create instance of "
 698  
                             + this.classname
 699  
                             + ".  "
 700  
                             + e.getMessage();
 701  
 
 702  0
                     throw new ValidatorException(msg);
 703  
 
 704  0
                 } catch (IllegalAccessException e) {
 705  0
                     String msg =
 706  
                         "Couldn't create instance of "
 707  
                             + this.classname
 708  
                             + ".  "
 709  
                             + e.getMessage();
 710  
 
 711  0
                     throw new ValidatorException(msg);
 712  0
                 }
 713  
             }
 714  
         }
 715  
 
 716  201
         return this.instance;
 717  
     }
 718  
 
 719  
     /**
 720  
      * Modifies the paramValue array with indexed fields.
 721  
      *
 722  
      * @param field
 723  
      * @param pos
 724  
      * @param paramValues
 725  
      */
 726  
     private void handleIndexedField(Field field, int pos, Object[] paramValues)
 727  
         throws ValidatorException {
 728  
 
 729  0
         int beanIndex = this.methodParameterList.indexOf(Validator.BEAN_PARAM);
 730  0
         int fieldIndex = this.methodParameterList.indexOf(Validator.FIELD_PARAM);
 731  
 
 732  0
         Object indexedList[] = field.getIndexedProperty(paramValues[beanIndex]);
 733  
 
 734  
         // Set current iteration object to the parameter array
 735  0
         paramValues[beanIndex] = indexedList[pos];
 736  
 
 737  
         // Set field clone with the key modified to represent
 738  
         // the current field
 739  0
         Field indexedField = (Field) field.clone();
 740  0
         indexedField.setKey(
 741  
             ValidatorUtils.replace(
 742  
                 indexedField.getKey(),
 743  
                 Field.TOKEN_INDEXED,
 744  
                 "[" + pos + "]"));
 745  
 
 746  0
         paramValues[fieldIndex] = indexedField;
 747  0
     }
 748  
 
 749  
     /**
 750  
      * If the result object is a <code>Boolean</code>, it will return its
 751  
      * value.  If not it will return <code>false</code> if the object is
 752  
      * <code>null</code> and <code>true</code> if it isn't.
 753  
      */
 754  
     private boolean isValid(Object result) {
 755  200
         if (result instanceof Boolean) {
 756  173
             Boolean valid = (Boolean) result;
 757  173
             return valid.booleanValue();
 758  
         }
 759  27
         return result != null;
 760  
     }
 761  
 
 762  
     /**
 763  
      * Returns the ClassLoader set in the Validator contained in the parameter
 764  
      * Map.
 765  
      */
 766  
     private ClassLoader getClassLoader(Map<String, Object> params) {
 767  131
         Validator v = (Validator) params.get(Validator.VALIDATOR_PARAM);
 768  131
         return v.getClassLoader();
 769  
     }
 770  
 
 771  
     /**
 772  
      * Returns the onlyReturnErrors setting in the Validator contained in the
 773  
      * parameter Map.
 774  
      */
 775  
     private boolean onlyReturnErrors(Map<String, Object> params) {
 776  105
         Validator v = (Validator) params.get(Validator.VALIDATOR_PARAM);
 777  105
         return v.getOnlyReturnErrors();
 778  
     }
 779  
 
 780  
     /**
 781  
      * Accessor method for Log instance.
 782  
      *
 783  
      * The Log instance variable is transient and
 784  
      * accessing it through this method ensures it
 785  
      * is re-initialized when this instance is
 786  
      * de-serialized.
 787  
      *
 788  
      * @return The Log instance.
 789  
      */
 790  
     private Log getLog() {
 791  1536
         if (log == null) {
 792  0
             log =  LogFactory.getLog(ValidatorAction.class);
 793  
         }
 794  1536
         return log;
 795  
     }
 796  
 }