001 package org.nakedobjects.applib.value;
002
003 import java.math.BigDecimal;
004
005 import org.nakedobjects.applib.annotation.Value;
006
007
008 @Value(semanticsProviderName = "org.nakedobjects.metamodel.value.MoneyValueSemanticsProvider")
009 public class Money extends Magnitude {
010
011 private static final long serialVersionUID = 1L;
012 private static final int[] cents = new int[] { 1, 10, 100, 100 };
013 private final long amount;
014 private final String currency;
015
016 public Money(final double amount, final String currency) {
017 assertCurrencySet(currency);
018 this.currency = currency.toUpperCase();
019 this.amount = Math.round(amount * centFactor());
020 }
021
022 public Money(final long amount, final String currency) {
023 assertCurrencySet(currency);
024 this.currency = currency.toUpperCase();
025 this.amount = amount * centFactor();
026 }
027
028 private void assertCurrencySet(final String currency) {
029 if (currency == null || currency.equals("")) {
030 throw new IllegalArgumentException("Currency must be specified");
031 }
032 if (currency.length() != 3) {
033 throw new IllegalArgumentException("Invalid currency code '" + currency + "'");
034 }
035 }
036
037 /**
038 * Add the specified money to this money.
039 */
040 public Money add(final Money money) {
041 assertSameCurrency(money);
042 return newMoney(amount + money.amount);
043 }
044
045 private void assertSameCurrency(final Money money) {
046 if (!money.getCurrency().equals(getCurrency())) {
047 throw new IllegalArgumentException("Not the same currency: " + getCurrency() + " & " + money.getCurrency());
048 }
049 }
050
051 private int centFactor() {
052 return cents[getFractionalDigits()];
053 }
054
055 /**
056 * Returns this value as a double.
057 */
058 public double doubleValue() {
059 return amount / (double) centFactor();
060 }
061
062 /**
063 * Returns this value as a float.
064 */
065 public float floatValue() {
066 return amount;
067 }
068
069 public BigDecimal getAmount() {
070 return BigDecimal.valueOf(amount, getFractionalDigits());
071 }
072
073 public String getCurrency() {
074 return currency;
075 }
076
077 private int getFractionalDigits() {
078 return 2;
079 }
080
081 public boolean hasSameCurrency(final Money money) {
082 return currency.equals(money.currency);
083 }
084
085 /**
086 * Returns this value as an int.
087 */
088 public int intValue() {
089 return (int) amount;
090 }
091
092 @Override
093 public boolean isEqualTo(final Magnitude magnitude) {
094 if (magnitude instanceof Money && hasSameCurrency((Money) magnitude)) {
095 return ((Money) magnitude).amount == amount;
096 } else {
097 throw new IllegalArgumentException("Parameter must be of type Money and have the same currency");
098 }
099 }
100
101 public boolean isGreaterThanZero() {
102 return amount > 0;
103 }
104
105 @Override
106 public boolean isLessThan(final Magnitude magnitude) {
107 if (magnitude instanceof Money && hasSameCurrency((Money) magnitude)) {
108 return amount < ((Money) magnitude).amount;
109 } else {
110 throw new IllegalArgumentException("Parameter must be of type Money and have the same currency");
111 }
112 }
113
114 /**
115 * Returns true if this value is less than zero.
116 */
117 public boolean isLessThanZero() {
118 return amount < 0;
119 }
120
121 public boolean isZero() {
122 return amount == 0;
123 }
124
125 /**
126 * Returns this value as an long.
127 */
128 public long longValue() {
129 return amount;
130 }
131
132 private Money newMoney(final long amount) {
133 return new Money(amount / (centFactor() * 1.0), this.currency);
134 }
135
136 /**
137 * Subtract the specified amount from this value.
138 */
139 public Money subtract(final Money money) {
140 assertSameCurrency(money);
141 return newMoney(amount - money.amount);
142 }
143
144 @Override
145 public boolean equals(final Object other) {
146 if (this == other) {
147 return true;
148 }
149 if (other == null) {
150 return false;
151 }
152 return other.getClass() == this.getClass() && equals((Money) other);
153 }
154
155 public boolean equals(final Money other) {
156 return other.currency.equals(currency) && other.amount == amount;
157 }
158
159 @Override
160 public int hashCode() {
161 return (int) amount;
162 }
163
164 @Override
165 public String toString() {
166 return amount / (centFactor() * 1.0) + " " + currency;
167 }
168 }
169 // Copyright (c) Naked Objects Group Ltd.