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