001/**
002 * Copyright (c) 2012, 2014, Credit Suisse (Anatole Tresch), Werner Keil and others by the @author tag.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005 * use this file except in compliance with the License. You may obtain a copy of
006 * the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013 * License for the specific language governing permissions and limitations under
014 * the License.
015 */
016package org.javamoney.moneta.spi;
017
018import javax.money.NumberValue;
019import javax.money.convert.*;
020
021import java.math.BigDecimal;
022import java.math.MathContext;
023import java.util.Objects;
024import java.util.logging.Logger;
025
026/**
027 * Abstract base class for {@link ExchangeRateProvider} implementations.
028 *
029 * @author Anatole Tresch
030 * @author Werner Keil
031 */
032public abstract class AbstractRateProvider implements ExchangeRateProvider {
033
034    /**
035     * The logger used.
036     */
037    protected final Logger log = Logger.getLogger(getClass().getName());
038
039    /**
040     * The {@link ConversionContext} of this provider.
041     */
042    private final ProviderContext providerContext;
043
044    /**
045     * Constructor.
046     *
047     * @param providerContext the {@link ProviderContext}, not null.
048     */
049    public AbstractRateProvider(ProviderContext providerContext) {
050        Objects.requireNonNull(providerContext);
051        this.providerContext = providerContext;
052    }
053
054    /*
055     * (non-Javadoc)
056     *
057     * @see javax.money.convert.spi.ExchangeRateProviderSpi#getExchangeRateType
058     * ()
059     */
060    @Override
061    public ProviderContext getContext() {
062        return providerContext;
063    }
064
065    @Override
066    public abstract ExchangeRate getExchangeRate(ConversionQuery conversionQuery);
067
068    @Override
069    public CurrencyConversion getCurrencyConversion(ConversionQuery conversionQuery) {
070        if (getContext().getRateTypes().size() == 1) {
071            return new LazyBoundCurrencyConversion(conversionQuery, this, ConversionContext
072                    .of(getContext().getProviderName(), getContext().getRateTypes().iterator().next()));
073        }
074        return new LazyBoundCurrencyConversion(conversionQuery, this,
075                ConversionContext.of(getContext().getProviderName(), RateType.ANY));
076    }
077
078
079    /**
080     * A protected helper method to multiply 2 {@link NumberValue} types.<br>
081     * If either of the values is <code>null</code> an {@link ArithmeticException} is thrown.
082     *
083     * @param multiplicand the first value to be multiplied
084     * @param multiplier   the second value to be multiplied
085     * @return the result of the multiplication as {@link NumberValue}
086     */
087    protected static NumberValue multiply(NumberValue multiplicand, NumberValue multiplier) {
088        if (Objects.isNull(multiplicand)) {
089            throw new ArithmeticException("The multiplicand cannot be null");
090        }
091        if (Objects.isNull(multiplier)) {
092            throw new ArithmeticException("The multiplier cannot be null");
093        }
094        return new DefaultNumberValue(
095                multiplicand.numberValueExact(BigDecimal.class).multiply(multiplier.numberValue(BigDecimal.class)));
096    }
097
098    /**
099     * A protected helper method to divide 2 {@link NumberValue} types.<br>
100     * If either of the values is <code>null</code> an {@link ArithmeticException} is thrown.
101     *
102     * @param dividend the first value to be divided
103     * @param divisor  the value to be divided by
104     * @return the result of the division as {@link NumberValue}
105     */
106    protected static NumberValue divide(NumberValue dividend, NumberValue divisor) {
107        if (Objects.isNull(dividend)) {
108            throw new ArithmeticException("The dividend cannot be null");
109        }
110        if (Objects.isNull(divisor)) {
111            throw new ArithmeticException("The divisor cannot be null");
112        }
113        return new DefaultNumberValue(
114                dividend.numberValueExact(BigDecimal.class).divide(divisor.numberValue(BigDecimal.class),
115                        MathContext.DECIMAL64));
116    }
117
118    /**
119     * A protected helper method to divide 2 {@link NumberValue} types.<br>
120     * If either of the values is <code>null</code> an {@link ArithmeticException} is thrown.
121     *
122     * @param dividend the first value to be divided
123     * @param divisor  the value to be divided by
124     * @param context  the {@link MathContext} to use
125     * @return the result of the division as {@link NumberValue}
126     */
127    protected static NumberValue divide(NumberValue dividend, NumberValue divisor, MathContext context) {
128        if (Objects.isNull(dividend)) {
129            throw new ArithmeticException("The dividend cannot be null");
130        }
131        if (Objects.isNull(divisor)) {
132            throw new ArithmeticException("The divisor cannot be null");
133        }
134        return new DefaultNumberValue(
135                dividend.numberValueExact(BigDecimal.class).divide(divisor.numberValue(BigDecimal.class), context));
136    }
137}