AppUtil.java

/***************************************************************************
   Copyright 2015 Emily Estes

   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.
***************************************************************************/
package net.metanotion.util;


import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;

import org.slf4j.LoggerFactory;

import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;
import ch.qos.logback.core.util.StatusPrinter;

/** This is a collection of utilty methods for starting up applications that involve Logback and configuration files
provided on the command line. Together with {@link net.metanotion.util.IniToStruct},
{@link net.metanotion.util.ArgsToStruct}, and {@link net.metanotion.util.IniProperties} these classes provide some
useful standards for application startup. */
public final class AppUtil {
	/** Read a logging configuration file specified on the command line to configure logback.
		@param args The command line argument array, it is assumed the file is specified in
			{@link net.metanotion.util.AppUtil#ARG_LOGGING_CONFIG}
		@throws JoranException if logback fails to successfully configure itself.
	*/
	public static void startLogging(final String[] args) throws JoranException {
		startLogging(args, AppUtil.ARG_LOGGING_CONFIG);
	}

	/** Read a logging configuration file specified on the command line to configure logback.
		@param args The command line argument array.
		@param argLoggingConfig The array position to look for the logging configuration file name.
		@throws JoranException if logback fails to successfully configure itself.
	*/
	public static void startLogging(final String[] args, final int argLoggingConfig) throws JoranException {
		if(args.length > argLoggingConfig) {
			final LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
			final JoranConfigurator configurator = new JoranConfigurator();
			configurator.setContext(context);
			context.reset();
			configurator.doConfigure(args[argLoggingConfig]);
			StatusPrinter.printInCaseOfErrorsOrWarnings(context);
		}
	}

	/* Command line argument array positions. */
	/** The command line argument array position to find the application ini file. */
	public static final int ARG_CONFIG = 0;
	/** The command line argument array position to find the logback logging configuration file. */
	public static final int ARG_LOGGING_CONFIG = 1;

	/** Read a configuration file into a configuration data structure using the provided defaults class for missing
		options. This is a utilty method for using the {@link net.metanotion.util.IniToStruct} class to read INI files.
		@param <C> The type of the configuration object to load.
		@param args The command line arguments, the config file is assumed be in the position denoted by
			{@link net.metanotion.util.AppUtil#ARG_CONFIG}
		@param defaultFile The default file name to look for if there is no command line parameter.
		@param config The class object for your applications configuration object. The instance variables of this class
			will be used to hold your applications configuration.
		@param defaults An instance of an object containing defaults for your application. The instance variables of
			this object will be used to populate missing values from the config file.
		@return An instance of the configuration class whose instance variables contain values from the config file(or
			default values if the are missing).
		@throws Exception if anything goes wrong.
	*/
	public static <C> C readConfig(final String[] args,
			final String defaultFile,
			final Class<C> config,
			final Object defaults) throws Exception {
		final String cFile = (args.length > ARG_CONFIG) ? args[ARG_CONFIG] : defaultFile;
		try (final Reader reader = new InputStreamReader(new FileInputStream(cFile), StandardCharsets.UTF_8)) {
			return new IniToStruct<C>(config).getInstance(defaults, reader);
		}
	}

	/** Standard "startup" procedure for an app server: start error logging and load a configuration filling in
		defaults where needed.
		@see net.metanotion.util.IniToStruct
		@see net.metanotion.util.AppUtil#startLogging
		@param <C> The type of the configuration object to load.
		@param args The command line argument array passed to your main function.
		@param defaultFile The default filename to use for loading your application's configuration file.
		@param config The class object for your applications configuration object. The instance variables of this class
			will be used to hold your applications configuration.
		@param defaults An instance of an object containing defaults for your application. The instance variables of
			this object will be used to populate missing values from the config file.
		@return An instance of the configuration class whose instance variables contain values from the config file(or
			default values if the are missing).
		@throws Exception if anything goes wrong.
	*/
	public static <C> C standardStart(final String[] args,
			final String defaultFile,
			final Class<C> config,
			final Object defaults) throws Exception {
		AppUtil.startLogging(args);
		return AppUtil.readConfig(args, defaultFile, config, defaults);
	}
}