View Javadoc

    1   /*
    2    * $Id: PercentValidator.java 386637 2006-03-17 13:22:26Z niallp $
    3    * $Revision: 386637 $
    4    * $Date: 2006-03-17 13:22:26 +0000 (Fri, 17 Mar 2006) $
    5    *
    6    * ====================================================================
    7    * Copyright 2006 The Apache Software Foundation
    8    *
    9    * Licensed under the Apache License, Version 2.0 (the "License");
    10   * you may not use this file except in compliance with the License.
    11   * You may obtain a copy of the License at
    12   *
    13   *     http://www.apache.org/licenses/LICENSE-2.0
    14   *
    15   * Unless required by applicable law or agreed to in writing, software
    16   * distributed under the License is distributed on an "AS IS" BASIS,
    17   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    18   * See the License for the specific language governing permissions and
    19   * limitations under the License.
    20   */
    21  package org.apache.commons.validator.routines;
    22
    23  import java.text.DecimalFormat;
    24  import java.text.Format;
    25  import java.math.BigDecimal;
    26
    27  /***
    28   * <p><b>Percentage Validation</b> and Conversion routines (<code>java.math.BigDecimal</code>).</p>
    29   *
    30   * <p>This is one implementation of a percent validator that has the following features:</p>
    31   *    <ul>
    32   *       <li>It is <i>lenient</i> about the the presence of the <i>percent symbol</i></li>
    33   *       <li>It converts the percent to a <code>java.math.BigDecimal</code></li>
    34   *    </ul>
    35   *
    36   * <p>However any of the <i>number</i> validators can be used for <i>percent</i> validation.
    37   *    For example, if you wanted a <i>percent</i> validator that converts to a
    38   *    <code>java.lang.Float</code> then you can simply instantiate an
    39   *    <code>FloatValidator</code> with the appropriate <i>format type</i>:</p>
    40   *
    41   *    <p><code>... = new FloatValidator(false, FloatValidator.PERCENT_FORMAT);</code></p>
    42   *
    43   * <p>Pick the appropriate validator, depending on the type (i.e Float, Double or BigDecimal)
    44   *    you want the percent converted to. Please note, it makes no sense to use
    45   *    one of the validators that doesn't handle fractions (i.e. byte, short, integer, long
    46   *    and BigInteger) since percentages are converted to fractions (i.e <code>50%</code> is
    47   *    converted to <code>0.5</code>).</p>
    48   *
    49   * @version $Revision: 386637 $ $Date: 2006-03-17 13:22:26 +0000 (Fri, 17 Mar 2006) $
    50   * @since Validator 1.3.0
    51   */
    52  public class PercentValidator extends BigDecimalValidator {
    53
    54      private static final PercentValidator VALIDATOR = new PercentValidator();
    55
    56      /*** DecimalFormat's percent (thousand multiplier) symbol */
    57      private static final char PERCENT_SYMBOL = '%';
    58
    59      private static final BigDecimal POINT_ZERO_ONE = new BigDecimal("0.01");
    60
    61      /***
    62       * Return a singleton instance of this validator.
    63       * @return A singleton instance of the PercentValidator.
    64       */
    65      public static BigDecimalValidator getInstance() {
    66          return VALIDATOR;
    67      }
    68
    69      /***
    70       * Construct a <i>strict</i> instance.
    71       */
    72      public PercentValidator() {
    73          this(true);
    74      }
    75
    76      /***
    77       * Construct an instance with the specified strict setting.
    78       *
    79       * @param strict <code>true</code> if strict
    80       *        <code>Format</code> parsing should be used.
    81       */
    82      public PercentValidator(boolean strict) {
    83          super(strict, PERCENT_FORMAT, true);
    84      }
    85
    86      /***
    87       * <p>Parse the value with the specified <code>Format</code>.</p>
    88       *
    89       * <p>This implementation is lenient whether the currency symbol
    90       *    is present or not. The default <code>NumberFormat</code>
    91       *    behaviour is for the parsing to "fail" if the currency
    92       *    symbol is missing. This method re-parses with a format
    93       *    without the currency symbol if it fails initially.</p>
    94       *
    95       * @param value The value to be parsed.
    96       * @param formatter The Format to parse the value with.
    97       * @return The parsed value if valid or <code>null</code> if invalid.
    98       */
    99      protected Object parse(String value, Format formatter) {
    100
    101         // Initial parse of the value
    102         BigDecimal parsedValue = (BigDecimal)super.parse(value, formatter);
    103         if (parsedValue != null || !(formatter instanceof DecimalFormat)) {
    104             return parsedValue;
    105         }
    106
    107         // Re-parse using a pattern without the percent symbol
    108         DecimalFormat decimalFormat = (DecimalFormat)formatter;
    109         String pattern = decimalFormat.toPattern();
    110         if (pattern.indexOf(PERCENT_SYMBOL) >= 0) {
    111             StringBuffer buffer = new StringBuffer(pattern.length());
    112             for (int i = 0; i < pattern.length(); i++) {
    113                 if (pattern.charAt(i) != PERCENT_SYMBOL) {
    114                     buffer.append(pattern.charAt(i));
    115                 }
    116             }
    117             decimalFormat.applyPattern(buffer.toString());
    118             parsedValue = (BigDecimal)super.parse(value, decimalFormat);
    119
    120             // If parsed OK, divide by 100 to get percent
    121             if (parsedValue != null) {
    122                 parsedValue = parsedValue.multiply(POINT_ZERO_ONE);
    123             }
    124
    125         }
    126         return parsedValue;
    127     }
    128 }