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.convert.ConversionQuery;
019import javax.money.convert.ExchangeRate;
020import javax.money.convert.ExchangeRateProvider;
021import javax.money.convert.ProviderContext;
022import javax.money.convert.ProviderContextBuilder;
023import javax.money.convert.RateType;
024
025import java.util.*;
026
027/**
028 * This class implements a {@link ExchangeRateProvider} that delegates calls to
029 * a collection of child {@link ExchangeRateProvider} instance.
030 *
031 * @author Anatole Tresch
032 */
033public class CompoundRateProvider extends AbstractRateProvider {
034    /**
035     * Kery used to store a list of child {@link javax.money.convert.ProviderContext} instances of the providers
036     * contained within this instance.
037     */
038    public static final String CHILD_PROVIDER_CONTEXTS_KEY = "childProviderContexts";
039    /**
040     * The {@link ExchangeRateProvider} instances.
041     */
042    private final List<ExchangeRateProvider> providers = new ArrayList<>();
043
044    /**
045     * Constructor.
046     *
047     * @param providers The collection of child {@link ExchangeRateProvider}
048     *                  instances this class delegates calls to.
049     */
050    public CompoundRateProvider(Iterable<ExchangeRateProvider> providers) {
051        super(createContext(providers));
052        for (ExchangeRateProvider exchangeRateProvider : providers) {
053            addProvider(exchangeRateProvider);
054        }
055    }
056
057    private static ProviderContext createContext(Iterable<ExchangeRateProvider> providers) {
058        Set<RateType> rateTypeSet = new HashSet<>();
059        StringBuilder providerName = new StringBuilder("Compound: ");
060        List<ProviderContext> childContextList = new ArrayList<>();
061        for (ExchangeRateProvider exchangeRateProvider : providers) {
062            childContextList.add(exchangeRateProvider.getContext());
063            providerName.append(exchangeRateProvider.getContext().getProviderName());
064            providerName.append(',');
065            rateTypeSet.addAll(exchangeRateProvider.getContext().getRateTypes());
066        }
067        providerName.setLength(providerName.length() - 1);
068
069        ProviderContextBuilder builder = ProviderContextBuilder.of(providerName.toString(), rateTypeSet);
070        builder.set(CHILD_PROVIDER_CONTEXTS_KEY, childContextList);
071        return builder.build();
072    }
073
074    /**
075     * Add an additional {@link ExchangeRateProvider} to the instance's delegate
076     * list.
077     *
078     * @param prov The {@link ExchangeRateProvider} to be added, not {@code null}
079     *             .
080     * @throws java.lang.NullPointerException if the provider is null.
081     *                                        .
082     */
083    private void addProvider(ExchangeRateProvider prov) {
084        if(prov==null){
085            throw new NullPointerException("ConversionProvider required.");
086        }
087        providers.add(prov);
088    }
089
090    /*
091     * (non-Javadoc)
092     *
093     * @see
094     * ExchangeRateProvider#getExchangeRate(org.javamoney.bp.
095     * CurrencyUnit, CurrencyUnit,
096     * ConversionContext)
097     */
098    @Override
099    public ExchangeRate getExchangeRate(ConversionQuery conversionQuery) {
100        for (ExchangeRateProvider prov : this.providers) {
101            if (prov.isAvailable(conversionQuery)) {
102                ExchangeRate rate = prov.getExchangeRate(conversionQuery);
103                if (rate!=null) {
104                    return rate;
105                }
106            }
107        }
108        return null;
109    }
110
111
112}