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 java.io.IOException;
019import java.net.URL;
020import java.util.Collections;
021import java.util.Enumeration;
022import java.util.HashMap;
023import java.util.Map;
024import java.util.Properties;
025import java.util.logging.Level;
026import java.util.logging.Logger;
027
028/**
029 * Loader for the Java Money JSR configuration.
030 *
031 * @author Anatole Tresch
032 */
033public final class MonetaryConfig {
034
035    private static final Logger LOG = Logger
036            .getLogger(MonetaryConfig.class.getName());
037
038    private static final MonetaryConfig INSTANCE = new MonetaryConfig();
039
040    private final Map<String, String> config = new HashMap<>();
041    private final Map<String, Integer> priorities = new HashMap<>();
042
043    private MonetaryConfig() {
044        try {
045            Enumeration<URL> urls = getClass().getClassLoader().getResources(
046                    "javamoney.properties");
047            while (urls.hasMoreElements()) {
048                URL url = urls.nextElement();
049                try {
050                    Properties props = new Properties();
051                    props.load(url.openStream());
052                    updateConfig(props);
053                } catch (Exception e) {
054                    LOG.log(Level.SEVERE,
055                            "Error loading javamoney.properties, ignoring "
056                                    + url, e);
057                }
058            }
059        } catch (IOException e) {
060            LOG.log(Level.SEVERE, "Error loading javamoney.properties.", e);
061        }
062    }
063
064    private void updateConfig(Properties props) {
065        for (Map.Entry<Object, Object> en : props.entrySet()) {
066            String key = en.getKey().toString();
067            String value = en.getValue().toString();
068            int prio = 0;
069            if (key.startsWith("{")) {
070                int index = key.indexOf('}');
071                if (index > 0) {
072                    String prioString = key.substring(1, index);
073                    try {
074                        prio = Integer.parseInt(prioString);
075                        key = key.substring(index + 1);
076                    } catch (NumberFormatException e) {
077                        LOG.warning("Invalid config key in javamoney.properties: " + key);
078                    }
079                }
080            }
081            Integer existingPrio = priorities.get(key);
082            if (existingPrio==null) {
083                priorities.put(key, prio);
084                config.put(key, value);
085            } else if (existingPrio < prio) {
086                priorities.put(key, prio);
087                config.put(key, value);
088            } else if (existingPrio == prio) {
089                String oldValue = props.getProperty(key);
090                if(!value.equals(oldValue)){
091                    throw new IllegalStateException(
092                            "AmbiguousConfiguration detected for '" + key + "'.");
093                }
094            }
095            // else ignore entry with lower prio!
096        }
097    }
098
099    public static Map<String, String> getConfig() {
100        return Collections.unmodifiableMap(INSTANCE.config);
101    }
102
103}