/* * Copyright 2014, The Sporting Exchange Limited * * 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 com.betfair.cougar.util.configuration; import org.slf4j.Logger; import com.betfair.cougar.logging.records.SimpleLogRecord; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.Resource; import java.io.IOException; import java.io.InputStream; import java.util.Properties; import java.util.logging.Level; /** * This helper class is used to facilitate layered property loading. */ public class PropertyLoader { private static final String DEFAULT_CONFIG_HOST_PROPERTY = "betfair.config.host"; private static final String DEFAULT_CONFIG_HOST_PROPERTY_VALUE = "/conf/"; private static final String COUGAR_APPLICATION_PROPERTIES_FILE = "cougar-application.properties"; private Logger logger; private Resource defaultConfig; private Resource appProperties; private String configOverride; public PropertyLoader(Resource defaultConfig, String configOverride) { this(defaultConfig, configOverride, null); } public PropertyLoader(Resource defaultConfig, String configOverride, Logger logger) { this.defaultConfig = defaultConfig; this.appProperties = new ClassPathResource(COUGAR_APPLICATION_PROPERTIES_FILE); this.configOverride = configOverride; this.logger = logger; } /** * This will realise the set of resources returned from @see constructResourcesList and * as a fully populated properties object, including System properties * @return returns a fully populated Properties object with values from the config, the override and the System (in that order of precedence) * @throws IOException */ public Properties buildConsolidatedProperties() throws IOException { //Cannot use the spring classes here because they a) use the logger early, which //scuppers log4j and b) they're designed to do bean value overriding - not to be //used directly in this fashion Properties properties = new Properties(); //Read them from the list of resources then mix in System for (Resource r : constructResourceList()) { try (InputStream is = r.getInputStream()) { properties.load(is); } } //System for (String propertyName : System.getProperties().stringPropertyNames()) { properties.setProperty(propertyName, System.getProperty(propertyName)); } return properties; } /** * @return returns an array of validated Resources for use with overlaid property files */ public Resource[] constructResourceList() { String configHost = System.getProperties().getProperty(DEFAULT_CONFIG_HOST_PROPERTY); if (configHost == null) { log("No config Host defined - assuming " + DEFAULT_CONFIG_HOST_PROPERTY_VALUE); configHost = DEFAULT_CONFIG_HOST_PROPERTY_VALUE; } DefaultResourceLoader loader = new DefaultResourceLoader(); Resource configOverrideResource = loader.getResource(configHost + configOverride); return handleConfig(defaultConfig, appProperties, configOverrideResource); } private Resource[] handleConfig(Resource defaultConfig, Resource appProperties, Resource configOverrideResource) { Resource[] resourceList; /** * We need to check to see if the resources exists before we actually configure them as we need to * log whether we found the resources or not. If we don't check this, Cougar will fail to start if * configuration is missing. */ if(configOverrideResource.exists()){ if(appProperties.exists()){ resourceList = new Resource[] { defaultConfig, appProperties, configOverrideResource }; log("loading properties from {}, {} and {}", defaultConfig, appProperties, configOverrideResource); } else{ resourceList = new Resource[] { defaultConfig, configOverrideResource }; log("loading properties from {} and {}", defaultConfig, configOverrideResource); } } else{ if(appProperties.exists()){ resourceList = new Resource[] { defaultConfig, appProperties }; log("unable to load override file {}, loading properties from {} and {} ", configOverrideResource, defaultConfig, appProperties); } else{ resourceList = new Resource[] { defaultConfig }; log("unable to load override file {}, loading properties from {} ", configOverrideResource, defaultConfig); } } return resourceList; } private void log(String message, Object... args) { if (logger != null) { logger.info(message, args); } else { //This is a last ditch effort to say something useful before the logging //superstructure is initialized SimpleLogRecord record = new SimpleLogRecord("", Level.INFO, message, args); System.out.println(record.getMessage()); } } }