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.CurrencyUnit;
019import javax.money.MonetaryAmount;
020import javax.money.MonetaryOperator;
021import javax.money.convert.ConversionContext;
022import javax.money.convert.CurrencyConversion;
023import javax.money.convert.CurrencyConversionException;
024import javax.money.convert.ExchangeRate;
025import java.util.Objects;
026
027/**
028 * Abstract base class used for implementing currency conversion.
029 *
030 * @author Anatole Tresch
031 * @author Werner Keil
032 */
033public abstract class AbstractCurrencyConversion implements CurrencyConversion {
034
035    private CurrencyUnit termCurrency;
036    private ConversionContext conversionContext;
037
038    public AbstractCurrencyConversion(CurrencyUnit termCurrency, ConversionContext conversionContext) {
039        Objects.requireNonNull(termCurrency);
040        Objects.requireNonNull(conversionContext);
041        this.termCurrency = termCurrency;
042        this.conversionContext = conversionContext;
043    }
044
045    /**
046     * Access the terminating {@link CurrencyUnit} of this conversion instance.
047     *
048     * @return the terminating {@link CurrencyUnit} , never {@code null}.
049     */
050    @Override
051    public CurrencyUnit getCurrency() {
052        return termCurrency;
053    }
054
055    /**
056     * Access the target {@link ConversionContext} of this conversion instance.
057     *
058     * @return the target {@link ConversionContext}.
059     */
060    @Override
061    public ConversionContext getConversionContext() {
062        return conversionContext;
063    }
064
065    /**
066     * Get the exchange rate type that this {@link MonetaryOperator} instance is
067     * using for conversion.
068     *
069     * @return the {@link ExchangeRate} to be used, or null, if this conversion
070     * is not supported (will lead to a
071     * {@link CurrencyConversionException}.
072     * @see #apply(MonetaryAmount)
073     */
074    @Override
075    public abstract ExchangeRate getExchangeRate(MonetaryAmount amount);
076
077    /*
078     * (non-Javadoc)
079     * @see javax.money.convert.CurrencyConversion#with(javax.money.convert.ConversionContext)
080     */
081    public abstract CurrencyConversion with(ConversionContext conversionContext);
082
083    /**
084     * Method that converts the source {@link MonetaryAmount} to an
085     * {@link MonetaryAmount} based on the {@link ExchangeRate} of this
086     * conversion.
087     *
088     * @param amount The source amount
089     * @return The converted amount, never null.
090     * @throws CurrencyConversionException if conversion failed, or the required data is not available.
091     * @see #getExchangeRate(MonetaryAmount)
092     */
093    @Override
094    public MonetaryAmount apply(MonetaryAmount amount) {
095        if (termCurrency.equals(Objects.requireNonNull(amount).getCurrency())) {
096            return amount;
097        }
098        ExchangeRate rate = getExchangeRate(amount);
099        if (Objects.isNull(rate) || !amount.getCurrency().equals(rate.getBaseCurrency())) {
100            throw new CurrencyConversionException(amount.getCurrency(),
101                    Objects.isNull(rate) ? null : rate.getCurrency(), null);
102        }
103        return amount.multiply(rate.getFactor()).getFactory().setCurrency(rate.getCurrency()).create();
104    }
105
106
107    /*
108     * (non-Javadoc)
109     *
110     * @see java.lang.Object#toString()
111     */
112    @Override
113    public String toString() {
114        return getClass().getName() + " [MonetaryAmount -> MonetaryAmount" + ']';
115    }
116
117}