001: /*
002: * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
003: * Copyright (C) 2007 - JScience (http://jscience.org/)
004: * All rights reserved.
005: *
006: * Permission to use, copy, modify, and distribute this software is
007: * freely granted, provided that this notice is preserved.
008: */
009: package javax.measure;
010:
011: import java.math.BigDecimal;
012: import java.text.FieldPosition;
013: import java.text.Format;
014: import java.text.NumberFormat;
015: import java.text.ParseException;
016: import java.text.ParsePosition;
017:
018: import javax.measure.unit.CompoundUnit;
019: import javax.measure.unit.Unit;
020: import javax.measure.unit.UnitFormat;
021:
022: /**
023: * <p> This class provides the interface for formatting and parsing {@link
024: * Measure measures}.</p>
025: *
026: * <p> As a minimum, instances of this class should be able to parse/format
027: * measure using {@link CompoundUnit}. </p>
028: *
029: * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
030: * @version 4.2, August 26, 2007
031: */
032: public abstract class MeasureFormat extends Format {
033:
034: /**
035: * Returns the measure format for the default locale.
036: *
037: * @return <code>getInstance(Number.getInstance(), Unit.getInstance())</code>
038: */
039: public static MeasureFormat getInstance() {
040: return DEFAULT;
041: }
042:
043: static final NumberUnit DEFAULT = new NumberUnit(NumberFormat
044: .getInstance(), UnitFormat.getInstance());
045:
046: /**
047: * Returns the measure format using the specified number format and
048: * unit format (the number and unit are separated by a space).
049: *
050: * @param numberFormat the number format.
051: * @param unitFormat the unit format.
052: * @return the corresponding format.
053: */
054: public static MeasureFormat getInstance(NumberFormat numberFormat,
055: UnitFormat unitFormat) {
056: return new NumberUnit(numberFormat, unitFormat);
057: }
058:
059: // Holds default implementation.
060: static final class NumberUnit extends MeasureFormat {
061: private final NumberFormat _numberFormat;
062:
063: private final UnitFormat _unitFormat;
064:
065: private NumberUnit(NumberFormat numberFormat,
066: UnitFormat unitFormat) {
067: _numberFormat = numberFormat;
068: _unitFormat = unitFormat;
069: }
070:
071: @Override
072: public StringBuffer format(Object obj, StringBuffer toAppendTo,
073: FieldPosition pos) {
074: Measure<?, ?> measure = (Measure<?, ?>) obj;
075: Object value = measure.getValue();
076: Unit<?> unit = measure.getUnit();
077: if (value instanceof Number) {
078: if (unit instanceof CompoundUnit)
079: return formatCompound(((Number) value)
080: .doubleValue(), (CompoundUnit<?>) unit,
081: toAppendTo, pos);
082: _numberFormat.format(value, toAppendTo, pos);
083: } else {
084: toAppendTo.append(value);
085: }
086: if (!measure.getUnit().equals(Unit.ONE)) {
087: toAppendTo.append(' ');
088: _unitFormat.format(unit, toAppendTo, pos);
089: }
090: return toAppendTo;
091: }
092:
093: // Measure using Compound unit have no separators in their representation.
094: StringBuffer formatCompound(double value, Unit<?> unit,
095: StringBuffer toAppendTo, FieldPosition pos) {
096: if (!(unit instanceof CompoundUnit)) {
097: toAppendTo.append((long) value);
098: return _unitFormat.format(unit, toAppendTo, pos);
099: }
100: Unit<?> high = ((CompoundUnit<?>) unit).getHigher();
101: Unit<?> low = ((CompoundUnit<?>) unit).getLower(); // The unit in which the value is stated.
102: long highValue = (long) low.getConverterTo(high).convert(
103: value);
104: double lowValue = value
105: - high.getConverterTo(low).convert(highValue);
106: formatCompound(highValue, high, toAppendTo, pos);
107: formatCompound(lowValue, low, toAppendTo, pos);
108: return toAppendTo;
109: }
110:
111: @Override
112: public Object parseObject(String source, ParsePosition pos) {
113: int start = pos.getIndex();
114: try {
115: int i = start;
116: Number value = _numberFormat.parse(source, pos);
117: if (i == pos.getIndex())
118: return null; // Cannot parse.
119: i = pos.getIndex();
120: if (i >= source.length())
121: return measureOf(value, Unit.ONE); // No unit.
122: boolean isCompound = !Character.isWhitespace(source
123: .charAt(i));
124: if (isCompound)
125: return parseCompound(value, source, pos);
126: if (++i >= source.length())
127: return measureOf(value, Unit.ONE); // No unit.
128: pos.setIndex(i); // Skips separator.
129: Unit<?> unit = _unitFormat
130: .parseProductUnit(source, pos);
131: return measureOf(value, unit);
132: } catch (ParseException e) {
133: pos.setIndex(start);
134: pos.setErrorIndex(e.getErrorOffset());
135: return null;
136: }
137: }
138:
139: @SuppressWarnings("unchecked")
140: private Object parseCompound(Number highValue, String source,
141: ParsePosition pos) throws ParseException {
142: Unit high = _unitFormat.parseSingleUnit(source, pos);
143: int i = pos.getIndex();
144: if (i >= source.length()
145: || Character.isWhitespace(source.charAt(i)))
146: return measureOf(highValue, high);
147: Measure lowMeasure = (Measure) parseObject(source, pos);
148: Unit unit = lowMeasure.getUnit();
149: long l = lowMeasure.longValue(unit)
150: + (long) high.getConverterTo(unit).convert(
151: highValue.longValue());
152: return Measure.valueOf(l, unit);
153: }
154:
155: @SuppressWarnings("unchecked")
156: private static Measure measureOf(Number value, Unit unit) {
157: if (value instanceof Double) {
158: return Measure.valueOf(value.doubleValue(), unit);
159: } else if (value instanceof Long) {
160: return Measure.valueOf(value.longValue(), unit);
161: } else if (value instanceof Float) {
162: return Measure.valueOf(value.floatValue(), unit);
163: } else if (value instanceof Integer) {
164: return Measure.valueOf(value.intValue(), unit);
165: } else if (value instanceof BigDecimal) {
166: return DecimalMeasure.valueOf((BigDecimal) value, unit);
167: } else {
168: return Measure.valueOf(value.doubleValue(), unit);
169: }
170: }
171:
172: private static final long serialVersionUID = 1L;
173: }
174: }
|