001/* 002 * Copyright (c) 2012, 2014, Credit Suisse (Anatole Tresch), Werner Keil. Licensed under the Apache 003 * License, Version 2.0 (the "License"); you may not use this file except in compliance with the 004 * License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 005 * Unless required by applicable law or agreed to in writing, software distributed under the License 006 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 007 * or implied. See the License for the specific language governing permissions and limitations under 008 * the License. 009 */ 010package org.javamoney.moneta.spi; 011 012import java.math.BigDecimal; 013import java.math.MathContext; 014import java.util.Objects; 015import java.util.logging.Logger; 016 017import javax.money.CurrencyUnit; 018import javax.money.MonetaryCurrencies; 019import javax.money.NumberValue; 020import javax.money.convert.ConversionContext; 021import javax.money.convert.CurrencyConversion; 022import javax.money.convert.CurrencyConversionException; 023import javax.money.convert.ExchangeRate; 024import javax.money.convert.ExchangeRateProvider; 025import javax.money.convert.ProviderContext; 026 027/** 028 * Abstract base class for {@link ExchangeRateProvider} implementations. 029 * 030 * @author Anatole Tresch 031 * @author Werner Keil 032 * 033 */ 034public abstract class AbstractRateProvider implements ExchangeRateProvider { 035 036 /** The logger used. */ 037 protected final Logger LOGGER = Logger.getLogger(getClass().getName()); 038 039 /** The {@link ConversionContext} of this provider. */ 040 private ProviderContext providerContext; 041 042 /** 043 * Constructor. 044 * 045 * @param providerContext 046 * the {@link ProviderContext}, not null. 047 */ 048 public AbstractRateProvider(ProviderContext providerContext) { 049 Objects.requireNonNull(providerContext); 050 this.providerContext = providerContext; 051 } 052 053 protected abstract ExchangeRate getExchangeRateInternal(CurrencyUnit base, 054 CurrencyUnit term, ConversionContext context); 055 056 /* 057 * (non-Javadoc) 058 * 059 * @see javax.money.convert.spi.ExchangeRateProviderSpi#getExchangeRateType 060 * () 061 */ 062 @Override 063 public ProviderContext getProviderContext() { 064 return providerContext; 065 } 066 067 /* 068 * (non-Javadoc) 069 * 070 * @see 071 * javax.money.convert.ExchangeRateProvider#isAvailable(javax.money.CurrencyUnit 072 * , javax.money.CurrencyUnit) 073 */ 074 @Override 075 public boolean isAvailable(CurrencyUnit src, CurrencyUnit target) { 076 return getExchangeRate(src, target) != null; 077 } 078 079 /* 080 * (non-Javadoc) 081 * 082 * @see 083 * javax.money.convert.ExchangeRateProvider#getExchangeRate(javax.money. 084 * CurrencyUnit, javax.money.CurrencyUnit) 085 */ 086 @Override 087 public ExchangeRate getExchangeRate(CurrencyUnit source, CurrencyUnit target) { 088 return getExchangeRate(source, target, ConversionContext.of()); 089 } 090 091 /* 092 * (non-Javadoc) 093 * 094 * @see 095 * javax.money.convert.ExchangeRateProvider#getReversed(javax.money.convert 096 * .ExchangeRate) 097 */ 098 @Override 099 public ExchangeRate getReversed(ExchangeRate rate) { 100 if (isAvailable(rate.getTerm(), rate.getBase(), 101 rate.getConversionContext())) { 102 return getExchangeRate(rate.getTerm(), rate.getBase(), 103 rate.getConversionContext()); 104 } 105 return null; 106 } 107 108 /* 109 * (non-Javadoc) 110 * 111 * @see 112 * javax.money.convert.ExchangeRateProvider#getCurrencyConversion(javax. 113 * money.CurrencyUnit) 114 */ 115 @Override 116 public CurrencyConversion getCurrencyConversion(CurrencyUnit termCurrency) { 117 return new LazyBoundCurrencyConversion(termCurrency, this, 118 ConversionContext.of()); 119 } 120 121 /* 122 * (non-Javadoc) 123 * 124 * @see 125 * javax.money.convert.ExchangeRateProvider#getCurrencyConversion(javax. 126 * money.CurrencyUnit, javax.money.convert.ConversionContext) 127 */ 128 @Override 129 public CurrencyConversion getCurrencyConversion(CurrencyUnit term, 130 ConversionContext conversionContext) { 131 return new LazyBoundCurrencyConversion(term, this, conversionContext); 132 } 133 134 /* 135 * (non-Javadoc) 136 * 137 * @see 138 * javax.money.convert.ExchangeRateProvider#isAvailable(java.lang.String, 139 * java.lang.String) 140 */ 141 @Override 142 public boolean isAvailable(String baseCode, String termCode) { 143 return isAvailable(MonetaryCurrencies.getCurrency(baseCode), 144 MonetaryCurrencies.getCurrency(termCode), 145 ConversionContext.of()); 146 } 147 148 /* 149 * (non-Javadoc) 150 * 151 * @see 152 * javax.money.convert.ExchangeRateProvider#getExchangeRate(java.lang.String 153 * , java.lang.String) 154 */ 155 @Override 156 public ExchangeRate getExchangeRate(String baseCode, String termCode) { 157 return getExchangeRate(MonetaryCurrencies.getCurrency(baseCode), 158 MonetaryCurrencies.getCurrency(termCode), 159 ConversionContext.of()); 160 } 161 162 /* 163 * (non-Javadoc) 164 * 165 * @see 166 * javax.money.convert.ExchangeRateProvider#getCurrencyConversion(java.lang 167 * .String) 168 */ 169 @Override 170 public CurrencyConversion getCurrencyConversion(String termCode) { 171 return getCurrencyConversion(MonetaryCurrencies.getCurrency(termCode)); 172 } 173 174 /* 175 * (non-Javadoc) 176 * 177 * @see 178 * javax.money.convert.ExchangeRateProvider#getCurrencyConversion(java.lang 179 * .String, javax.money.convert.ConversionContext) 180 */ 181 @Override 182 public CurrencyConversion getCurrencyConversion(String termCode, 183 ConversionContext conversionContext) { 184 return getCurrencyConversion(MonetaryCurrencies.getCurrency(termCode), 185 conversionContext); 186 } 187 188 /* 189 * (non-Javadoc) 190 * 191 * @see 192 * javax.money.convert.ExchangeRateProvider#isAvailable(java.lang.String, 193 * java.lang.String, javax.money.convert.ConversionContext) 194 */ 195 @Override 196 public boolean isAvailable(String baseCode, String termCode, 197 ConversionContext conversionContext) { 198 return isAvailable(MonetaryCurrencies.getCurrency(baseCode), 199 MonetaryCurrencies.getCurrency(termCode), conversionContext); 200 } 201 202 /* 203 * (non-Javadoc) 204 * 205 * @see 206 * javax.money.convert.ExchangeRateProvider#getExchangeRate(java.lang.String 207 * , java.lang.String, javax.money.convert.ConversionContext) 208 */ 209 @Override 210 public ExchangeRate getExchangeRate(String baseCode, String termCode, 211 ConversionContext conversionContext) { 212 return getExchangeRate(MonetaryCurrencies.getCurrency(baseCode), 213 MonetaryCurrencies.getCurrency(termCode), conversionContext); 214 } 215 216 /* 217 * (non-Javadoc) 218 * 219 * @see 220 * org.javamoney.moneta.convert.internal.AbstractRateProvider#isAvailable 221 * (javax.money.CurrencyUnit, javax.money.CurrencyUnit, 222 * javax.money.convert.ConversionContext) 223 */ 224 @Override 225 public boolean isAvailable(CurrencyUnit base, CurrencyUnit term, 226 ConversionContext conversionContext) { 227 return getExchangeRateInternal(base, term, 228 conversionContext) != null; 229 } 230 231 /* 232 * (non-Javadoc) 233 * 234 * @see 235 * org.javamoney.moneta.convert.internal.AbstractRateProvider#getExchangeRate 236 * (javax.money.CurrencyUnit, javax.money.CurrencyUnit, 237 * javax.money.convert.ConversionContext) 238 */ 239 @Override 240 public ExchangeRate getExchangeRate(CurrencyUnit base, CurrencyUnit term, 241 ConversionContext conversionContext) { 242 ExchangeRate rate = getExchangeRateInternal(base, term, 243 conversionContext); 244 if (rate == null) { 245 throw new CurrencyConversionException(base, term, conversionContext); 246 } 247 return rate; 248 } 249 250 /** 251 * A protected helper method to multiply 2 {@link NumberValue} types.<br> 252 * If either of the values is <code>null</code> an {@link ArithmeticException} is thrown. 253 * 254 * @param multiplicand the first value to be multiplied 255 * @param multiplier the second value to be multiplied 256 * @return the result of the multiplication as {@link NumberValue} 257 */ 258 protected static final NumberValue multiply(NumberValue multiplicand, NumberValue multiplier) { 259 if (multiplicand == null) { 260 throw new ArithmeticException("The multiplicand cannot be null"); 261 } 262 if (multiplier == null) { 263 throw new ArithmeticException("The multiplier cannot be null"); 264 } 265 return new DefaultNumberValue( 266 multiplicand.numberValue(BigDecimal.class).multiply( 267 multiplier.numberValue(BigDecimal.class))); // TODO should we use numberValueExact? 268 } 269 270 /** 271 * A protected helper method to divide 2 {@link NumberValue} types.<br> 272 * If either of the values is <code>null</code> an {@link ArithmeticException} is thrown. 273 * 274 * @param dividend the first value to be divided 275 * @param divisor the value to be divided by 276 * @return the result of the division as {@link NumberValue} 277 */ 278 protected static final NumberValue divide(NumberValue dividend, NumberValue divisor) { 279 if (dividend == null) { 280 throw new ArithmeticException("The dividend cannot be null"); 281 } 282 if (divisor == null) { 283 throw new ArithmeticException("The divisor cannot be null"); 284 } 285 return new DefaultNumberValue( 286 dividend.numberValue(BigDecimal.class).divide( 287 divisor.numberValue(BigDecimal.class))); // TODO should we use numberValueExact? 288 } 289 290 /** 291 * A protected helper method to divide 2 {@link NumberValue} types.<br> 292 * If either of the values is <code>null</code> an {@link ArithmeticException} is thrown. 293 * 294 * @param dividend the first value to be divided 295 * @param divisor the value to be divided by 296 * @param context the {@link MathContext} to use 297 * @return the result of the division as {@link NumberValue} 298 */ 299 protected static final NumberValue divide(NumberValue dividend, NumberValue divisor, MathContext context) { 300 if (dividend == null) { 301 throw new ArithmeticException("The dividend cannot be null"); 302 } 303 if (divisor == null) { 304 throw new ArithmeticException("The divisor cannot be null"); 305 } 306 return new DefaultNumberValue( 307 dividend.numberValue(BigDecimal.class).divide( 308 divisor.numberValue(BigDecimal.class), context)); // TODO should we use numberValueExact? 309 } 310}