001: /*
002: Copyright (C) 2006 Know Gate S.L. All rights reserved.
003: C/Oña, 107 1º2 28050 Madrid (Spain)
004:
005: Redistribution and use in source and binary forms, with or without
006: modification, are permitted provided that the following conditions
007: are met:
008:
009: 1. Redistributions of source code must retain the above copyright
010: notice, this list of conditions and the following disclaimer.
011:
012: 2. The end-user documentation included with the redistribution,
013: if any, must include the following acknowledgment:
014: "This product includes software parts from hipergate
015: (http://www.hipergate.org/)."
016: Alternately, this acknowledgment may appear in the software itself,
017: if and wherever such third-party acknowledgments normally appear.
018:
019: 3. The name hipergate must not be used to endorse or promote products
020: derived from this software without prior written permission.
021: Products derived from this software may not be called hipergate,
022: nor may hipergate appear in their name, without prior written
023: permission.
024:
025: This library is distributed in the hope that it will be useful,
026: but WITHOUT ANY WARRANTY; without even the implied warranty of
027: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
028:
029: You should have received a copy of hipergate License with this code;
030: if not, visit http://www.hipergate.org or mail to info@hipergate.org
031: */
032:
033: package com.knowgate.math;
034:
035: import java.math.BigInteger;
036: import java.math.BigDecimal;
037:
038: import java.text.DecimalFormat;
039: import java.text.FieldPosition;
040: import java.text.NumberFormat;
041:
042: import java.util.Currency;
043:
044: import com.knowgate.misc.Gadgets;
045: import java.util.Locale;
046:
047: import com.knowgate.misc.Gadgets;
048:
049: /**
050: * <p>Combination of BigDecimal with Currency Sign</p>
051: * This class handles money amounts that include a currency sign
052: * @author Sergio Montoro Ten
053: * @version 1.0
054: */
055: public class Money extends BigDecimal {
056:
057: private static final DecimalFormat FMT2 = new DecimalFormat("#0.00");
058: private static final FieldPosition FRAC = new FieldPosition(
059: NumberFormat.FRACTION_FIELD);
060:
061: private CurrencyCode oCurrCode;
062:
063: // ---------------------------------------------------------------------------
064:
065: private Money(String sVal) throws UnsupportedOperationException {
066: super (sVal);
067: throw new UnsupportedOperationException(
068: "Money(String) is not an allowed constructor");
069: }
070:
071: // ---------------------------------------------------------------------------
072:
073: public Money(Money oVal) {
074: super (((BigDecimal) oVal).toString());
075: oCurrCode = oVal.oCurrCode;
076: }
077:
078: // ---------------------------------------------------------------------------
079:
080: /**
081: * Constructor
082: * @param sVal String Numeric value in US decimal format (using dot as decimal delimiter)
083: * @param oCur CurrencyCode
084: * @throws NumberFormatException
085: */
086: public Money(String sVal, CurrencyCode oCur)
087: throws NumberFormatException {
088: super (sVal);
089: oCurrCode = oCur;
090: }
091:
092: // ---------------------------------------------------------------------------
093:
094: /**
095: * Constructor
096: * @param sVal String Numeric value in US decimal format (using dot as decimal delimiter)
097: * @param sCur String Currency alphanumeric code {"USD", "EUR", etc.}
098: * @throws NumberFormatException
099: * @throws IllegalArgumentException
100: */
101: public Money(String sVal, String sCur)
102: throws NumberFormatException, IllegalArgumentException {
103: super (sVal);
104: oCurrCode = CurrencyCode.currencyCodeFor(sCur);
105: if (null == oCurrCode)
106: throw new IllegalArgumentException("Money() " + sCur
107: + " is not a legal currency alphanumeric code");
108: oCurrCode = CurrencyCode.currencyCodeFor(sCur);
109: }
110:
111: // ---------------------------------------------------------------------------
112:
113: /**
114: * Constructor
115: * @param dVal double
116: * @param oCur CurrencyCode
117: */
118: public Money(double dVal, CurrencyCode oCur) {
119: super (dVal);
120: oCurrCode = oCur;
121: }
122:
123: // ---------------------------------------------------------------------------
124:
125: /**
126: * Constructor
127: * @param dVal double
128: * @param sCur String Currency alphanumeric code {"USD", "EUR", etc.}
129: * @throws IllegalArgumentException
130: */
131: public Money(double dVal, String sCur)
132: throws IllegalArgumentException {
133: super (dVal);
134: oCurrCode = CurrencyCode.currencyCodeFor(sCur);
135: }
136:
137: // ---------------------------------------------------------------------------
138:
139: public Money(BigDecimal oVal, CurrencyCode oCur) {
140: super (oVal.toString());
141: oCurrCode = oCur;
142: }
143:
144: // ---------------------------------------------------------------------------
145:
146: public Money(BigDecimal oVal, String sCur) {
147: super (oVal.toString());
148: oCurrCode = CurrencyCode.currencyCodeFor(sCur);
149: }
150:
151: // ---------------------------------------------------------------------------
152:
153: public Money(BigInteger oVal, CurrencyCode oCur) {
154: super (oVal);
155: oCurrCode = oCur;
156: }
157:
158: // ---------------------------------------------------------------------------
159:
160: public Money(BigInteger oVal, String sCur) {
161: super (oVal);
162: oCurrCode = CurrencyCode.currencyCodeFor(sCur);
163: }
164:
165: // ---------------------------------------------------------------------------
166:
167: public CurrencyCode currencyCode() {
168: return oCurrCode;
169: }
170:
171: // ---------------------------------------------------------------------------
172:
173: public static boolean isMoney(String sVal) {
174: if (sVal == null)
175: return false;
176: if (sVal.length() == 0)
177: return false;
178: String sAmount = sVal.toUpperCase();
179: int iDot = sAmount.indexOf('.');
180: int iCom = sAmount.indexOf(',');
181: if (iDot != 0 && iCom != 0) {
182: if (iDot > iCom) {
183: Gadgets.removeChar(sAmount, ',');
184: } else {
185: Gadgets.removeChar(sAmount, '.');
186: }
187: } // fi
188: sAmount = sAmount.replace(',', '.');
189: sAmount = Gadgets.removeChars(sAmount,
190: "€$£¤¢¥#ƒ& ABCDEFGHIJKLMNOPQRSZUVWXYZ");
191: boolean bMatch = false;
192: try {
193: bMatch = Gadgets.matches(sAmount,
194: "([0-9]+)|([0-9]+.[0-9]+)");
195: } catch (org.apache.oro.text.regex.MalformedPatternException neverthrown) {
196: }
197: return bMatch;
198: } // isMoney
199:
200: // ---------------------------------------------------------------------------
201:
202: public static Money parse(String sVal) throws NullPointerException,
203: IllegalArgumentException, NumberFormatException {
204: int iDot, iCom;
205: CurrencyCode oCur = null;
206: String sAmount;
207:
208: if (null == sVal)
209: throw new NullPointerException(
210: "Money.parse() argument cannot be null");
211: if (sVal.length() == 0)
212: throw new IllegalArgumentException(
213: "Money.parse() argument cannot be an empty string");
214:
215: sAmount = sVal.toUpperCase();
216: if (sAmount.indexOf("EUR") >= 0 || sAmount.indexOf("€") >= 0
217: || sAmount.indexOf("€") >= 0)
218: oCur = CurrencyCode.EUR;
219: else if (sAmount.indexOf("USD") >= 0
220: || sAmount.indexOf("$") >= 0)
221: oCur = CurrencyCode.USD;
222: else if (sAmount.indexOf("GBP") >= 0
223: || sAmount.indexOf("£") >= 0)
224: oCur = CurrencyCode.GBP;
225: else if (sAmount.indexOf("JPY") >= 0
226: || sAmount.indexOf("YEN") >= 0
227: || sAmount.indexOf("¥") >= 0)
228: oCur = CurrencyCode.JPY;
229: else if (sAmount.indexOf("CNY") >= 0
230: || sAmount.indexOf("YUAN") >= 0)
231: oCur = CurrencyCode.CNY;
232:
233: iDot = sAmount.indexOf('.');
234: iCom = sAmount.indexOf(',');
235:
236: if (iDot != 0 && iCom != 0) {
237: if (iDot > iCom) {
238: Gadgets.removeChar(sAmount, ',');
239: } else {
240: Gadgets.removeChar(sAmount, '.');
241: }
242: } // fi
243:
244: sAmount = sAmount.replace(',', '.');
245: sAmount = Gadgets.removeChars(sAmount,
246: "€$£¤¢¥#ƒ& ABCDEFGHIJKLMNOPQRSZUVWXYZ");
247:
248: return new Money(sAmount, oCur);
249: } // parse
250:
251: // ---------------------------------------------------------------------------
252:
253: /**
254: * Rounds a BigDecimal value to two decimals
255: * @return BigDecimal
256: */
257: public Money round2() {
258: StringBuffer oBuffer = new StringBuffer();
259: FMT2.format(doubleValue(), oBuffer, FRAC);
260: return new Money(oBuffer.toString(), oCurrCode);
261: }
262:
263: // ---------------------------------------------------------------------------
264:
265: /**
266: * <p>Convert <b>this</b> money to another currency</p>
267: * @param oTarget Target CurrencyCode
268: * @param oRatio BigDecimal Conversion ratio
269: * @return Money if <b>this</b> CurrencyCode is the same as oTarget
270: * then <b>this</b> is returned without any modification,
271: * if if <b>this</b> CurrencyCode is different from oTarget
272: * then the returned value is <b>this</b> multiplied by oRatio.
273: * @throws NullPointerException if oTarget is <b>null</b>
274: */
275: public Money convertTo(CurrencyCode oTarget, BigDecimal oRatio)
276: throws NullPointerException {
277:
278: Money oNewVal;
279:
280: if (oTarget == null)
281: throw new NullPointerException(
282: "Money.convertTo() target currency cannot be null");
283:
284: if (oCurrCode != null) {
285: if (oCurrCode.equals(oTarget))
286: oNewVal = this ;
287: else
288: oNewVal = new Money(multiply(oRatio), oTarget);
289: } else {
290: oNewVal = new Money(multiply(oRatio), oTarget);
291: }
292: return oNewVal;
293: } // convertTo
294:
295: // ---------------------------------------------------------------------------
296:
297: /**
298: * Format a BigDecimal as a String following the rules for an specific language and country
299: * @param sLanguage String ISO-639 two letter language code
300: * @param sCountry String ISO-3166 two leter country code
301: * @return String
302: */
303:
304: public String format(String sLanguage, String sCountry) {
305:
306: Locale oLoc;
307: if (null == sCountry)
308: sCountry = oCurrCode.countryCode();
309:
310: if (null != sLanguage && null != sCountry)
311: oLoc = new Locale(sLanguage, sCountry);
312: else if (null != sLanguage)
313: oLoc = new Locale(sLanguage);
314: else
315: oLoc = Locale.getDefault();
316: NumberFormat oFmtC = NumberFormat.getCurrencyInstance(oLoc);
317: oFmtC.setCurrency(currencyCode().currency());
318: return oFmtC.format(doubleValue());
319: } // format
320:
321: // ---------------------------------------------------------------------------
322:
323: public String toString() {
324: if (oCurrCode == null)
325: return super .toString();
326: else
327: return super .toString() + " " + oCurrCode.alphaCode();
328: }
329:
330: // ---------------------------------------------------------------------------
331:
332: }
|