001/*
002 * CREDIT SUISSE IS WILLING TO LICENSE THIS SPECIFICATION TO YOU ONLY UPON THE
003 * CONDITION THAT YOU ACCEPT ALL OF THE TERMS CONTAINED IN THIS AGREEMENT.
004 * PLEASE READ THE TERMS AND CONDITIONS OF THIS AGREEMENT CAREFULLY. BY
005 * DOWNLOADING THIS SPECIFICATION, YOU ACCEPT THE TERMS AND CONDITIONS OF THE
006 * AGREEMENT. IF YOU ARE NOT WILLING TO BE BOUND BY IT, SELECT THE "DECLINE"
007 * BUTTON AT THE BOTTOM OF THIS PAGE.
008 *
009 * Specification: JSR-354 Money and Currency API ("Specification")
010 *
011 * Copyright (c) 2012-2013, Credit Suisse All rights reserved.
012 */
013package org.javamoney.moneta.spi;
014
015import org.javamoney.moneta.spi.base.BaseMonetaryCurrenciesSingletonSpi;
016
017import javax.money.CurrencyQuery;
018import javax.money.CurrencyUnit;
019import javax.money.spi.Bootstrap;
020import javax.money.spi.CurrencyProviderSpi;
021import java.util.ArrayList;
022import java.util.HashSet;
023import java.util.List;
024import java.util.Set;
025import java.util.logging.Level;
026import java.util.logging.Logger;
027
028/**
029 * Factory singleton for {@link javax.money.CurrencyUnit} instances as provided by the
030 * different registered {@link javax.money.spi.CurrencyProviderSpi} instances.
031 *
032 * This class is thread safe.
033 *
034 * @author Anatole Tresch
035 */
036public class DefaultMonetaryCurrenciesSingletonSpi extends BaseMonetaryCurrenciesSingletonSpi {
037
038    @Override
039    public Set<CurrencyUnit> getCurrencies(CurrencyQuery query) {
040        Set<CurrencyUnit> result = new HashSet<>();
041        List<CurrencyProviderSpi> providers = collectProviders(query);
042        for (CurrencyProviderSpi spi : providers) {
043            try {
044                result.addAll(spi.getCurrencies(query));
045            } catch (Exception e) {
046                Logger.getLogger(DefaultMonetaryCurrenciesSingletonSpi.class.getName())
047                        .log(Level.SEVERE, "Error loading currency provider names for " + spi.getClass().getName(),
048                                e);
049            }
050        }
051        return result;
052    }
053
054    private List<CurrencyProviderSpi> collectProviders(CurrencyQuery query) {
055        List<CurrencyProviderSpi> result = new ArrayList<>();
056        if (!query.getProviderNames().isEmpty()) {
057            for (String providerName : query.getProviderNames()) {
058                CurrencyProviderSpi provider = getProvider(providerName);
059                if (provider == null) {
060                    Logger.getLogger(DefaultMonetaryCurrenciesSingletonSpi.class.getName()).warning("No such currency " +
061                            "provider found, ignoring: " + providerName);
062                } else {
063                    result.add(provider);
064                }
065            }
066        }
067        else{
068            for(String providerName:getDefaultProviderChain()){
069                CurrencyProviderSpi provider = getProvider(providerName);
070                if (provider == null) {
071                    Logger.getLogger(DefaultMonetaryCurrenciesSingletonSpi.class.getName()).warning("No such currency " +
072                            "provider found, ignoring: " + providerName);
073                } else {
074                    result.add(provider);
075                }
076            }
077        }
078        return result;
079    }
080
081    private CurrencyProviderSpi getProvider(String providerName) {
082        for(CurrencyProviderSpi provider: Bootstrap.getServices(CurrencyProviderSpi.class)){
083            if(provider.getProviderName().equals(providerName)){
084                return provider;
085            }
086        }
087        return null;
088    }
089
090    /**
091     * This default implementation simply returns all providers defined in arbitrary order.
092     *
093     * @return the default provider chain, never null.
094     */
095    @Override
096    public List<String> getDefaultProviderChain() {
097        List<String> provList = new ArrayList<>();
098        String defaultChain = MonetaryConfig.getConfig().get("currencies.default-chain");
099        if(defaultChain!=null) {
100            String[] items = defaultChain.split(",");
101            for (String item : items) {
102                if (getProviderNames().contains(item.trim())) {
103                    provList.add(item);
104                } else {
105                    Logger.getLogger(getClass().getName())
106                            .warning("Ignoring non existing default provider: " + item);
107                }
108            }
109        }
110        else{
111            for(CurrencyProviderSpi currencyProviderSpi: Bootstrap.getServices(CurrencyProviderSpi.class)) {
112                provList.add(currencyProviderSpi.getProviderName());
113            }
114        }
115        return provList;
116    }
117
118    /**
119     * Get the names of the currently loaded providers.
120     *
121     * @return the names of the currently loaded providers, never null.
122     */
123    @Override
124    public Set<String> getProviderNames() {
125        Set<String> result = new HashSet<>();
126        for (CurrencyProviderSpi spi : Bootstrap.getServices(CurrencyProviderSpi.class)) {
127            try {
128                result.add(spi.getProviderName());
129            } catch (Exception e) {
130                Logger.getLogger(DefaultMonetaryCurrenciesSingletonSpi.class.getName())
131                        .log(Level.SEVERE, "Error loading currency provider names for " + spi.getClass().getName(),
132                                e);
133            }
134        }
135        return result;
136    }
137
138}