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 org.javamoney.moneta.spi.base.BaseCurrencyProviderSpi;
019
020import javax.money.CurrencyQuery;
021import javax.money.CurrencyUnit;
022import java.util.*;
023import java.util.concurrent.ConcurrentHashMap;
024
025/**
026 * This class provides a programmatic singleton for globally registering new {@link java.util.Currency}  into the
027 * {@link javax.money.Monetary} singleton either by currency code, locale, or both.
028 */
029public class ConfigurableCurrencyUnitProvider extends BaseCurrencyProviderSpi {
030    /**
031     * The currency units, identified by currency code.
032     */
033    private static final Map<String, CurrencyUnit> currencyUnits = new ConcurrentHashMap<>();
034    /**
035     * The currency units, identified by numeric code.
036     */
037    private static final Map<Integer, CurrencyUnit> currencyUnitsByNumericCode = new ConcurrentHashMap<>();
038    /**
039     * The currency units identified by Locale.
040     */
041    private static final Map<Locale, CurrencyUnit> currencyUnitsByLocale = new ConcurrentHashMap<>();
042
043
044    /**
045     * Return a {@link CurrencyUnit} instances matching the given
046     * {@link javax.money.CurrencyContext}.
047     *
048     * @param currencyQuery the {@link javax.money.CurrencyQuery} containing the parameters determining the query. not null.
049     * @return the corresponding {@link CurrencyUnit}, or null, if no such unit
050     * is provided by this provider.
051     */
052    public Set<CurrencyUnit> getCurrencies(CurrencyQuery currencyQuery) {
053        Set<CurrencyUnit> result = new HashSet<>(currencyUnits.size());
054        if (!currencyQuery.getCurrencyCodes().isEmpty()) {
055            for (String code : currencyQuery.getCurrencyCodes()) {
056                CurrencyUnit cu = currencyUnits.get(code);
057                if (cu != null) {
058                    result.add(cu);
059                }
060            }
061            return result;
062        }
063        if (!currencyQuery.getCountries().isEmpty()) {
064            for (Locale locale : currencyQuery.getCountries()) {
065                CurrencyUnit cu = currencyUnitsByLocale.get(locale);
066                if (cu != null) {
067                    result.add(cu);
068                }
069            }
070            return result;
071        }
072        if (!currencyQuery.getNumericCodes().isEmpty()) {
073            for (Integer numericCode : currencyQuery.getNumericCodes()) {
074                CurrencyUnit cu = currencyUnitsByNumericCode.get(numericCode);
075                if (cu != null) {
076                    result.add(cu);
077                }
078            }
079            return result;
080        }
081        result.addAll(currencyUnits.values());
082        return result;
083    }
084
085    /**
086     * Registers a new currency unit under its currency code and potentially numeric code.
087     *
088     * @param currencyUnit the new currency to be registered, not null.
089     * @return any unit instance registered previously by this instance, or null.
090     */
091    public static CurrencyUnit registerCurrencyUnit(CurrencyUnit currencyUnit) {
092        Objects.requireNonNull(currencyUnit);
093        CurrencyUnit registered = ConfigurableCurrencyUnitProvider.currencyUnits.put(currencyUnit.getCurrencyCode(), currencyUnit);
094        int numericCode = currencyUnit.getNumericCode();
095        if (numericCode != -1) {
096            ConfigurableCurrencyUnitProvider.currencyUnitsByNumericCode.put(numericCode, currencyUnit);
097        }
098        return registered;
099    }
100
101    /**
102     * Registers a new currency unit under the given Locale.
103     *
104     * @param currencyUnit the new currency to be registered, not null.
105     * @param locale       the Locale, not null.
106     * @return any unit instance registered previously by this instance, or null.
107     */
108    public static CurrencyUnit registerCurrencyUnit(CurrencyUnit currencyUnit, Locale locale) {
109        Objects.requireNonNull(locale);
110        Objects.requireNonNull(currencyUnit);
111        return ConfigurableCurrencyUnitProvider.currencyUnitsByLocale.put(locale, currencyUnit);
112    }
113
114    /**
115     * Removes a CurrencyUnit.
116     *
117     * @param currencyCode the currency code, not null.
118     * @return any unit instance removed, or null.
119     */
120    public static CurrencyUnit removeCurrencyUnit(String currencyCode) {
121        Objects.requireNonNull(currencyCode);
122        CurrencyUnit removed = ConfigurableCurrencyUnitProvider.currencyUnits.remove(currencyCode);
123        if (removed != null) {
124            int numericCode = removed.getNumericCode();
125            if (numericCode != -1) {
126                ConfigurableCurrencyUnitProvider.currencyUnitsByNumericCode.remove(numericCode);
127            }
128        }
129        return removed;
130    }
131
132    /**
133     * Removes a CurrencyUnit.
134     *
135     * @param locale the Locale, not null.
136     * @return any unit instance removed, or null.
137     */
138    public static CurrencyUnit removeCurrencyUnit(Locale locale) {
139        Objects.requireNonNull(locale);
140        return ConfigurableCurrencyUnitProvider.currencyUnitsByLocale.remove(locale);
141    }
142
143    /*
144     * (non-Javadoc)
145     *
146     * @see java.lang.Object#toString()
147     */
148    @Override
149    public String toString() {
150        return "ConfigurableCurrencyUnitProvider [currencyUnits=" + currencyUnits
151                + ", currencyUnitsByNumericCode=" + currencyUnitsByNumericCode
152                + ", currencyUnitsByLocale=" + currencyUnitsByLocale + ']';
153    }
154
155}