001: /**
002: * Copyright 2006 Webmedia Group Ltd.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: **/package org.araneaframework.uilib.form.control;
016:
017: import java.math.BigDecimal;
018: import org.apache.commons.lang.StringUtils;
019: import org.araneaframework.uilib.form.FilteredInputControl;
020: import org.araneaframework.uilib.form.control.inputfilter.InputFilter;
021: import org.araneaframework.uilib.support.UiLibMessages;
022: import org.araneaframework.uilib.util.MessageUtil;
023:
024: /**
025: * This class represents a textbox control that accepts only valid
026: * floating-point numbers.
027: *
028: * This class does not support localization. It does not use @link NumberFormat
029: * class to parse and format @link BigDecimal objects because @link NumberFormat
030: * would convert @link BigDecimal objects into doubles.
031: *
032: * To customize parsing and formatting one could create a subclass of it and
033: * override @link #createBigDecimal(String) and @link #toString(BigDecimal)
034: * methods. To use the subclass in JSPs also another JSP Tag must be created
035: * to use this implementation and configure validation script.
036: *
037: * @author Jevgeni Kabanov (ekabanov <i>at</i> araneaframework <i>dot</i> org)
038: * @author <a href="mailto:rein@araneaframework.org">Rein Raudjärv</a>
039: */
040: public class FloatControl extends EmptyStringNullableControl implements
041: FilteredInputControl {
042: private InputFilter inputFilter;
043: private BigDecimal minValue;
044: private BigDecimal maxValue;
045: private Integer maxScale;
046:
047: /**
048: * Empty.
049: */
050: public FloatControl() {
051: //Empty
052: }
053:
054: /**
055: * Makes a float control that has minimum, maximum value and maximum scale.
056: *
057: * @param minValue minimum permitted value.
058: * @param maxValue maximum permitted value.
059: * @param maxScale maximum permitted scale.
060: */
061: public FloatControl(BigDecimal minValue, BigDecimal maxValue,
062: Integer maxScale) {
063: setMinValue(minValue);
064: setMaxValue(maxValue);
065: setMaxScale(maxScale);
066: }
067:
068: /**
069: * Makes a float control that has minimum and maximum value.
070: *
071: * @param minValue minimum permitted value.
072: * @param maxValue maximum permitted value.
073: */
074: public FloatControl(BigDecimal minValue, BigDecimal maxValue) {
075: this (minValue, maxValue, null);
076: }
077:
078: /**
079: * Sets the maximum value.
080: * @param maxValue maximum value.
081: */
082: public void setMaxValue(BigDecimal maxValue) {
083: this .maxValue = maxValue;
084: }
085:
086: /**
087: * Sets the minimum value.
088: * @param minValue minimum value.
089: */
090: public void setMinValue(BigDecimal minValue) {
091: this .minValue = minValue;
092: }
093:
094: /**
095: * Sets the maximum scale.
096: * @param maxScale maximum scale.
097: */
098: public void setMaxScale(Integer maxScale) {
099: if (maxScale != null && maxScale.intValue() < 0) {
100: throw new IllegalArgumentException(
101: "Maximum scale cannot be negative");
102: }
103: this .maxScale = maxScale;
104: }
105:
106: /**
107: * Returns the maxValue.
108: * @return the maxValue.
109: */
110: public BigDecimal getMaxValue() {
111: return maxValue;
112: }
113:
114: /**
115: * Returns the minValue.
116: * @return the minValue.
117: */
118: public BigDecimal getMinValue() {
119: return minValue;
120: }
121:
122: /**
123: * Returns the maximum scale.
124: * @return the maximum scale.
125: */
126: public Integer getMaxScale() {
127: return maxScale;
128: }
129:
130: /**
131: * Returns "BigDecimal".
132: * @return "BigDecimal".
133: */
134: public String getRawValueType() {
135: return "BigDecimal";
136: }
137:
138: /** @since 1.0.11 */
139: public InputFilter getInputFilter() {
140: return inputFilter;
141: }
142:
143: /** @since 1.0.11 */
144: public void setInputFilter(InputFilter inputFilter) {
145: this .inputFilter = inputFilter;
146: }
147:
148: //*********************************************************************
149: //* INTERNAL METHODS
150: //*********************************************************************
151:
152: /**
153: * Trims request parameter.
154: */
155: protected String preprocessRequestParameter(String parameterValue) {
156: String result = super
157: .preprocessRequestParameter(parameterValue);
158: return (result == null ? null : result.trim());
159: }
160:
161: /**
162: * Checks that the submitted data is a valid floating-point number.
163: *
164: */
165: protected Object fromRequest(String parameterValue) {
166: BigDecimal result = null;
167:
168: try {
169: result = createBigDecimal(parameterValue);
170: } catch (NumberFormatException e) {
171: addError(MessageUtil.localizeAndFormat(
172: UiLibMessages.NOT_A_NUMBER, MessageUtil.localize(
173: getLabel(), getEnvironment()),
174: getEnvironment()));
175: }
176:
177: if (getInputFilter() != null
178: && !StringUtils.containsOnly(parameterValue,
179: getInputFilter().getCharacterFilter())) {
180: addError(MessageUtil.localizeAndFormat(getInputFilter()
181: .getInvalidInputMessage(), MessageUtil.localize(
182: getLabel(), getEnvironment()), getInputFilter()
183: .getCharacterFilter(), getEnvironment()));
184: }
185:
186: return result;
187: }
188:
189: /**
190: *
191: */
192: protected String toResponse(Object controlValue) {
193: return toString((BigDecimal) controlValue);
194: }
195:
196: /**
197: * Converts String into BigDecimal. This method can be overrided in subclasses.
198: *
199: * @param str String object
200: * @return BigDecimal object
201: * @throws NumberFormatException <tt>str</tt> is not a valid representation
202: * of a BigDecimal
203: */
204: protected BigDecimal createBigDecimal(String str)
205: throws NumberFormatException {
206: if (str == null) {
207: return null;
208: }
209: return new BigDecimal(str);
210: }
211:
212: /**
213: * Converts BigDecimal into String. This method can be overrided in subclasses.
214: *
215: * @param dec BigDecimal object
216: * @return String object
217: */
218: protected String toString(BigDecimal dec) {
219: if (dec == null) {
220: return null;
221: }
222: return dec.toString();
223: }
224:
225: /**
226: * Checks that the submitted value is in permitted range.
227: *
228: */
229: protected void validateNotNull() {
230: // minimum and maximum permitted values
231: if (minValue != null
232: && maxValue != null
233: && ((((BigDecimal) getRawValue()).compareTo(minValue) == -1) || ((BigDecimal) getRawValue())
234: .compareTo(maxValue) == 1)) {
235: addError(MessageUtil.localizeAndFormat(
236: UiLibMessages.NUMBER_NOT_BETWEEN, new Object[] {
237: MessageUtil.localize(getLabel(),
238: getEnvironment()),
239: minValue.toString(), maxValue.toString() },
240: getEnvironment()));
241: } else if (minValue != null
242: && ((BigDecimal) getRawValue()).compareTo(minValue) == -1) {
243: addError(MessageUtil.localizeAndFormat(
244: UiLibMessages.NUMBER_NOT_GREATER, new Object[] {
245: MessageUtil.localize(getLabel(),
246: getEnvironment()),
247: minValue.toString(), }, getEnvironment()));
248: } else if (maxValue != null
249: && ((BigDecimal) getRawValue()).compareTo(maxValue) == 1) {
250: addError(MessageUtil.localizeAndFormat(
251: UiLibMessages.NUMBER_NOT_LESS, new Object[] {
252: MessageUtil.localize(getLabel(),
253: getEnvironment()),
254: maxValue.toString(), }, getEnvironment()));
255: }
256:
257: // maximum permitted scale
258: if (maxScale != null
259: && ((BigDecimal) getRawValue()).scale() > maxScale
260: .intValue()) {
261: addError(MessageUtil.localizeAndFormat(
262: UiLibMessages.SCALE_NOT_LESS, new Object[] {
263: MessageUtil.localize(getLabel(),
264: getEnvironment()),
265: maxScale.toString(), }, getEnvironment()));
266: }
267: }
268:
269: /**
270: * Returns {@link ViewModel}.
271: * @return {@link ViewModel}.
272: */
273: public Object getViewModel() {
274: return new ViewModel();
275: }
276:
277: //*********************************************************************
278: //* VIEW MODEL
279: //*********************************************************************
280:
281: /**
282: * @author Jevgeni Kabanov (ekabanov <i>at</i> araneaframework <i>dot</i> org)
283: *
284: */
285: public class ViewModel extends StringArrayRequestControl.ViewModel {
286: private InputFilter inputFilter;
287: private BigDecimal maxValue;
288: private BigDecimal minValue;
289: private Integer maxScale;
290:
291: /**
292: * Takes an outer class snapshot.
293: */
294: public ViewModel() {
295: this .maxValue = FloatControl.this .getMaxValue();
296: this .minValue = FloatControl.this .getMinValue();
297: this .maxScale = FloatControl.this .getMaxScale();
298: this .inputFilter = FloatControl.this .getInputFilter();
299: }
300:
301: /**
302: * Returns maximum permitted value.
303: * @return maximum permitted value.
304: */
305: public BigDecimal getMaxValue() {
306: return this .maxValue;
307: }
308:
309: /**
310: * Returns minimum permitted value.
311: * @return minimum permitted value.
312: */
313: public BigDecimal getMinValue() {
314: return this .minValue;
315: }
316:
317: /**
318: * Returns maximum permitted scale.
319: * @return maximum permitted scale.
320: */
321: public Integer getMaxScale() {
322: return maxScale;
323: }
324:
325: public InputFilter getInputFilter() {
326: return this.inputFilter;
327: }
328: }
329: }
|