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