001: /*
002: * Geotools2 - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2002, 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: */
017: package org.geotools.feature.iso.attribute;
018:
019: import java.math.BigDecimal;
020: import java.math.BigInteger;
021:
022: import org.geotools.feature.iso.AttributeImpl;
023: import org.opengis.feature.type.AttributeDescriptor;
024: import org.opengis.feature.type.AttributeType;
025:
026: /**
027: * Class that represents a Numeric.
028: *
029: * @author Ian Schneider
030: * @author Chris Holmes, TOPP
031: */
032: public class NumericAttribute extends AttributeImpl implements
033: org.opengis.feature.simple.NumericAttribute {
034:
035: /**
036: * @param descriptor
037: * @param content
038: * @throws IllegalArgumentException
039: */
040: public NumericAttribute(Number content,
041: AttributeDescriptor descriptor)
042: throws IllegalArgumentException {
043:
044: super (content, descriptor, null);
045:
046: if (!Number.class.isAssignableFrom(((AttributeType) descriptor
047: .type()).getBinding())) {
048: throw new IllegalArgumentException(
049: "Numeric requires Number class, "
050: + "not "
051: + ((AttributeType) descriptor.type())
052: .getBinding());
053: }
054: }
055:
056: public String toString() {
057: StringBuffer sb = new StringBuffer("NumericAttribute[");
058: sb.append("TYPE=").append(getType().getName()).append(
059: ", content='").append(getValue()).append("']");
060: return sb.toString();
061: }
062:
063: /**
064: * Allows this AttributeType to convert an argument to its prefered storage
065: * type. If no parsing is possible, returns the original value. If a parse
066: * is attempted, yet fails (i.e. a poor decimal format) throw the
067: * Exception. This is mostly for use internally in Features, but
068: * implementors should simply follow the rules to be safe.
069: *
070: * @param value the object to attempt parsing of.
071: *
072: * @return <code>value</code> converted to the preferred storage of this
073: * <code>AttributeType</code>. If no parsing was possible then
074: * the same object is returned.
075: *
076: * @throws IllegalArgumentException if parsing is attempted and is
077: * unsuccessful.
078: *
079: * @task REVISIT: When type is Number, should we always be using Double?
080: * (What else would we do? - IanS)
081: */
082: protected Object parse(Object value)
083: throws IllegalArgumentException {
084:
085: Class type = getType().getBinding();
086:
087: // handle null values first
088: if (value == null) {
089: return value;
090: }
091:
092: // no parse needed here if types are compatable
093: if ((value.getClass() == type)
094: || type.isAssignableFrom(value.getClass())) {
095: return value;
096: }
097:
098: // convert one Number to our preferred type
099: if (value instanceof Number) {
100: return convertNumber((Number) value);
101: }
102:
103: // parse a String to our preferred type
104: // note, this is the final parsing attempt !
105: String str = value.toString();
106:
107: try {
108: Object parsed = parseFromString(str);
109:
110: if (parsed != null) {
111: return parsed;
112: }
113: } catch (IllegalArgumentException iae) {
114: // do nothing
115: }
116:
117: // check empty string or black space
118: if ((str.length() == 0) || (str.trim().length() == 0)) {
119: Object parsed = parseFromString("0");
120:
121: if (parsed != null) {
122: return parsed;
123: }
124: }
125:
126: // nothing else to do
127: throw new IllegalArgumentException("Cannot parse "
128: + value.getClass());
129: }
130:
131: protected Object parseFromString(String value)
132: throws IllegalArgumentException {
133: Class type = ((AttributeType) DESCRIPTOR.type()).getBinding();
134: if (type == Byte.class) {
135: return Byte.decode(value);
136: }
137:
138: if (type == Short.class) {
139: return Short.decode(value);
140: }
141:
142: if (type == Integer.class) {
143: return Integer.decode(value);
144: }
145:
146: if (type == Float.class) {
147: return Float.valueOf(value);
148: }
149:
150: if (type == Double.class) {
151: return Double.valueOf(value);
152: }
153:
154: if (type == Long.class) {
155: return Long.decode(value);
156: }
157:
158: if (type == BigInteger.class) {
159: return new BigInteger(value);
160: }
161:
162: if (type == BigDecimal.class) {
163: return new BigDecimal(value);
164: }
165:
166: if (Number.class.isAssignableFrom(type)) {
167: return new Double(value);
168: }
169:
170: return null;
171: }
172:
173: protected Object convertNumber(Number number) {
174: Class type = getType().getBinding();
175:
176: if (type == Byte.class) {
177: return new Byte(number.byteValue());
178: }
179:
180: if (type == Short.class) {
181: return new Short(number.shortValue());
182: }
183:
184: if (type == Integer.class) {
185: return new Integer(number.intValue());
186: }
187:
188: if (type == Float.class) {
189: return new Float(number.floatValue());
190: }
191:
192: if (type == Double.class) {
193: return new Double(number.doubleValue());
194: }
195:
196: if (type == Long.class) {
197: return new Long(number.longValue());
198: }
199:
200: if (type == BigInteger.class) {
201: return BigInteger.valueOf(number.longValue());
202: }
203:
204: if (type == BigDecimal.class) {
205: return BigDecimal.valueOf(number.longValue());
206: }
207:
208: throw new RuntimeException("NumericAttribute cannot parse "
209: + number);
210: }
211:
212: public Number getNumber() {
213: return (Number) getValue();
214: }
215:
216: public void setNumber(Number newValue) {
217: setValue(newValue);
218: }
219: }
|