001/*
002 * Copyright (c) 2012, 2013, Credit Suisse (Anatole Tresch), Werner Keil.
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 * 
016 * Contributors: Anatole Tresch - initial implementation.
017 */
018package org.javamoney.moneta.spi;
019
020import java.util.ArrayList;
021import java.util.List;
022
023import javax.money.CurrencyUnit;
024import javax.money.convert.ConversionContext;
025import javax.money.convert.ExchangeRate;
026import javax.money.convert.ExchangeRateProvider;
027import javax.money.convert.ProviderContext;
028
029/**
030 * This class implements a {@link ExchangeRateProvider} that delegates calls to
031 * a collection of child {@link ExchangeRateProvider} instance.
032 * 
033 * @author Anatole Tresch
034 */
035public class CompoundRateProvider extends AbstractRateProvider {
036        /** The {@link ExchangeRateProvider} instances. */
037        private final List<ExchangeRateProvider> providers = new ArrayList<ExchangeRateProvider>();
038
039        /**
040         * Constructor.
041         * 
042         * @param providerContext
043         *            The {@link ProviderContext} this instance is providing.
044         *            Providers added must return the same on
045         *            {@link ProviderContext#getProviderName()}.
046         */
047        public CompoundRateProvider(Iterable<ExchangeRateProvider> providers) {
048                super(createContext(providers));
049                for (ExchangeRateProvider exchangeRateProvider : providers) {
050                        addProvider(exchangeRateProvider);
051                }
052        }
053
054        private static ProviderContext createContext(
055                        Iterable<ExchangeRateProvider> providers) {
056                StringBuilder providerName = new StringBuilder("Compound: ");
057                for (ExchangeRateProvider exchangeRateProvider : providers) {
058                        providerName.append(exchangeRateProvider.getProviderContext()
059                                        .getProviderName());
060                        providerName.append(',');
061                }
062                providerName.setLength(providerName.length() - 1);
063                return new ProviderContext.Builder(providerName.toString()).create();
064        }
065
066        /**
067         * Add an additional {@link ExchangeRateProvider} to the instance's delegate
068         * list. Hereby {@link ExchangeRateProvider#getExchangeRateType()} of the
069         * provider added must be equal to {@link #getExchangeRateType()}.
070         * 
071         * @param prov
072         *            The {@link ExchangeRateProvider} to be added, not {@code null}
073         *            .
074         * @throws IllegalArgumentException
075         *             if {@link ExchangeRateProvider#getExchangeRateType()} of the
076         *             provider added is not equal to {@link #getExchangeRateType()}
077         *             .
078         */
079        private void addProvider(ExchangeRateProvider prov) {
080                if (prov == null) {
081                        throw new IllegalArgumentException("ConversionProvider required.");
082                }
083                providers.add(prov);
084        }
085
086        /*
087         * (non-Javadoc)
088         * 
089         * @see
090         * javax.money.convert.ExchangeRateProvider#getExchangeRate(javax.money.
091         * CurrencyUnit, javax.money.CurrencyUnit,
092         * javax.money.convert.ConversionContext)
093         */
094        @Override
095        protected ExchangeRate getExchangeRateInternal(CurrencyUnit base,
096                        CurrencyUnit term, ConversionContext context) {
097                for (ExchangeRateProvider prov : this.providers) {
098                        if (prov.isAvailable(base, term, context)) {
099                                ExchangeRate rate = prov.getExchangeRate(base, term, context);
100                                if (rate != null) {
101                                        return rate;
102                                }
103                        }
104                }
105                return null;
106        }
107
108}