Resources.java

/*
 * This file is part of Indicators.
 *
 * Indicators is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Indicators is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Indicators. If not, see <https://www.gnu.org/licenses/>.
 */
package fr.inrae.agroclim.indicators.resources;

import java.text.MessageFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.Objects;
import java.util.ResourceBundle;

import lombok.Getter;

/**
 * Resources from .properties file.
 *
 * Last change $Date$
 *
 * @author $Author$
 * @version $Revision$
 */
public final class Resources {

    /**
     * The locale for the bundle.
     */
    private Locale currentLocale;

    /**
     * Path of .property resource.
     */
    @Getter
    private String bundleName;

    /**
     * Resource bundle.
     */
    private ResourceBundle resourceBundle;

    /**
     * Constructor.
     *
     * @param bundle resource bundle build outside.
     */
    public Resources(final ResourceBundle bundle) {
        bundleName = bundle.getBaseBundleName();
        currentLocale = bundle.getLocale();
        resourceBundle = bundle;
    }

    /**
     * Constructor.
     *
     * @param name File of message resource.
     * @param locale Locale for the bundle.
     */
    public Resources(final String name, final Locale locale) {
        bundleName = name;
        currentLocale = locale;
        resourceBundle = ResourceBundle.getBundle(bundleName, currentLocale);
        // Fallback to xxxx.properties and not xxxx_current_locale.properties.
        if (!resourceBundle.getLocale().equals(locale)) {
            resourceBundle = ResourceBundle.getBundle(bundleName, Locale.ROOT);
        }
    }

    /**
     * Return message with inlined arguments.
     *
     * @param key message key
     * @param messageArguments arguments for the message.
     * @return message with arguments or exclamation message
     */
    public String format(final String key,
            final Object... messageArguments) {
        try {
            final MessageFormat formatter = new MessageFormat(resourceBundle.getString(key), currentLocale);
            return formatter.format(messageArguments);
        } catch (final MissingResourceException e) {
            if (messageArguments == null) {
                return '!' + key + '!';
            }
            return '!' + key + " : " + Arrays.toString(messageArguments) + "!";
        }
    }

    /**
     * @return keys of resource
     */
    public List<String> getKeys() {
        return Collections.list(resourceBundle.getKeys());
    }

    /**
     * Retrieve date from key.
     *
     * 2 patterns available : yyyyMMddHHmmss or
     * DateTimeFormatter.ISO_LOCAL_DATE_TIME.
     *
     * @param key message key
     * @return date time
     * @throws DateTimeParseException if unable to parse the requested result
     */
    public LocalDateTime getLocalDateTime(final String key)
            throws DateTimeParseException {
        final String val = getString(key);
        DateTimeFormatter formatter;
        DateTimeParseException exception = null;
        for (final String format : Arrays.asList("yyyyMMddHHmmss",
                "yyyy-MM-dd'T'HH:mm:ss", "yyyy-MM-dd HH:mm:ss")) {
            try {
                formatter = DateTimeFormatter.ofPattern(format);
                return formatter.parse(getString(key), LocalDateTime::from);
            } catch (final DateTimeParseException ex) {
                exception = ex;
            }
        }
        throw new DateTimeParseException(
                String.format(
                        "Value of key \"%s\" could not be parsed: %s",
                        key,
                        val),
                val,
                0,
                exception);
    }

    /**
     * Retrieve message from key.
     *
     * @param key message key
     * @return message value or exclamation message
     */
    public String getString(final String key) {
        try {
            return resourceBundle.getString(key);
        } catch (final MissingResourceException e) {
            return '!' + key + '!';
        }
    }

    /**
     * Get build version and build date of library.
     *
     * @return version and date
     */
    public String getVersionAndBuildDate() {
        final String version = getString("version");
        final String date = getString("build.date")
                .replace("-", "")
                .replace(" ", "")
                .replace(":", "");
        return version + "+" + date;
    }

    /**
     * Refresh bundle using current locale and current bundle.
     */
    private void refresh() {
        resourceBundle = ResourceBundle.getBundle(bundleName, currentLocale);
    }

    /**
     * @param name File of message resource.
     */
    public void setBundleName(final String name) {
        bundleName = name;
        refresh();
    }

    /**
     * @param locale Locale for the bundle.
     */
    public void setLocale(final Locale locale) {
        if (Objects.equals(currentLocale, locale)) {
            return;
        }
        currentLocale = locale;
        refresh();
    }
}