1 /***
2 * Copyright (c) 2002, CodeStreet LLC. All rights reserved.<p>
3 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
4 * conditions are met:<p>
5 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
6 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
7 * in the documentation and/or other materials provided with the distribution. Neither the name of CodeStreet LLC. nor the
8 * names of its contributors may be used to endorse or promote products derived from this software without specific prior written
9 * permission.<p>
10 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
11 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
12 * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
13 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
15 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.<p>
16 */
17
18 package com.codestreet.messageforge;
19
20 import java.math.*;
21 import java.util.Currency;
22
23 /***
24 * Class to represent a <tt>Money</tt> field. The motivation and
25 * implementation of this data type comes from the book <tt>Patterns
26 * of Enterprise Application Architecture</tt>
27 * by <tt>Martin Fowler</tt>.
28 *
29 * @author Jawaid Hakim.
30 */
31 public class RMoney implements Comparable
32 {
33 /***
34 * Factory.
35 * @param amount USD amount.
36 * @return New instance.
37 */
38 public static RMoney valueOfDollar(long amount)
39 {
40 return new RMoney(amount, Currency.getInstance("USD"));
41 }
42
43 /***
44 * Factory.
45 * @param amount USD amount.
46 * @return New instance.
47 */
48 public static RMoney valueOfDollar(double amount)
49 {
50 return new RMoney(amount, Currency.getInstance("USD"));
51 }
52
53 /***
54 * Factory.
55 * @param amount Amount in specified currency.
56 * @param currency Currency.
57 * @return New instance.
58 */
59 public static RMoney valueOf(long amount, Currency currency)
60 {
61 return new RMoney(amount, currency);
62 }
63
64 /***
65 * Factory.
66 * @param amount Amount in specified currency.
67 * @param currency Currency.
68 * @return New instance.
69 */
70 public static RMoney valueOf(double amount, Currency currency)
71 {
72 return new RMoney(amount, currency);
73 }
74
75 /***
76 * Ctor.
77 * @param amount Amount in specified currency.
78 * @param currency Currency.
79 * @return New instance.
80 */
81 RMoney(long amount, Currency currency, int centFactor)
82 {
83 currency_ = currency;
84 amount_ = amount * centFactor;
85 }
86
87 /***
88 * Ctor.
89 * @param amount Amount in specified currency.
90 * @param currency Currency.
91 * @return New instance.
92 */
93 private RMoney(long amount, Currency currency)
94 {
95 currency_ = currency;
96 amount_ = amount * centFactor();
97 }
98
99 /***
100 * Ctor.
101 * @param amount Amount in specified currency.
102 * @param currency Currency.
103 * @return New instance.
104 */
105 private RMoney(double amount, Currency currency)
106 {
107 currency_ = currency;
108 amount_ = Math.round(amount * centFactor());
109 }
110
111 /***
112 * Get amount.
113 * @return Amount.
114 */
115 public BigDecimal getAmount()
116 {
117 return BigDecimal.valueOf(
118 amount_,
119 currency_.getDefaultFractionDigits());
120 }
121
122 /***
123 * Get amount as a <tt>long</tt>.
124 * @return Amount as <tt>long</tt>.
125 */
126 public long longValue()
127 {
128 return amount_;
129 }
130
131 /***
132 * Get currency.
133 * @return Currency.
134 */
135 public Currency getCurrency()
136 {
137 return currency_;
138 }
139
140 /***
141 * Override.
142 * @return Returns <tt>true</tt> if both currency and amount
143 * and equal.
144 */
145 public boolean equals(Object another)
146 {
147 return (another instanceof RMoney) && equals((RMoney) another);
148 }
149
150 /***
151 * Equals.
152 * @return Returns <tt>true</tt> if both currency and amount
153 * and equal.
154 */
155 public boolean equals(RMoney another)
156 {
157 return currency_.equals(another.getCurrency())
158 && (amount_ == another.longValue());
159 }
160
161 /***
162 * Override.
163 * @return Hash code.
164 */
165 public int hashCode()
166 {
167 return (int) (amount_ ^ (amount_ >>> 32));
168 }
169
170 /***
171 * Addition operator.
172 * @param another Argument.
173 * @return New instance.
174 */
175 public RMoney add(RMoney another)
176 {
177 if (!currency_.equals(another.getCurrency()))
178 throw new IllegalArgumentException(
179 "Currency mismatch: "
180 + currency_.toString()
181 + ", "
182 + another.getCurrency().toString());
183 return newMoney(amount_ + another.longValue());
184 }
185
186 /***
187 * Subtraction operator.
188 * @param another Argument.
189 * @return New instance.
190 */
191 public RMoney subtract(RMoney another)
192 {
193 if (!currency_.equals(another.getCurrency()))
194 throw new IllegalArgumentException(
195 "Currency mismatch: "
196 + currency_.toString()
197 + ", "
198 + another.getCurrency().toString());
199 return newMoney(amount_ - another.longValue());
200 }
201
202 /***
203 * Multiplication operator.
204 * @param amount Amount to multiple by.
205 * @return New instance.
206 */
207 public RMoney multiply(double amount)
208 {
209 return multiply(new BigDecimal(amount));
210 }
211
212 /***
213 * Multiplication operator.
214 * @param amount Amount to multiple by.
215 * @return New instance.
216 */
217 public RMoney multiply(RMoney amount)
218 {
219 return multiply(amount.getAmount());
220 }
221
222 /***
223 * Multiplication operator.
224 * @param amount Amount to multiple by.
225 * @return New instance.
226 */
227 public RMoney multiply(BigDecimal amount)
228 {
229 return RMoney.valueOf(
230 getAmount().multiply(amount).longValue(),
231 currency_);
232 }
233
234 /***
235 * Division operator.
236 * @param amount Amount to divide by.
237 * @return New instance.
238 */
239 public RMoney divide(double amount)
240 {
241 return divide(new BigDecimal(amount));
242 }
243
244 /***
245 * Division operator.
246 * @param amount Amount to divide by.
247 * @return New instance.
248 */
249 public RMoney divide(BigDecimal amount)
250 {
251 return divide(amount, BigDecimal.ROUND_HALF_EVEN);
252 }
253
254 /***
255 * Division operator.
256 * @param amount Amount to divide by.
257 * @return New instance.
258 */
259 public RMoney divide(RMoney amount)
260 {
261 return divide(amount.getAmount());
262 }
263
264 /***
265 * Division operator.
266 * @param amount Amount to divide by.
267 * @param roundingMode Rounding mode. See <tt>BigDecimal</tt> for
268 * details.
269 * @return New instance.
270 */
271 public RMoney divide(BigDecimal amount, int roundingMode)
272 {
273 return RMoney.valueOf(
274 getAmount().divide(amount, roundingMode).longValue(),
275 getCurrency());
276 }
277
278 /***
279 * Interface implementation.
280 * @param another Argument.
281 * @return Returns <tt>0</tt>, <tt>1</tt>, or <tt>-1</tt> depending on
282 * whether the argument is equal to, greater than, or less than this.
283 */
284 public int compareTo(Object another)
285 {
286 return compareTo((RMoney) another);
287 }
288
289 /***
290 * Interface implementation.
291 * @param another Argument.
292 * @return Returns <tt>0</tt>, <tt>1</tt>, or <tt>-1</tt> depending on
293 * whether the argument is equal to, greater than, or less than this.
294 */
295 public int compareTo(RMoney another)
296 {
297 if (!currency_.equals(another.getCurrency()))
298 throw new IllegalArgumentException(
299 "Currency mismatch: "
300 + currency_.toString()
301 + ", "
302 + another.getCurrency().toString());
303
304 if (amount_ < another.longValue())
305 return -1;
306 else if (amount_ == another.longValue())
307 return 0;
308 else
309 return 1;
310 }
311
312 /***
313 * Allocate amount in specified ratios.
314 * @param ratios Ratios. Sum of ratios must be greater than <tt>0</tt>.
315 * @return Amount of this instance allocated in specified ratios.
316 */
317 public RMoney[] allocate(long[] ratios)
318 {
319 if (ratios == null)
320 throw new NullPointerException("Null pointer");
321
322 long total = 0;
323 for (int i = 0; i < ratios.length; ++i)
324 {
325 total += ratios[i];
326 }
327 if (total <= 0)
328 throw new IllegalArgumentException("Sum of ratios is 0");
329
330 long rem = longValue();
331 RMoney[] results = new RMoney[ratios.length];
332 for (int i = 0; i < results.length; ++i)
333 {
334 results[i] = newMoney(longValue() * ratios[i] / total);
335 rem -= results[i].longValue();
336 }
337 for (int i = 0; i < rem; ++i)
338 {
339 results[i] = newMoney(results[i].longValue() + 1);
340 }
341 return results;
342 }
343
344 private RMoney newMoney(long amount)
345 {
346 return new RMoney(amount, currency_, 1);
347 }
348
349 private int centFactor()
350 {
351 int index = currency_.getDefaultFractionDigits();
352 return cents[index];
353 }
354
355 private static final int[] cents = { 1, 10, 100, 1000 };
356 private long amount_;
357 private Currency currency_;
358 }
This page was automatically generated by Maven