View Javadoc
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