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.internal;
017
018import org.javamoney.moneta.spi.base.BaseMonetaryAmountsSingletonSpi;
019
020import javax.money.MonetaryAmount;
021import javax.money.MonetaryAmountFactory;
022import javax.money.MonetaryException;
023import javax.money.spi.Bootstrap;
024import javax.money.spi.MonetaryAmountFactoryProviderSpi;
025
026import java.util.Map;
027import java.util.Set;
028import java.util.concurrent.ConcurrentHashMap;
029
030/**
031 * Default implementation ot {@link javax.money.spi.MonetaryAmountsSingletonSpi} loading the SPIs on startup
032 * initially once, using the
033 * JSR's {@link javax.money.spi.Bootstrap} mechanism.
034 */
035public class DefaultMonetaryAmountsSingletonSpi extends BaseMonetaryAmountsSingletonSpi {
036
037    private final Map<Class<? extends MonetaryAmount>, MonetaryAmountFactoryProviderSpi<?>> factories =
038            new ConcurrentHashMap<>();
039
040    private Class<? extends MonetaryAmount> configuredDefaultAmountType = loadDefaultAmountType();
041
042    public DefaultMonetaryAmountsSingletonSpi() {
043        for (MonetaryAmountFactoryProviderSpi<?> f : Bootstrap.getServices(MonetaryAmountFactoryProviderSpi.class)) {
044            MonetaryAmountFactoryProviderSpi<?> factory = factories.get(f.getAmountType());
045            if(factory==null){
046                factories.put(f.getAmountType(), f);
047            }
048        }
049    }
050
051    /**
052     * Tries to load the default {@link MonetaryAmount} class from
053     * {@code javamoney.properties} with contents as follows:<br/>
054     * <code>
055     * org.javamoney.bp.defaults.amount.class=my.fully.qualified.ClassName
056     * </code>
057     *
058     * @return the loaded default class, or {@code null}
059     */
060    // type check should be safe, exception will be logged if not.
061    private Class<? extends MonetaryAmount> loadDefaultAmountType() {
062        return null;
063    }
064
065
066    // save cast, since members are managed by this instance
067    @SuppressWarnings("unchecked")
068    @Override
069    public <T extends MonetaryAmount> MonetaryAmountFactory<T> getAmountFactory(Class<T> amountType) {
070        MonetaryAmountFactoryProviderSpi<T> f = MonetaryAmountFactoryProviderSpi.class.cast(factories.get(amountType));
071        if (f!=null) {
072            return f.createMonetaryAmountFactory();
073        }
074        throw new MonetaryException("No matching MonetaryAmountFactory found, type=" + amountType.getName());
075    }
076
077    @Override
078    public Set<Class<? extends MonetaryAmount>> getAmountTypes() {
079        return factories.keySet();
080    }
081
082    /*
083     * (non-Javadoc)
084     *
085     * @see org.javamoney.bp.api.spi.MonetaryAmountsSpi#getDefaultAmountType()
086     */
087    @Override
088    public Class<? extends MonetaryAmount> getDefaultAmountType() {
089        if (configuredDefaultAmountType==null) {
090            for (MonetaryAmountFactoryProviderSpi<?> f : Bootstrap.getServices(MonetaryAmountFactoryProviderSpi.class)) {
091                if (f.getQueryInclusionPolicy() == MonetaryAmountFactoryProviderSpi.QueryInclusionPolicy.ALWAYS) {
092                    configuredDefaultAmountType = f.getAmountType();
093                    break;
094                }
095            }
096        }
097        if(configuredDefaultAmountType==null){
098            throw new MonetaryException("No MonetaryAmountFactoryProviderSpi registered.");
099        }
100        return configuredDefaultAmountType;
101    }
102
103}