/* * Copyright [1999-2015] Wellcome Trust Sanger Institute and the EMBL-European Bioinformatics Institute * Copyright [2016-2017] EMBL-European Bioinformatics Institute * * 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 org.ensembl.healthcheck.configurationmanager; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.lang.reflect.InvocationHandler; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.logging.Logger; import uk.co.flamingpenguin.jewel.cli.OptionNotPresentException; /** * A configuration object that gets its information from a property file. * * Use ConfigurationFactory for instantiation or one of the many constructors * */ public class ConfigurationByProperties<T> extends AbstractAliasAwareWithStanardInvocationHanderConfigurationBacking<T> { static final Logger log = Logger.getLogger(ConfigurationByProperties.class .getCanonicalName()); /** * A list of strings may be expected as a configuration value. In properties * file however, there are only strings. In case a list of strings is * requested in the configuration interface the string found in the property * will be split on the value in the listSeparatorInProperyFile variable to * generate a list of values. * * Update 11/10/2010: Changed from comma (",") to space (" ") as requested * by Dan * */ private final static String LIST_SEPARATOR_IN_PROPERTY_FILE = "\\s+"; private final Properties properties; protected Map<String, Set<String>> parameterAliasesMap; /** * * Construct a ConfigurationByProperties object that proxies a * configurationInterfaceToProxy. Initialised by passing properties. * * @param configurationInterfaceToProxy * @param properties * @return {@link ConfigurationByProperties} */ public static Object newInstance(Class configurationInterfaceToProxy, Properties properties) { return createProxyUsingConfigurationObject( configurationInterfaceToProxy, new ConfigurationByProperties( configurationInterfaceToProxy, properties)); } /** * * Construct a ConfigurationByProperties object that proxies a * configurationInterfaceToProxy. Initialised by passing the name of a * property file. * * @param configurationInterfaceToProxy * @param propertyFile * @return {@link ConfigurationByProperties} * @throws IOException */ public static Object newInstance(Class configurationInterfaceToProxy, String propertyFile) throws IOException { return createProxyUsingConfigurationObject( configurationInterfaceToProxy, new ConfigurationByProperties( configurationInterfaceToProxy, propertyFile)); } /** * * Creates a proxy of type configurationInterfaceToProxy for a handler which * is an instance of this object. * * @param configurationInterfaceToProxy * @param handler * @return proxy */ private static Object createProxyUsingConfigurationObject( Class configurationInterfaceToProxy, InvocationHandler handler) { Object configuration = java.lang.reflect.Proxy.newProxyInstance( configurationInterfaceToProxy.getClassLoader(), new Class[] { configurationInterfaceToProxy }, handler); return configuration; } /** * Constructor using a filename for finding the properties file * * @param propertyFile * @throws IOException * */ public ConfigurationByProperties(Class<T> configurationClass, String propertyFile) throws IOException { this(configurationClass, new File(propertyFile)); } /** * Constructor using a File object for finding the properties file * * @param propertyFile * @throws IOException * */ public ConfigurationByProperties(Class<T> configurationClass, File propertyFile) throws IOException { this(configurationClass, new FileInputStream(propertyFile)); } /** * Constructor using a FileInputStream object for reading the properties * file. * * @param propertyFis * @throws IOException * */ public ConfigurationByProperties(Class<T> configurationClass, FileInputStream propertyFis) throws IOException { super(configurationClass); Properties properties = new Properties(); properties.load(propertyFis); propertyFis.close(); this.properties = properties; parameterAliasesMap = this .createParameterAliasesMap(configurationClass); } /** * @param properties * * Constructor that takes the properties directly. * */ public ConfigurationByProperties(Class<T> configurationClass, Properties properties) { super(configurationClass); this.properties = properties; parameterAliasesMap = this .createParameterAliasesMap(configurationClass); } protected Object mockDirectGetMethod(String varRequested) { // Result may be null String configValue = this.properties.getProperty(varRequested); // Requested property might not have been set. If so if (configValue == null) { throw new OptionNotPresentException( "No configuration setting found for " + varRequested); } log.fine("varRequested: " + varRequested); configurationDataType dataTypeExpected = canonicalVarName2DataType .get(alias2CanonicalVarName.get(varRequested)); if (dataTypeExpected == null) { throw new NullPointerException("Unknown return data type for " + varRequested); } if (dataTypeExpected == configurationDataType.String) { // Return trimmed version of the String so trailing spaces will // not be returned as part of the value. // return configValue.trim(); } if (dataTypeExpected == configurationDataType.List_Of_Strings) { List<String> returnValue = new ArrayList<String>(); for (String currentValue : configValue .split(LIST_SEPARATOR_IN_PROPERTY_FILE)) { // The trimmed values are returned. Actually the call to trim // does not have any effect here anymore, because the split // on LIST_SEPARATOR_IN_PROPERTY_FILE already gets rid of // whitespaces around the values. // returnValue.add(currentValue.trim()); } return returnValue; } throw new RuntimeException("Unknown return type " + dataTypeExpected + " for " + varRequested + "!"); } protected boolean mockDirectIsMethod(String varRequested) { try { // mockGetMethod(varRequested); mockDirectGetMethod(varRequested); } catch (OptionNotPresentException e) { return false; } return true; } public String toString() { return this.getClass().getSimpleName() + " " + properties.toString(); } }