Skip to content
ConfigurationLoaderUtil.java 6.18 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
    /*
      * 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) {
        if (log == null) {
            log.fatal("ERROR: Log object is null - but must be present!");
            throw new NullPointerException("ERROR: Log object is null - but must be present!");
        }
        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
                */
            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
                */
        }
        log.info("Configuration file [" + configPath + "] loaded!");
        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();
        }
    }