001package ca.uhn.fhir.i18n;
002
003import ca.uhn.fhir.context.ConfigurationException;
004
005import java.text.MessageFormat;
006import java.util.*;
007import java.util.concurrent.ConcurrentHashMap;
008
009import static org.apache.commons.lang3.StringUtils.isNotBlank;
010import static org.apache.commons.lang3.StringUtils.trim;
011
012/*
013 * #%L
014 * HAPI FHIR - Core Library
015 * %%
016 * Copyright (C) 2014 - 2018 University Health Network
017 * %%
018 * Licensed under the Apache License, Version 2.0 (the "License");
019 * you may not use this file except in compliance with the License.
020 * You may obtain a copy of the License at
021 * 
022 * http://www.apache.org/licenses/LICENSE-2.0
023 * 
024 * Unless required by applicable law or agreed to in writing, software
025 * distributed under the License is distributed on an "AS IS" BASIS,
026 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
027 * See the License for the specific language governing permissions and
028 * limitations under the License.
029 * #L%
030 */
031
032/**
033 * This feature is not yet in its final state and should be considered an internal part of HAPI for now - use with caution
034 */
035public class HapiLocalizer {
036
037        @SuppressWarnings("WeakerAccess")
038        public static final String UNKNOWN_I18N_KEY_MESSAGE = "!MESSAGE!";
039        private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(HapiLocalizer.class);
040        private static boolean ourFailOnMissingMessage;
041        private final Map<String, MessageFormat> myKeyToMessageFormat = new ConcurrentHashMap<>();
042        private List<ResourceBundle> myBundle = new ArrayList<>();
043        private String[] myBundleNames;
044
045        public HapiLocalizer() {
046                this(HapiLocalizer.class.getPackage().getName() + ".hapi-messages");
047        }
048
049        public HapiLocalizer(String... theBundleNames) {
050                myBundleNames = theBundleNames;
051                init();
052        }
053
054        public Set<String> getAllKeys() {
055                HashSet<String> retVal = new HashSet<>();
056                for (ResourceBundle nextBundle : myBundle) {
057                        Enumeration<String> keysEnum = nextBundle.getKeys();
058                        while (keysEnum.hasMoreElements()) {
059                                retVal.add(keysEnum.nextElement());
060                        }
061                }
062                return retVal;
063        }
064
065        /**
066         * @return Returns the raw message format string for the given key, or returns {@link #UNKNOWN_I18N_KEY_MESSAGE} if not found
067         */
068        @SuppressWarnings("WeakerAccess")
069        public String getFormatString(String theQualifiedKey) {
070                String formatString = null;
071                for (ResourceBundle nextBundle : myBundle) {
072                        if (nextBundle.containsKey(theQualifiedKey)) {
073                                formatString = nextBundle.getString(theQualifiedKey);
074                                formatString = trim(formatString);
075                        }
076                        if (isNotBlank(formatString)) {
077                                break;
078                        }
079                }
080
081                if (formatString == null) {
082                        ourLog.warn("Unknown localization key: {}", theQualifiedKey);
083                        if (ourFailOnMissingMessage) {
084                                throw new ConfigurationException("Unknown localization key: " + theQualifiedKey);
085                        }
086                        formatString = UNKNOWN_I18N_KEY_MESSAGE;
087                }
088                return formatString;
089        }
090
091        public String getMessage(Class<?> theType, String theKey, Object... theParameters) {
092                return getMessage(toKey(theType, theKey), theParameters);
093        }
094
095        public String getMessage(String theQualifiedKey, Object... theParameters) {
096                if (theParameters != null && theParameters.length > 0) {
097                        MessageFormat format = myKeyToMessageFormat.get(theQualifiedKey);
098                        if (format != null) {
099                                return format.format(theParameters);
100                        }
101
102                        String formatString = getFormatString(theQualifiedKey);
103
104                        format = new MessageFormat(formatString.trim());
105                        myKeyToMessageFormat.put(theQualifiedKey, format);
106                        return format.format(theParameters);
107                }
108                return getFormatString(theQualifiedKey);
109        }
110
111        protected void init() {
112                for (String nextName : myBundleNames) {
113                        myBundle.add(ResourceBundle.getBundle(nextName));
114                }
115        }
116
117        /**
118         * This <b>global setting</b> causes the localizer to fail if any attempts
119         * are made to retrieve a key that does not exist. This method is primarily for
120         * unit tests.
121         */
122        public static void setOurFailOnMissingMessage(boolean ourFailOnMissingMessage) {
123                HapiLocalizer.ourFailOnMissingMessage = ourFailOnMissingMessage;
124        }
125
126        public static String toKey(Class<?> theType, String theKey) {
127                return theType.getName() + '.' + theKey;
128        }
129
130}