001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2004-2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.feature.type;
017:
018: import java.math.BigDecimal;
019: import java.math.BigInteger;
020: import org.geotools.feature.DefaultAttributeType;
021: import org.geotools.feature.PrimativeAttributeType;
022: import org.opengis.filter.Filter;
023:
024: /**
025: * Class that represents a Numeric.
026: *
027: * @author Ian Schneider
028: * @author Chris Holmes, TOPP
029: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/main/src/main/java/org/geotools/feature/type/NumericAttributeType.java $
030: */
031: public class NumericAttributeType extends DefaultAttributeType
032: implements PrimativeAttributeType {
033: /**
034: * Constructor with name, type and nillable. Type should always be a
035: * Number class.
036: *
037: * @param name Name of this attribute.
038: * @param type Class type of this attribute.
039: * @param nillable If nulls are allowed for the attribute of this type.
040: * @param min
041: * @param max
042: * @param defaultValue default value when none is suppled
043: * @param filter
044: *
045: * @throws IllegalArgumentException is type is not a Number.
046: *
047: * @task REVISIT: protected?
048: */
049: public NumericAttributeType(String name, Class type,
050: boolean nillable, int min, int max, Object defaultValue,
051: Filter filter) throws IllegalArgumentException {
052: super (name, type, nillable, min, max, defaultValue);
053: this .filter = filter;
054: if (!Number.class.isAssignableFrom(type)) {
055: throw new IllegalArgumentException(
056: "Numeric requires Number class, " + "not " + type);
057: }
058: }
059:
060: private Filter filter;
061:
062: public NumericAttributeType(String name, Class type,
063: boolean nillable, Object defaultValue, Filter filter)
064: throws IllegalArgumentException {
065: super (name, type, nillable, defaultValue);
066: this .filter = filter;
067: if (!Number.class.isAssignableFrom(type)) {
068: throw new IllegalArgumentException(
069: "Numeric requires Number class, " + "not " + type);
070: }
071: }
072:
073: /**
074: * Allows this AttributeType to convert an argument to its prefered storage
075: * type. If no parsing is possible, returns the original value. If a parse
076: * is attempted, yet fails (i.e. a poor decimal format) throw the
077: * Exception. This is mostly for use internally in Features, but
078: * implementors should simply follow the rules to be safe.
079: *
080: * @param value the object to attempt parsing of.
081: *
082: * @return <code>value</code> converted to the preferred storage of this
083: * <code>AttributeType</code>. If no parsing was possible then
084: * the same object is returned.
085: *
086: * @throws IllegalArgumentException if parsing is attempted and is
087: * unsuccessful.
088: *
089: * @task REVISIT: When type is Number, should we always be using Double?
090: * (What else would we do? - IanS)
091: */
092: public Object parse(Object value) throws IllegalArgumentException {
093: // handle null values first
094: if (value == null) {
095: return value;
096: }
097:
098: // no parse needed here if types are compatable
099: if ((value.getClass() == type)
100: || type.isAssignableFrom(value.getClass())) {
101: return value;
102: }
103:
104: // convert one Number to our preferred type
105: if (value instanceof Number) {
106: return convertNumber((Number) value);
107: }
108:
109: // parse a String to our preferred type
110: // note, this is the final parsing attempt !
111: String str = value.toString();
112:
113: //JD: trim any spaces off
114: str = str.trim();
115:
116: try {
117: Object parsed = parseFromString(str);
118:
119: if (parsed != null) {
120: return parsed;
121: }
122: } catch (IllegalArgumentException iae) {
123: // do nothing
124: }
125:
126: // check empty string or black space
127: if ((str.length() == 0) || (str.trim().length() == 0)) {
128: Object parsed = parseFromString("0");
129:
130: if (parsed != null) {
131: return parsed;
132: }
133: }
134:
135: // nothing else to do
136: throw new IllegalArgumentException("Cannot parse "
137: + value.getClass());
138: }
139:
140: /**
141: * Duplicate the given Object. In this case, since Number classes are
142: * immutable, lets return the Object.
143: *
144: * @param o DOCUMENT ME!
145: *
146: * @return DOCUMENT ME!
147: */
148: public Object duplicate(Object o) {
149: return o;
150: }
151:
152: protected Object parseFromString(String value)
153: throws IllegalArgumentException {
154: if (type == Byte.class) {
155: return Byte.decode(value);
156: }
157:
158: if (type == Short.class) {
159: return Short.decode(value);
160: }
161:
162: if (type == Integer.class) {
163: return Integer.decode(value);
164: }
165:
166: if (type == Float.class) {
167: return Float.valueOf(value);
168: }
169:
170: if (type == Double.class) {
171: return Double.valueOf(value);
172: }
173:
174: if (type == Long.class) {
175: return Long.decode(value);
176: }
177:
178: if (type == BigInteger.class) {
179: return new BigInteger(value);
180: }
181:
182: if (type == BigDecimal.class) {
183: return new BigDecimal(value);
184: }
185:
186: if (Number.class.isAssignableFrom(type)) {
187: return new Double(value);
188: }
189:
190: return null;
191: }
192:
193: protected Object convertNumber(Number number) {
194: if (type == Byte.class) {
195: return new Byte(number.byteValue());
196: }
197:
198: if (type == Short.class) {
199: return new Short(number.shortValue());
200: }
201:
202: if (type == Integer.class) {
203: return new Integer(number.intValue());
204: }
205:
206: if (type == Float.class) {
207: return new Float(number.floatValue());
208: }
209:
210: if (type == Double.class) {
211: return new Double(number.doubleValue());
212: }
213:
214: if (type == Long.class) {
215: return new Long(number.longValue());
216: }
217:
218: if (type == BigInteger.class) {
219: return BigInteger.valueOf(number.longValue());
220: }
221:
222: if (type == BigDecimal.class) {
223: return BigDecimal.valueOf(number.longValue());
224: }
225:
226: throw new RuntimeException("AttributeGT.Numeric cannot parse "
227: + number);
228: }
229:
230: /* (non-Javadoc)
231: * @see org.geotools.feature.PrimativeAttributeType#getRestriction()
232: */
233: public Filter getRestriction() {
234: return filter;
235: }
236:
237: }
|