package dk.gov.oiosi.configuration; import dk.gov.oiosi.common.RaspLibraryException; import org.apache.commons.configuration.ConfigurationUtils; import org.apache.commons.configuration.XMLConfiguration; import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine; import org.apache.commons.logging.Log; 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, Log log) { if (log == null) { throw new IllegalArgumentException("ConfigurationLoaderUtil.loadXMLConfiguration: log object is null but must be present"); } XMLConfiguration config = null; try { if (log.isDebugEnabled()) { log.debug("Looking for configuration file: " + configPath); } // Remember first error: Throwable firstError = null; for (String configPrefix : CONFIG_PATH_PREFIX_LIST) { try { config = new XMLConfiguration(configPrefix + configPath); if (log.isInfoEnabled()) { log.debug("Ready to load configuration file: " + configPrefix + configPath); } /* * If 2 files exist, then the first should be used */ break; } 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) { log.error("Unable to find configuration at [" + configPath + "]: " + e.getMessage(), e); try { config = new XMLConfiguration("../" + configPath); } catch (Throwable e1) { log.error("Unable to find configuration at [" + "../" + configPath + "]: " + e1.getMessage(), 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) { /* * 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(); log.fatal("OIORASP cannot load configuration xml [" + configPath + "]: " + e.getMessage(), e); throw new RaspLibraryException("OIORASP cannot load configuration xml [" + configPath + "]", e); } 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 (String configPathPrefix : configPathPrefixList) { String canonicalPath = canonicalPath(new File(configPathPrefix + 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(); } } }