package com.cloudhopper.commons.xbean.util;
/*
* #%L
* ch-commons-xbean
* %%
* Copyright (C) 2015 Cloudhopper by Twitter
* %%
* 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.
* #L%
*/
import com.cloudhopper.commons.util.StringUtil;
import com.cloudhopper.commons.util.SubstitutionException;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.InputStream;
import java.io.IOException;
import java.util.Properties;
/**
* Utilities for replacing templated properties in files before they are used to "configure" and XmlBean.
* It is often the case that XBean is used to configure applications with sensitive information that
* should not reside in the code, but can be replaced in memory, at runtime, from a more secure source.
*
* Simple properties example (properties are templated as ${name}):
* <pre>
* {@code
* InputStream is = PropertiesReplacementUtil.replace(confFile, propsFile);
* Foo foo = XmlBeanFactory.create(is, Foo.class);
* }
* </pre>
*
* Properties example with different delimiters:
* <pre>
* {@code
* Properties props = PropertiesReplacementUtil.loadProperties(propsFile);
* InputStream is = PropertiesReplacementUtil.replaceProperties(new FileInputStream(confFile), props, "{{", "}}");
* Foo foo = XmlBeanFactory.create(is, Foo.class);
* }
* </pre>
*
* Example for replacing from properties file, System.getProperties(), and System.getenv():
* <pre>
* {@code
* InputStream is = PropertiesReplacementUtil.replace(confFile, propsFile, System.getProperties, true);
* Foo foo = XmlBeanFactory.create(is, Foo.class);
* }
* </pre>
* @author garth
*/
public class PropertiesReplacementUtil {
/**
* Creates an InputStream containing the document resulting from replacing template
* parameters in the given file.
* @param file The template file
* @param props The properties file
* @return An InputStream containing the resulting document.
*/
static public InputStream replace(File file, File props) throws IOException, SubstitutionException{
return replace(file, props, null, false);
}
/**
* Creates an InputStream containing the document resulting from replacing template
* parameters in the given file.
* @param file The template file
* @param props The properties file
* @param base Properties that should override those loaded from the file
* @param env If properties from System.getenv should also be used
* @return An InputStream containing the resulting document.
*/
static public InputStream replace(File file, File props, Properties base, boolean env) throws IOException, SubstitutionException{
if (env) return replaceProperties(replaceEnv(file), loadProperties(base, props));
else return replaceProperties(file, loadProperties(base, props));
}
/**
* Creates an InputStream containing the document resulting from replacing template
* parameters in the given file.
* @param file The template file
* @param props The properties
* @return An InputStream containing the resulting document.
*/
static public InputStream replaceProperties(File file, Properties props) throws IOException, SubstitutionException {
return replaceProperties(new FileInputStream(file), props);
}
/**
* Creates an InputStream containing the document resulting from replacing template
* parameters in the given InputStream source.
* @param source The source stream
* @param props The properties
* @return An InputStream containing the resulting document.
*/
static public InputStream replaceProperties(InputStream source, Properties props) throws IOException, SubstitutionException {
return replaceProperties(source, props, "${", "}");
}
/**
* Creates an InputStream containing the document resulting from replacing template
* parameters in the given InputStream source.
* @param source The source stream
* @param props The properties
* @param startStr The String that marks the start of a replacement key such as "${"
* @param endStr The String that marks the end of a replacement key such as "}"
* @return An InputStream containing the resulting document.
*/
static public InputStream replaceProperties(InputStream source, Properties props, String startStr, String endStr) throws IOException, SubstitutionException {
String template = streamToString(source);
String replaced = StringUtil.substituteWithProperties(template, startStr, endStr, props);
System.err.println(template);
System.err.println(replaced);
return new ByteArrayInputStream(replaced.getBytes());
}
/**
* Creates an InputStream containing the document resulting from replacing template
* parameters in the given file, using System.getenv as names/values.
* @param file The template file
* @return An InputStream containing the resulting document.
*/
static public InputStream replaceEnv(File file) throws IOException, SubstitutionException {
return replaceEnv(new FileInputStream(file));
}
/**
* Creates an InputStream containing the document resulting from replacing template
* parameters in the given InputStream source, using System.getenv as names/values.
* @param source The source stream
* @return An InputStream containing the resulting document.
*/
static public InputStream replaceEnv(InputStream source) throws IOException, SubstitutionException {
String template = streamToString(source);
String replaced = StringUtil.substituteWithEnvironment(template);
System.err.println(template);
System.err.println(replaced);
return new ByteArrayInputStream(replaced.getBytes());
}
/**
* Loads the given file into a Properties object.
* @param file The file to load
* @return Properties loaded from the file
*/
static public Properties loadProperties(File file) throws IOException {
return loadProperties(null, file);
}
/**
* Loads the given file into a Properties object.
* @param base Properties that should override those loaded from the file
* @param file The file to load
* @return Properties loaded from the file
*/
static public Properties loadProperties(Properties base, File file) throws IOException {
FileReader reader = new FileReader(file);
Properties props = new Properties();
props.load(reader);
if (base != null) props.putAll(base);
reader.close();
return props;
}
static private String streamToString(InputStream source) throws IOException {
InputStream is = new BufferedInputStream(source);
try {
return StringUtil.readToString(is);
} finally {
is.close();
}
}
}