001: /*
002: * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
003: * Copyright (C) 2006 - 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 org.jscience.economics.money;
010:
011: import javolution.context.LocalContext;
012: import javolution.util.LocalMap;
013:
014: import javax.measure.converter.ConversionException;
015: import javax.measure.converter.UnitConverter;
016: import javax.measure.unit.DerivedUnit;
017: import javax.measure.unit.Unit;
018: import javax.measure.unit.UnitFormat;
019:
020: /**
021: * <p> This class represents a currency {@link javax.measure.unit.Unit Unit}.
022: * Currencies are a special form of {@link DerivedUnit}, conversions
023: * between currencies is possible if their respective exchange rates
024: * have been set and the conversion factor can be changed dynamically.</p>
025: *
026: * <p> Quantities stated in {@link Currency} are usually instances of
027: * {@link Money}.</p>
028: *
029: * <p> By default, the label associated to a currency is its ISO-4217 code
030: * (see the <a href="http://www.bsi-global.com/iso4217currency"> ISO 4217
031: * maintenance agency</a> for a table of currency codes). An application may
032: * change this default using the {@link javax.measure.unit.UnitFormat#label
033: * UnitFormat.label(String)} method.
034: * For example:[code]
035: * UnitFormat.getStandardInstance().label(Currency.EUR, "€");
036: * UnitFormat.getStandardInstance().label(Currency.GBP, "£");
037: * UnitFormat.getStandardInstance().label(Currency.JPY, "¥");
038: * UnitFormat.getStandardInstance().label(Currency.USD, "$");
039: * [/code]</p>
040: *
041: * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
042: * @version 3.0, February 13, 2006
043: * @see #setExchangeRate
044: */
045: public class Currency extends DerivedUnit<Money> {
046:
047: /**
048: * The Australian Dollar currency unit.
049: */
050: public static final Currency AUD = new Currency("AUD");
051:
052: /**
053: * The Canadian Dollar currency unit.
054: */
055: public static final Currency CAD = new Currency("CAD");
056:
057: /**
058: * The China Yan currency.
059: */
060: public static final Currency CNY = new Currency("CNY");
061:
062: /**
063: * The Euro currency.
064: */
065: public static final Currency EUR = new Currency("EUR");
066:
067: /**
068: * The British Pound currency.
069: */
070: public static final Currency GBP = new Currency("GBP");
071:
072: /**
073: * The Japanese Yen currency.
074: */
075: public static final Currency JPY = new Currency("JPY");
076:
077: /**
078: * The Korean Republic Won currency.
079: */
080: public static final Currency KRW = new Currency("KRW");
081:
082: /**
083: * The Taiwanese dollar currency.
084: */
085: public static final Currency TWD = new Currency("TWD");
086:
087: /**
088: * The United State dollar currency.
089: */
090: public static final Currency USD = new Currency("USD");
091:
092: /**
093: * Holds the reference currency.
094: */
095: private static final LocalContext.Reference<Currency> REFERENCE = new LocalContext.Reference<Currency>();
096:
097: /**
098: * Holds the exchanges rate to the reference currency.
099: */
100: private static final LocalMap<String, Double> TO_REFERENCE = new LocalMap<String, Double>();
101:
102: /**
103: * Holds the converter to the {@link Money#BASE_UNIT money base unit}.
104: */
105: private final Converter _toBaseUnit;
106:
107: /**
108: * Creates the currency unit for the given currency code.
109: * See the <a href="http://www.bsi-global.com/iso4217currency"> ISO 4217
110: * maintenance agency</a> for more information, including a table of
111: * currency codes.
112: *
113: * @param code the ISO-4217 code of the currency (e.g.
114: * <code>"EUR", "USD", "JPY"</code>).
115: * @throws IllegalArgumentException if the specified code is not an ISO-4217
116: * code.
117: */
118: public Currency(String code) {
119: _toBaseUnit = new Converter(code, false);
120: UnitFormat.getInstance().label(this , code);
121: }
122:
123: /**
124: * Returns the currency code for this currency.
125: *
126: * @return the ISO-4217 code of the currency
127: * (e.g. <code>"EUR", "USD", "JPY"</code>).
128: */
129: public String getCode() {
130: return _toBaseUnit._code;
131: }
132:
133: /**
134: * Returns the default number of fraction digits used with this currency
135: * unit. For example, the default number of fraction digits for
136: * the {@link Currency#EUR} is 2, while for the {@link Currency#JPY} (Yen)
137: * it's 0. This method can be overriden for custom currencies returning
138: * values different from <code>2</code>.
139: *
140: * @return the default number of fraction digits for this currency.
141: */
142: public int getDefaultFractionDigits() {
143: return (this .equals(JPY) || (this .equals(KRW))) ? 0 : 2;
144: }
145:
146: /**
147: * Sets the reference currency (context-local). Changing the
148: * reference currency clears all the exchange rates previously set.
149: *
150: * @param currency the new reference currency.
151: * @see javolution.context.LocalContext
152: */
153: public static void setReferenceCurrency(Currency currency) {
154: REFERENCE.set(currency);
155: TO_REFERENCE.clear();
156: TO_REFERENCE.put(currency.getCode(), 1.0);
157: }
158:
159: /**
160: * Returns the currency used as reference when setting the exchange rate.
161: * By default, the reference currency is the currency for the default
162: * country locale.
163: *
164: * @return the reference currency.
165: * @see #setExchangeRate
166: */
167: public static Currency getReferenceCurrency() {
168: return REFERENCE.get();
169: }
170:
171: /**
172: * Sets the exchange rate of this {@link Currency} relatively to
173: * the reference currency. Setting the exchange rate allows
174: * for conversion between {@link Money} stated in different currencies.
175: * For example:<pre>
176: * Currency.setReferenceCurrency(Currency.USD);
177: * Currency.EUR.setExchangeRate(1.17); // 1.0 € = 1.17 $
178: * </pre>
179: *
180: * @param refAmount the amount stated in the {@link #getReferenceCurrency}
181: * equals to one unit of this {@link Currency}.
182: * @see #getReferenceCurrency
183: */
184: public void setExchangeRate(double refAmount) {
185: TO_REFERENCE.put(this .getCode(), refAmount);
186: }
187:
188: /**
189: * Returns the exchange rate for this {@link Currency}.
190: *
191: * @return the amount stated in the {@link #getReferenceCurrency}
192: * equals to one unit of this {@link Currency}.
193: * @throws ConversionException if the exchange rate has not be set for
194: * this {@link Currency}.
195: */
196: public double getExchangeRate() {
197: Double refAmount = TO_REFERENCE.get(this .getCode());
198: if (refAmount == null)
199: throw new ConversionException("Exchange rate not set for "
200: + this .getCode());
201: return refAmount.doubleValue();
202: }
203:
204: @Override
205: public boolean equals(Object obj) {
206: if (this == obj)
207: return true;
208: if (!(obj instanceof Currency))
209: return false;
210: Currency that = (Currency) obj;
211: return this ._toBaseUnit.equals(that._toBaseUnit);
212: }
213:
214: @Override
215: public int hashCode() {
216: return _toBaseUnit.hashCode();
217: }
218:
219: @Override
220: public Unit<? super Money> getStandardUnit() {
221: return Money.BASE_UNIT;
222: }
223:
224: @Override
225: public UnitConverter toStandardUnit() {
226: return _toBaseUnit;
227: }
228:
229: /**
230: * This class represents the currency converters.
231: */
232: private static class Converter extends UnitConverter {
233:
234: String _code;
235:
236: boolean _invert;
237:
238: private Converter(String code, boolean invert) {
239: _code = code;
240: _invert = invert;
241: }
242:
243: @Override
244: public UnitConverter inverse() {
245: return new Converter(_code, !_invert);
246: }
247:
248: @Override
249: public double convert(double x) throws ConversionException {
250: Double refAmount = TO_REFERENCE.get(_code);
251: if (refAmount == null)
252: throw new ConversionException(
253: "Exchange rate not set for " + _code);
254: return _invert ? x / refAmount.doubleValue() : x
255: * refAmount.doubleValue();
256: }
257:
258: @Override
259: public boolean isLinear() {
260: return true;
261: }
262:
263: @Override
264: public boolean equals(Object obj) {
265: if (this == obj)
266: return true;
267: if (!(obj instanceof Converter))
268: return false;
269: Converter that = (Converter) obj;
270: return this ._code.equals(that._code)
271: && (this ._invert == that._invert);
272: }
273:
274: @Override
275: public int hashCode() {
276: return _invert ? _code.hashCode() : -_code.hashCode();
277: }
278:
279: private static final long serialVersionUID = 1L;
280: }
281:
282: private static final long serialVersionUID = 1L;
283: }
|