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 }