/************************************************************************* * * * EJBCA Community: The OpenSource Certificate Authority * * * * This software is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2.1 of the License, or any later version. * * * * See terms of license at gnu.org. * * * *************************************************************************/ package org.ejbca.config; import java.io.File; import java.net.URL; import java.util.Iterator; import java.util.Properties; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.configuration.CompositeConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.PropertiesConfiguration; import org.apache.commons.configuration.SystemConfiguration; import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy; import org.apache.log4j.Logger; import org.cesecore.config.ConfigurationHolder; /** * This is a singleton. Used to configure common-configuration with our sources. * * Use like this: * String value = ConfigurationHolder.getString("my.conf.property.key"); or * String value = ConfigurationHolder.getString("my.conf.property.key", "default value"); * or * String value = ConfigurationHolder.getExpandedString("my.conf.property.key", "default value"); * to be able to parse values containing ${property} * * See in-line comments below for the sources added to the configuration. * * @version $Id: EjbcaConfigurationHolder.java 27627 2017-12-21 12:08:15Z henriks $ */ public final class EjbcaConfigurationHolder { private static final Logger log = Logger.getLogger(EjbcaConfigurationHolder.class); private static CompositeConfiguration config = null; private static CompositeConfiguration configBackup = null; /** ejbca.properties must be first in this file, because CONFIGALLOWEXTERNAL is defined in there. */ public static final String[] CONFIG_FILES = {"ejbca.properties", "web.properties", "cmptcp.properties", "externalra-caservice.properties", "ocsp.properties", "jaxws.properties", "cache.properties", "crlstore.properties", "certstore.properties", "database.properties", "va.properties", "va-publisher.properties"}; /** Configuration property that enables dynamic reading of properties from the file system. This is not allowed by default for security reasons. */ public static final String CONFIGALLOWEXTERNAL = "allow.external-dynamic.configuration"; /** This is a singleton so it's not allowed to create an instance explicitly */ private EjbcaConfigurationHolder() { } /** Use static code block to instantiate the instance at class load and prevent the thread synchronization issues. * This solution takes advantage of the Java memory model's guarantees about class initialization to ensure thread safety. */ static { instanceInternal(); } /** Method used to retrieve the singleton Configuration instance */ public static Configuration instance() { return config; } private static CompositeConfiguration instanceInternal() { // read ejbca.properties, from config file built into jar, and see if we allow configuration by external files boolean allowexternal = false; try { final URL url = EjbcaConfigurationHolder.class.getResource("/conf/"+CONFIG_FILES[0]); if (url != null) { final PropertiesConfiguration pc = new PropertiesConfiguration(url); allowexternal = "true".equalsIgnoreCase(pc.getString(CONFIGALLOWEXTERNAL, "false")); if (allowexternal) { log.info("Allow external re-configuration: " + allowexternal); } } } catch (ConfigurationException e) { log.error("Error intializing configuration: ", e); } config = new CompositeConfiguration(); // Only add these config sources if we allow external configuration if (allowexternal) { // Override with system properties, this is prio 1 if it exists (java -Dscep.test=foo) config.addConfiguration(new SystemConfiguration()); log.info("Added system properties to configuration source (java -Dfoo.prop=bar)."); // Override with file in "application server home directory"/conf, this is prio 2 for (int i=0; i i = instance().getKeys(); while (i.hasNext()) { final String key = (String) i.next(); properties.setProperty(key, instance().getString(key)); } return properties; } /** * @param property the property to look for * @param defaultValue default value to use if property is not found * @return String configured for property, or default value, if defaultValue is null and property is not found null is returned. */ public static String getString(final String property) { // Commons configuration interprets ','-separated values as an array of Strings, but we need the whole String for example SubjectDNs. String ret = null; final StringBuilder str = new StringBuilder(); String rets[] = instance().getStringArray(property); if (rets.length == 0) { rets = ConfigurationHolder.getDefaultValueArray(property); } for (int i=0; i i = properties.keySet().iterator(); while (i.hasNext()) { final String key = (String) i.next(); final String value = (String) properties.get(key); config.setProperty(key, value); } return true; } /** * Takes a backup of the active configuration if necessary and updates the active configuration. * * NOTE: This method should only be used by tests through ConfigurationSessionBean! */ public static boolean updateConfiguration(final String key, final String value) { backupConfiguration(); // Only takes a backup if necessary. config.setProperty(key, value); return true; } }