Skip to content
ConfigurationLoaderUtil.java 4.7 KiB
Newer Older
package dk.gov.oiosi.configuration;

import org.apache.commons.configuration.ConfigurationUtils;
import org.apache.commons.configuration.XMLConfiguration;
import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;
import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine;
import org.apache.log4j.Logger;

import java.io.File;
import java.net.URL;

/**
 * Loads OIORASP configuration file, provides as clear as possible error
 * messages in case of problems
 *
 * @since OIORASP 1.3.0
 */
class ConfigurationLoaderUtil {

	/*
	 * At first we search by directly given path, than also in conf subfolder
	 * (like it was in OIORASP 1.2.3.HotFix1, for backward compatibility), than
	 * - in parent folder.
	 * TODO DLK: Why do we search in parent folder? What if file with the same
	 * name is located in more than 2 places?
	 */
	protected static final String[] CONFIG_PATH_PREFIX_LIST = new String[] { "", "conf/", "../" };

	public static XMLConfiguration loadXMLConfiguration(String configPath, Logger log) {
		XMLConfiguration config = null;
		try {
			if (log != null && log.isDebugEnabled()) {
				log.debug("Looking for configuration file " + configPath);
			}

			/*
			 * Remember first error
			 */
			Throwable firstError = null;
			for (int i = 0; i < CONFIG_PATH_PREFIX_LIST.length; i++) {
				try {
					config = new XMLConfiguration(CONFIG_PATH_PREFIX_LIST[i] + configPath);
				} catch (Throwable e) {
					if (firstError == null) {
						firstError = e;
					}
				}
			}

			/*
			 * Try to give a hint at which location OIORASP configuration was
			 * found or at least where we looked for it
			 */
			if (config == null) {
				URL configPathUrl = null;
				try {
					/*
					 * It is highly important to use the same way of location as
					 * XMLConfiguration uses.
					 * It is not enough just to check that File(configPath)
					 * exists, at server environment OIORASP configuration xml
					 * is placed into classpath.
					 */
					configPathUrl = ConfigurationUtils.locate(configPath);
				} catch (Exception e2) {
					/*
					 * Hide locate exception, it has no detailed information, we
					 * will build our own message below
					 */
				}
				if (configPathUrl == null) {
					/*
					 * OIORASP configuration xml was not found at all, try to
					 * describe, where we looked for it.
					 */
					throw new RuntimeException(buildLoadingErrorDescription(CONFIG_PATH_PREFIX_LIST, configPath));
				}
				throw new RuntimeException("Failed to parse OIORASP configuration file loaded by url '" + configPathUrl + "' with path " + configPath, firstError);
			}

			try {
				config = new XMLConfiguration(configPath);
			} catch (Throwable e) {
				try {
					config = new XMLConfiguration("../" + configPath);
				} catch (Throwable e1) {
				}
			}

			/*
			 * TODO: What is the reason to have this reloading strategy? Do we
			 * really support RaspConfiguration.xml dynamic modification?
			 */
			config.setReloadingStrategy(new FileChangedReloadingStrategy());
			config.setExpressionEngine(new XPathExpressionEngine());
		} catch (Exception e) {
			StringBuilder m = new StringBuilder();
			m.append("OIORASP cannot load configuration xml '");
			m.append(configPath);
			m.append(". ");
			m.append(e.getMessage());
			/*
			 * Log error also into System.err in case if logger is not
			 * configured at all at this environment
			 * This is a critical situation which is expected to be fixed asap,
			 * so it should be very visible
			 */
			System.err.println(m.toString());
			e.printStackTrace();

			if (log != null) {
				log.fatal(m.toString(), e);
			}
			/*
			 * TODO: Why don't we throw exception at this point? Is it really
			 * possible that OIORASP can be used without RaspConfiguration.xml?
			 * But for backward compatibility let's keep it, later it can be
			 * changed, e.g. in version 2.0.0
			 */
		}
		return config;
	}

	protected static String buildLoadingErrorDescription(String[] configPathPrefixList, String configPath) {
		StringBuilder sb = new StringBuilder();
		sb.append("Failed to locate OIORASP configuration file '");
		sb.append(configPath);
		sb.append("', tried to check next locations: ");
		sb.append("classpath");
		for (int i = 0; i < configPathPrefixList.length; i++) {
			String canonicalPath = canonicalPath(new File(configPathPrefixList[i] + configPath));
			sb.append(", '");
			sb.append(canonicalPath);
			sb.append("'");
		}
		return sb.toString();
	}

	private static String canonicalPath(File file) {
		try {
			return file.getCanonicalPath();
		} catch (Exception e) {
			return file.getAbsolutePath();
		}
	}
}