001/*
002 * Copyright (c) 2012, 2013, 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.util.Objects;
014
015import javax.money.CurrencyUnit;
016import javax.money.MonetaryAmount;
017import javax.money.MonetaryOperator;
018import javax.money.convert.ConversionContext;
019import javax.money.convert.CurrencyConversion;
020import javax.money.convert.CurrencyConversionException;
021import javax.money.convert.ExchangeRate;
022import javax.money.convert.ProviderContext;
023
024import org.javamoney.moneta.BuildableCurrencyUnit;
025
026/**
027 * Abstract base class used for implementing currency conversion.
028 * 
029 * @author Anatole Tresch
030 * @author Werner Keil
031 */
032public abstract class AbstractCurrencyConversion implements CurrencyConversion {
033
034        private CurrencyUnit termCurrency;
035        private ConversionContext conversionContext;
036
037        public AbstractCurrencyConversion(CurrencyUnit termCurrency,
038                        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        public CurrencyUnit getTermCurrency() {
051                return termCurrency;
052        }
053
054        /**
055         * Access the target {@link ConversionContext} of this conversion instance.
056         * 
057         * @return the target {@link ConversionContext}.
058         */
059        public ConversionContext getConversionContext() {
060                return conversionContext;
061        }
062
063        /**
064         * Get the exchange rate type that this {@link MonetaryOperator} instance is
065         * using for conversion.
066         * 
067         * @see #apply(MonetaryAmount)
068         * @return the {@link ExchangeRate} to be used, or null, if this conversion
069         *         is not supported (will lead to a
070         *         {@link CurrencyConversionException}.
071         */
072        @Override
073        public abstract ExchangeRate getExchangeRate(MonetaryAmount amount);
074        
075        /*
076         * (non-Javadoc)
077         * @see javax.money.convert.CurrencyConversion#with(javax.money.convert.ConversionContext)
078         */
079        public abstract CurrencyConversion with(ConversionContext conversionContext);
080
081        /**
082         * Method that converts the source {@link MonetaryAmount} to an
083         * {@link MonetaryAmount} based on the {@link ExchangeRate} of this
084         * conversion.<br/>
085         * 
086         * @see #getExchangeRate(MonetaryAmount)
087         * @param amount
088         *            The source amount
089         * @return The converted amount, never null.
090         * @throws CurrencyConversionException
091         *             if conversion failed, or the required data is not available.
092         */
093        // safe conversion due to MonetaryAmount contract
094        @Override
095        @SuppressWarnings("unchecked")
096        public <T extends MonetaryAmount> T apply(T amount) {
097                ExchangeRate rate = getExchangeRate(amount);
098                if (rate == null || !amount.getCurrency().equals(rate.getBase())) {
099                        throw new CurrencyConversionException(amount.getCurrency(),
100                                        rate == null ? null : rate.getTerm(), null);
101                }
102                return (T) amount
103                                .getFactory()
104                                .setCurrency(rate.getTerm())
105                                .setNumber(
106                                                amount.multiply(rate.getFactor()).getNumber()
107                                                                .numberValue(BigDecimal.class)).create();
108        }
109
110        
111        /*
112         * (non-Javadoc)
113         * 
114         * @see java.lang.Object#toString()
115         */
116        @Override
117        public String toString() {
118                return getClass().getName() + " [MonetaryAmount -> MonetaryAmount"
119                                + "]";
120        }
121
122}