1 /*
2 * Copyright 2007 Kasper B. Graversen
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.supercsv.cellprocessor.constraint;
17
18 import org.supercsv.cellprocessor.CellProcessorAdaptor;
19 import org.supercsv.cellprocessor.ift.DoubleCellProcessor;
20 import org.supercsv.cellprocessor.ift.StringCellProcessor;
21 import org.supercsv.exception.SuperCsvCellProcessorException;
22 import org.supercsv.exception.SuperCsvConstraintViolationException;
23 import org.supercsv.util.CsvContext;
24
25 /**
26 * Converts the input data to a Double and ensures that number is within a specified numeric range (inclusive). If the
27 * data has no upper bound (or lower bound), you should use either of <code>MIN</code> or <code>MAX</code> constants
28 * provided in the class.
29 *
30 * @author Kasper B. Graversen
31 * @author James Bassett
32 */
33 public class DMinMax extends CellProcessorAdaptor implements StringCellProcessor {
34
35 /** Maximum value for a Double */
36 public static final double MAX_DOUBLE = Double.MAX_VALUE;
37
38 /** Minimum value for a Double */
39 public static final double MIN_DOUBLE = Double.MIN_VALUE;
40
41 /** Maximum value for a Short */
42 public static final double MAX_SHORT = Short.MAX_VALUE;
43
44 /** Minimum value for a Short */
45 public static final double MIN_SHORT = Short.MIN_VALUE;
46
47 /** Maximum value for a Character */
48 public static final double MAX_CHAR = Character.MAX_VALUE;
49
50 /** Minimum value for a Character */
51 public static final double MIN_CHAR = Character.MIN_VALUE;
52
53 /** Maximum value for 8 bits (unsigned) */
54 public static final int MAX_8_BIT_UNSIGNED = 255;
55
56 /** Minimum value for 8 bits (unsigned) */
57 public static final int MIN_8_BIT_UNSIGNED = 0;
58
59 /** Maximum value for 8 bits (signed) */
60 public static final int MAX_8_BIT_SIGNED = Byte.MAX_VALUE;
61
62 /** Minimum value for 8 bits (signed) */
63 public static final int MIN_8_BIT_SIGNED = Byte.MIN_VALUE;
64
65 private final double min;
66
67 private final double max;
68
69 /**
70 * Constructs a new <tt>DMinMax</tt> processor, which converts the input to a Double and ensures the value is
71 * between the supplied min and max values.
72 *
73 * @param min
74 * the minimum value (inclusive)
75 * @param max
76 * the maximum value (inclusive)
77 * @throws IllegalArgumentException
78 * if {@code max < min}
79 */
80 public DMinMax(final double min, final double max) {
81 super();
82 checkPreconditions(min, max);
83 this.min = min;
84 this.max = max;
85 }
86
87 /**
88 * Constructs a new <tt>DMinMax</tt> processor, which converts the input to a Double, ensures the value is between
89 * the supplied min and max values, then calls the next processor in the chain.
90 *
91 * @param min
92 * the minimum value (inclusive)
93 * @param max
94 * the maximum value (inclusive)
95 * @param next
96 * the next processor in the chain
97 * @throws IllegalArgumentException
98 * if {@code max < min}
99 * @throws NullPointerException
100 * if next is null
101 */
102 public DMinMax(final double min, final double max, final DoubleCellProcessor next) {
103 super(next);
104 checkPreconditions(min, max);
105 this.min = min;
106 this.max = max;
107 }
108
109 /**
110 * Checks the preconditions for creating a new DMinMax processor.
111 *
112 * @param min
113 * the minimum value (inclusive)
114 * @param max
115 * the maximum value (inclusive)
116 * @throws IllegalArgumentException
117 * if {@code max < min}
118 */
119 private static void checkPreconditions(final double min, final double max) {
120 if( max < min ) {
121 throw new IllegalArgumentException(String.format("max (%f) should not be < min (%f)", max, min));
122 }
123 }
124
125 /**
126 * {@inheritDoc}
127 *
128 * @throws SuperCsvCellProcessorException
129 * if value is null or can't be parsed as a Double
130 * @throws SuperCsvConstraintViolationException
131 * if value doesn't lie between min and max (inclusive)
132 */
133 public Object execute(final Object value, final CsvContext context) {
134 validateInputNotNull(value, context);
135
136 final Double result;
137 if( value instanceof Double ) {
138 result = (Double) value;
139 } else {
140 try {
141 result = Double.parseDouble(value.toString());
142 }
143 catch(final NumberFormatException e) {
144 throw new SuperCsvCellProcessorException(String.format("'%s' could not be parsed as a Double", value),
145 context, this, e);
146 }
147 }
148
149 if( result < min || result > max ) {
150 throw new SuperCsvConstraintViolationException(String.format(
151 "%f does not lie between the min (%f) and max (%f) values (inclusive)", result, min, max), context,
152 this);
153 }
154
155 return next.execute(result, context);
156 }
157
158 }