package org.springframework.cloud.localconfig; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.commons.lang3.text.StrLookup; import org.apache.commons.lang3.text.StrSubstitutor; import org.springframework.cloud.util.EnvironmentAccessor; /** * Helper class that handles finding and merging properties to be read by the connector. * * @author Christopher Smith */ class PropertiesFileResolver { public static final String BOOTSTRAP_PROPERTIES_FILENAME = "spring-cloud-bootstrap.properties"; private static final Logger logger = Logger.getLogger(PropertiesFileResolver.class.getName()); private final EnvironmentAccessor env; private final String classpathPropertiesFilename; PropertiesFileResolver(final EnvironmentAccessor env, final String classpathPropertiesFilename) { this.env = env; this.classpathPropertiesFilename = classpathPropertiesFilename; } PropertiesFileResolver(final EnvironmentAccessor env) { this(env, BOOTSTRAP_PROPERTIES_FILENAME); } PropertiesFileResolver() { this(new EnvironmentAccessor()); } /** * Inspects the system properties for an entry named {@value LocalConfigConnector#PROPERTIES_FILE_PROPERTY} directing it to an * external properties file. * * @return a {@code File} pointing to the external properties file, or {@code null} if the system property couldn't be read */ File findCloudPropertiesFileFromSystem() { String filename = null; try { filename = env.getSystemProperty(LocalConfigConnector.PROPERTIES_FILE_PROPERTY); } catch (SecurityException e) { logger.log(Level.WARNING, "SecurityManager prevented reading system property " + LocalConfigConnector.PROPERTIES_FILE_PROPERTY, e); return null; } if (filename == null) { logger.fine("didn't find system property for a configuration file"); return null; } File file = new File(filename); logger.info("found system property for a configuration file: " + file); return file; } /** * Looks for a resource named {@code filename} (usually {@value #BOOTSTRAP_PROPERTIES_FILENAME}) on the classpath. If present, * it is loaded and * inspected for a property named {@value LocalConfigConnector#PROPERTIES_FILE_PROPERTY}, which is interpolated from the system * properties and returned. * * @return the filename derived from the classpath control file, or {@code null} if one couldn't be found */ File findCloudPropertiesFileFromClasspath() { // see if we have a spring-cloud.properties at all InputStream in = getClass().getClassLoader().getResourceAsStream(classpathPropertiesFilename); if (in == null) { logger.info("no " + classpathPropertiesFilename + " found on the classpath to direct us to an external properties file"); return null; } // load it as a properties file Properties properties = new Properties(); try { properties.load(in); } catch (IOException e) { logger.log(Level.SEVERE, "found " + classpathPropertiesFilename + " on the classpath but couldn't load it as a properties file", e); return null; } // read the spring.cloud.propertiesFile property from it String template = properties.getProperty(LocalConfigConnector.PROPERTIES_FILE_PROPERTY); if (template == null) { logger.log(Level.SEVERE, "found properties file " + classpathPropertiesFilename + " on the classpath, but it didn't contain a property named " + LocalConfigConnector.PROPERTIES_FILE_PROPERTY); return null; } // if there's anything else, the client probably tried to put an app ID or other credentials there if (properties.entrySet().size() > 1) logger.warning("the properties file " + classpathPropertiesFilename + " contained properties besides " + LocalConfigConnector.PROPERTIES_FILE_PROPERTY + "; ignoring"); logger.fine("substituting system properties into '" + template + "'"); File configFile = new File(new StrSubstitutor(systemPropertiesLookup(env)).replace(template)); logger.info("derived configuration file name: " + configFile); return configFile; } File findCloudPropertiesFile() { File file = findCloudPropertiesFileFromSystem(); if (file != null) { logger.info("using configuration file from system properties"); return file; } file = findCloudPropertiesFileFromClasspath(); if (file != null) logger.info("using configuration file derived from " + classpathPropertiesFilename); else logger.info("did not find any Spring Cloud configuration file"); return file; } /** * Adapter from the {@link EnvironmentAccessor}'s system-property resolution to the {@code StrLookup} interface. * * @param env the {@code EnvironmentAccessor} to use for the lookups * @return a {@code StrLookup} view of the accessor's system properties */ private StrLookup<String> systemPropertiesLookup(final EnvironmentAccessor env) { return new StrLookup<String>() { @Override public String lookup(String key) { return env.getSystemProperty(key); } }; } }