alpine.Config.java Source code

Java tutorial

Introduction

Here is the source code for alpine.Config.java

Source

/*
 * This file is part of Alpine.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Copyright (c) Steve Springett. All Rights Reserved.
 */
package alpine;

import alpine.logging.Logger;
import alpine.util.PathUtil;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Properties;

/**
 * The Config class is responsible for reading the application.properties file.
 *
 * @author Steve Springett
 * @since 1.0.0
 */
public class Config {

    private static final Logger LOGGER = Logger.getLogger(Config.class);
    private static final String ALPINE_APP_PROP = "alpine.application.properties";
    private static final String PROP_FILE = "application.properties";
    private static final String ALPINE_VERSION_PROP_FILE = "alpine.version";
    private static final String APPLICATION_VERSION_PROP_FILE = "application.version";
    private static final Config INSTANCE;
    private static Properties properties;
    private static Properties alpineVersionProperties;
    private static Properties applicationVersionProperties;

    static {
        LOGGER.info(StringUtils.repeat("-", 80));
        INSTANCE = new Config();
        INSTANCE.init();
        LOGGER.info(StringUtils.repeat("-", 80));
        LOGGER.info("Application: " + INSTANCE.getApplicationName());
        LOGGER.info("Version:     " + INSTANCE.getApplicationVersion());
        LOGGER.info("Built-on:    " + INSTANCE.getApplicationBuildTimestamp());
        LOGGER.info(StringUtils.repeat("-", 80));
        LOGGER.info("Framework:   " + INSTANCE.getFrameworkName());
        LOGGER.info("Version :    " + INSTANCE.getFrameworkVersion());
        LOGGER.info("Built-on:    " + INSTANCE.getFrameworkBuildTimestamp());
        LOGGER.info(StringUtils.repeat("-", 80));
    }

    public interface Key {

        /**
         * The name of the property.
         * @return String of the property name
         */
        String getPropertyName();

        /**
         * The default value of the property if not found.
         * @return the default value
         */
        Object getDefaultValue();
    }

    public enum AlpineKey implements Key {
        WORKER_THREADS("alpine.worker.threads", 0), WORKER_THREAD_MULTIPLIER("alpine.worker.thread.multiplier",
                4), DATA_DIRECTORY("alpine.data.directory", "~/.alpine"), DATABASE_MODE("alpine.database.mode",
                        "embedded"), DATABASE_PORT("alpine.database.port", 9092), DATABASE_URL(
                                "alpine.database.url",
                                "jdbc:h2:mem:alpine"), DATABASE_DRIVER("alpine.database.driver",
                                        "org.h2.Driver"), DATABASE_DRIVER_PATH("alpine.database.driver.path",
                                                null), DATABASE_USERNAME("alpine.database.username",
                                                        "sa"), DATABASE_PASSWORD("alpine.database.password",
                                                                ""), ENFORCE_AUTHENTICATION(
                                                                        "alpine.enforce.authentication",
                                                                        true), ENFORCE_AUTHORIZATION(
                                                                                "alpine.enforce.authorization",
                                                                                true), BCRYPT_ROUNDS(
                                                                                        "alpine.bcrypt.rounds",
                                                                                        14), LDAP_ENABLED(
                                                                                                "alpine.ldap.enabled",
                                                                                                false), LDAP_SERVER_URL(
                                                                                                        "alpine.ldap.server.url",
                                                                                                        null), LDAP_BASEDN(
                                                                                                                "alpine.ldap.basedn",
                                                                                                                null), LDAP_SECURITY_AUTH(
                                                                                                                        "alpine.ldap.security.auth",
                                                                                                                        null), LDAP_BIND_USERNAME(
                                                                                                                                "alpine.ldap.bind.username",
                                                                                                                                null), LDAP_BIND_PASSWORD(
                                                                                                                                        "alpine.ldap.bind.password",
                                                                                                                                        null), LDAP_AUTH_USERNAME_FMT(
                                                                                                                                                "alpine.ldap.auth.username.format",
                                                                                                                                                null), LDAP_ATTRIBUTE_NAME(
                                                                                                                                                        "alpine.ldap.attribute.name",
                                                                                                                                                        "userPrincipalName"), LDAP_ATTRIBUTE_MAIL(
                                                                                                                                                                "alpine.ldap.attribute.mail",
                                                                                                                                                                "mail"), LDAP_GROUPS_FILTER(
                                                                                                                                                                        "alpine.ldap.groups.filter",
                                                                                                                                                                        null), LDAP_USER_GROUPS_FILTER(
                                                                                                                                                                                "alpine.ldap.user.groups.filter",
                                                                                                                                                                                null), LDAP_USER_PROVISIONING(
                                                                                                                                                                                        "alpine.ldap.user.provisioning",
                                                                                                                                                                                        false), LDAP_TEAM_SYNCHRONIZATION(
                                                                                                                                                                                                "alpine.ldap.team.synchronization",
                                                                                                                                                                                                false), HTTP_PROXY_ADDRESS(
                                                                                                                                                                                                        "alpine.http.proxy.address",
                                                                                                                                                                                                        null), HTTP_PROXY_PORT(
                                                                                                                                                                                                                "alpine.http.proxy.port",
                                                                                                                                                                                                                null), HTTP_PROXY_USERNAME(
                                                                                                                                                                                                                        "alpine.http.proxy.username",
                                                                                                                                                                                                                        null), HTTP_PROXY_PASSWORD(
                                                                                                                                                                                                                                "alpine.http.proxy.password",
                                                                                                                                                                                                                                null), WATCHDOG_LOGGING_INTERVAL(
                                                                                                                                                                                                                                        "alpine.watchdog.logging.interval",
                                                                                                                                                                                                                                        0);

        private String propertyName;
        private Object defaultValue;

        AlpineKey(String item, Object defaultValue) {
            this.propertyName = item;
            this.defaultValue = defaultValue;
        }

        public String getPropertyName() {
            return propertyName;
        }

        public Object getDefaultValue() {
            return defaultValue;
        }
    }

    /**
     * Returns an instance of the Config object.
     * @return a Config object
     * @since 1.0.0
     */
    public static Config getInstance() {
        return INSTANCE;
    }

    /**
     * Initialize the Config object. This method should only be called once.
     */
    private void init() {
        if (properties != null) {
            return;
        }

        LOGGER.info("Initializing Configuration");
        properties = new Properties();

        final String alpineAppProp = PathUtil.resolve(System.getProperty(ALPINE_APP_PROP));
        if (StringUtils.isNotBlank(alpineAppProp)) {
            LOGGER.info("Loading application properties from " + alpineAppProp);
            try (FileInputStream fileInputStream = new FileInputStream(new File(alpineAppProp))) {
                properties.load(fileInputStream);
            } catch (FileNotFoundException e) {
                LOGGER.error("Could not find property file " + alpineAppProp);
            } catch (IOException e) {
                LOGGER.error("Unable to load " + alpineAppProp);
            }
        } else {
            LOGGER.info("System property " + ALPINE_APP_PROP + " not specified");
            LOGGER.info("Loading " + PROP_FILE + " from classpath");
            try (InputStream in = this.getClass().getClassLoader().getResourceAsStream(PROP_FILE)) {
                properties.load(in);
            } catch (IOException e) {
                LOGGER.error("Unable to load " + PROP_FILE);
            }
        }
        if (properties.size() == 0) {
            LOGGER.error(
                    "A fatal error occurred loading application properties. Please correct the issue and restart the application.");
        }

        alpineVersionProperties = new Properties();
        try (InputStream in = this.getClass().getClassLoader().getResourceAsStream(ALPINE_VERSION_PROP_FILE)) {
            alpineVersionProperties.load(in);
        } catch (IOException e) {
            LOGGER.error("Unable to load " + ALPINE_VERSION_PROP_FILE);
        }
        if (alpineVersionProperties.size() == 0) {
            LOGGER.error(
                    "A fatal error occurred loading Alpine version information. Please correct the issue and restart the application.");
        }

        applicationVersionProperties = new Properties();
        try (InputStream in = this.getClass().getClassLoader().getResourceAsStream(APPLICATION_VERSION_PROP_FILE)) {
            applicationVersionProperties.load(in);
        } catch (IOException e) {
            LOGGER.error("Unable to load " + APPLICATION_VERSION_PROP_FILE);
        }
        if (applicationVersionProperties.size() == 0) {
            LOGGER.error(
                    "A fatal error occurred loading application version information. Please correct the issue and restart the application.");
        }
    }

    /**
     * Returns the Alpine component name.
     * @return the Alpine name
     * @since 1.0.0
     */
    public String getFrameworkName() {
        return alpineVersionProperties.getProperty("name");
    }

    /**
     * Returns the Alpine version.
     * @return the Alpine version
     * @since 1.0.0
     */
    public String getFrameworkVersion() {
        return alpineVersionProperties.getProperty("version");
    }

    /**
     * Returns the Alpine built timestamp.
     * @return the timestamp in which this version of Alpine was built
     * @since 1.0.0
     */
    public String getFrameworkBuildTimestamp() {
        return alpineVersionProperties.getProperty("timestamp");
    }

    /**
     * Returns the Alpine UUID.
     * @return the UUID unique to this build of Alpine
     * @since 1.3.0
     */
    public String getFrameworkBuildUuid() {
        return alpineVersionProperties.getProperty("uuid");
    }

    /**
     * Returns the Application component name.
     * @return the Application name
     * @since 1.0.0
     */
    public String getApplicationName() {
        return applicationVersionProperties.getProperty("name", "Unknown Alpine Application");
    }

    /**
     * Returns the Application version.
     * @return the Application version
     * @since 1.0.0
     */
    public String getApplicationVersion() {
        return applicationVersionProperties.getProperty("version", "0.0.0");
    }

    /**
     * Returns the Application built timestamp.
     * @return the timestamp in which this version of the Application was built
     * @since 1.0.0
     */
    public String getApplicationBuildTimestamp() {
        return applicationVersionProperties.getProperty("timestamp", "1970-01-01 00:00:00");
    }

    /**
     * Returns the Application UUID.
     * @return the UUID unique to this build of the application
     * @since 1.3.0
     */
    public String getApplicationBuildUuid() {
        return applicationVersionProperties.getProperty("uuid");
    }

    /**
     * Returns the fully qualified path to the configured data directory.
     * Expects a fully qualified path or a path starting with ~/
     *
     * Defaults to ~/.alpine if data directory is not specified.
     * @return a File object of the data directory
     * @since 1.0.0
     */
    public File getDataDirectorty() {
        final String prop = PathUtil.resolve(getProperty(AlpineKey.DATA_DIRECTORY));
        return new File(prop).getAbsoluteFile();
    }

    /**
     * Return the configured value for the specified Key. As of v1.4.3, this
     * method will first check if the key has been specified as an environment
     * variable. If it has, the method will return the value. If it hasn't
     * been specified in the environment, it will retrieve the value (and optional
     * default value) from the properties configuration.
     *
     * This method is Docker-friendly in that configuration can be specified via
     * environment variables which is a common method of configuration when
     * configuration files are not easily accessible.
     *
     * @param key The Key to return the configuration for
     * @return a String of the value of the configuration
     * @since 1.0.0
     */
    public String getProperty(Key key) {
        final String envVariable = getPropertyFromEnvironment(key);
        if (envVariable != null) {
            return envVariable;
        }
        if (key.getDefaultValue() == null) {
            return properties.getProperty(key.getPropertyName());
        } else {
            return properties.getProperty(key.getPropertyName(), String.valueOf(key.getDefaultValue()));
        }
    }

    /**
     * Return the configured value for the specified Key.
     * @param key The Key to return the configuration for
     * @return a int of the value of the configuration
     * @since 1.0.0
     */
    public int getPropertyAsInt(Key key) {
        try {
            return Integer.parseInt(getProperty(key));
        } catch (NumberFormatException e) {
            LOGGER.error("Error parsing number from property: " + key.getPropertyName());
            return -1;
        }
    }

    /**
     * Return the configured value for the specified Key.
     * @param key The Key to return the configuration for
     * @return a long of the value of the configuration
     * @since 1.0.0
     */
    public long getPropertyAsLong(Key key) {
        try {
            return Long.parseLong(getProperty(key));
        } catch (NumberFormatException e) {
            LOGGER.error("Error parsing number from property: " + key.getPropertyName());
            return -1;
        }
    }

    /**
     * Return the configured value for the specified Key.
     * @param key The Key to return the configuration for
     * @return a boolean of the value of the configuration
     * @since 1.0.0
     */
    public boolean getPropertyAsBoolean(Key key) {
        return "true".equalsIgnoreCase(getProperty(key));
    }

    /**
     * Return the configured value for the specified Key.
     * @param key The Key to return the configuration for
     * @return a String of the value of the configuration
     * @since 1.0.0
     * @deprecated use {{@link #getProperty(Key)}}
     */
    @Deprecated
    public String getProperty(String key) {
        return properties.getProperty(key);
    }

    /**
     * Return the configured value for the specified Key.
     * @param key The String of the key to return the configuration for
     * @param defaultValue The default value if the key cannot be found
     * @return a String of the value of the configuration
     * @since 1.0.0
     * @deprecated use {{@link #getProperty(Key)}
     */
    @Deprecated
    public String getProperty(String key, String defaultValue) {
        return properties.getProperty(key, defaultValue);
    }

    /**
     * Extends the runtime classpath to include the files or directories specified.
     * @param paths one or more strings representing a single JAR file or a directory containing JARs.
     * @since 1.0.0
     */
    public void expandClasspath(String... paths) {
        if (paths == null || paths.length == 0) {
            return;
        }
        for (String path : paths) {
            expandClasspath(new File(PathUtil.resolve(path)));
        }
    }

    /**
     * Extends the runtime classpath to include the files or directories specified.
     * @param files one or more File objects representing a single JAR file or a directory containing JARs.
     * @since 1.0.0
     */
    public void expandClasspath(File... files) {
        URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
        Class<URLClassLoader> urlClass = URLClassLoader.class;
        for (File file : files) {
            LOGGER.info("Expanding classpath to include: " + file.getAbsolutePath());
            URI fileUri = file.toURI();
            try {
                Method method = urlClass.getDeclaredMethod("addURL", URL.class);
                method.setAccessible(true);
                method.invoke(urlClassLoader, fileUri.toURL());
            } catch (MalformedURLException | NoSuchMethodException | IllegalAccessException
                    | InvocationTargetException e) {
                LOGGER.error("Error expanding classpath", e);
            }
        }
    }

    /**
     * Attempts to retrieve the key via environment variable. Property names are
     * always upper case with periods replaced with underscores.
     *
     * alpine.worker.threads
     *    becomes
     * ALPINE_WORKER_THREADS
     *
     * @param key the key to retrieve from environment
     * @return the value of the key (if set), null otherwise.
     * @since 1.4.3
     */
    private String getPropertyFromEnvironment(Key key) {
        final String envVariable = key.getPropertyName().toUpperCase().replace(".", "_");
        try {
            return StringUtils.trimToNull(System.getenv(envVariable));
        } catch (SecurityException e) {
            LOGGER.warn("A security exception prevented access to the environment variable. Using defaults.");
        } catch (NullPointerException e) {
            // Do nothing. The key was not specified in an environment variable. Continue along.
        }
        return null;
    }

    /**
     * Determins is unit tests are enabled by checking if the 'alpine.unittests.enabled'
     * system property is set to true or false.
     * @return true if unit tests are enabled, false if not
     * @since 1.0.0
     */
    public static boolean isUnitTestsEnabled() {
        return Boolean.valueOf(System.getProperty("alpine.unittests.enabled", "false"));
    }

    /**
     * Enables unit tests by setting 'alpine.unittests.enabled' system property to true.
     * @since 1.0.0
     */
    public static void enableUnitTests() {
        System.setProperty("alpine.unittests.enabled", "true");
    }

}