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.internal;
014
015import org.javamoney.moneta.spi.MonetaryConfig;
016
017import javax.money.CurrencyQuery;
018import javax.money.CurrencyUnit;
019import javax.money.spi.Bootstrap;
020import javax.money.spi.CurrencyProviderSpi;
021import javax.money.spi.MonetaryCurrenciesSingletonSpi;
022import java.util.ArrayList;
023import java.util.HashSet;
024import java.util.List;
025import java.util.Set;
026import java.util.logging.Level;
027import java.util.logging.Logger;
028
029/**
030 * Factory singleton for {@link javax.money.CurrencyUnit} instances as provided by the
031 * different registered {@link javax.money.spi.CurrencyProviderSpi} instances.
032 * <p/>
033 * This class is thread safe.
034 *
035 * @author Anatole Tresch
036 */
037public class DefaultMonetaryCurrenciesSingletonSpi implements MonetaryCurrenciesSingletonSpi {
038
039    @Override
040    public Set<CurrencyUnit> getCurrencies(CurrencyQuery query) {
041        Set<CurrencyUnit> result = new HashSet<>();
042        List<CurrencyProviderSpi> providers = collectProviders(query);
043        for (CurrencyProviderSpi spi : providers) {
044            try {
045                result.addAll(spi.getCurrencies(query));
046            } catch (Exception e) {
047                Logger.getLogger(DefaultMonetaryCurrenciesSingletonSpi.class.getName())
048                        .log(Level.SEVERE, "Error loading currency provider names for " + spi.getClass().getName(),
049                                e);
050            }
051        }
052        return result;
053    }
054
055    private List<CurrencyProviderSpi> collectProviders(CurrencyQuery query) {
056        List<CurrencyProviderSpi> result = new ArrayList<>();
057        if (!query.getProviderNames().isEmpty()) {
058            for (String providerName : query.getProviderNames()) {
059                CurrencyProviderSpi provider = getProvider(providerName);
060                if (provider == null) {
061                    Logger.getLogger(DefaultMonetaryCurrenciesSingletonSpi.class.getName()).warning("No such currenvcy " +
062                            "provider found, ignoring: " + providerName);
063                } else {
064                    result.add(provider);
065                }
066            }
067        }
068        else{
069            for(String providerName:getDefaultProviderChain()){
070                CurrencyProviderSpi provider = getProvider(providerName);
071                if (provider == null) {
072                    Logger.getLogger(DefaultMonetaryCurrenciesSingletonSpi.class.getName()).warning("No such currenvcy " +
073                            "provider found, ignoring: " + providerName);
074                } else {
075                    result.add(provider);
076                }
077            }
078        }
079        return result;
080    }
081
082    private CurrencyProviderSpi getProvider(String providerName) {
083        for(CurrencyProviderSpi provider:Bootstrap.getServices(CurrencyProviderSpi.class)){
084            if(provider.getProviderName().equals(providerName)){
085                return provider;
086            }
087        }
088        return null;
089    }
090
091    /**
092     * This default implementation simply returns all providers defined in arbitrary order.
093     *
094     * @return the default provider chain, never null.
095     */
096    @Override
097    public List<String> getDefaultProviderChain() {
098        List<String> provList = new ArrayList<>();
099        String defaultChain = MonetaryConfig.getConfig().get("currencies.default-chain");
100        if(defaultChain!=null) {
101            String[] items = defaultChain.split(",");
102            for (String item : items) {
103                if (getProviderNames().contains(item.trim())) {
104                    provList.add(item);
105                } else {
106                    Logger.getLogger(getClass().getName())
107                            .warning("Ignoring non existing default provider: " + item);
108                }
109            }
110        }
111        else{
112            Bootstrap.getServices(CurrencyProviderSpi.class).forEach(
113                    p -> provList.add(p.getProviderName())
114            );
115        }
116        return provList;
117    }
118
119    /**
120     * Get the names of the currently loaded providers.
121     *
122     * @return the names of the currently loaded providers, never null.
123     */
124    @Override
125    public Set<String> getProviderNames() {
126        Set<String> result = new HashSet<>();
127        for (CurrencyProviderSpi spi : Bootstrap.getServices(CurrencyProviderSpi.class)) {
128            try {
129                result.add(spi.getProviderName());
130            } catch (Exception e) {
131                Logger.getLogger(DefaultMonetaryCurrenciesSingletonSpi.class.getName())
132                        .log(Level.SEVERE, "Error loading currency provider names for " + spi.getClass().getName(),
133                                e);
134            }
135        }
136        return result;
137    }
138
139}