From f83fd471846736ee7cf6c440577c77759a50a0dd Mon Sep 17 00:00:00 2001
From: Dave Syer
+ * {@link Launcher} for archives with user-configured classpath and main class via a
+ * properties file. This model is often more flexible and more amenable to creating
+ * well-behaved OS-level services than a model based on executable jars.
+ *
+ * Looks in various places for a properties file to extract loader settings, defaulting to
+ * application.properties
either on the current classpath or in the current
+ * working directory. The name of the properties file can be changed by setting a System
+ * property loader.config.name
(e.g. -Dloader.config.name=foo
+ * will look for foo.properties
. If that file doesn't exist then tries
+ * loader.config.location
(with allowed prefixes classpath:
and
+ * file:
or any valid URL). Once that file is located turns it into
+ * Properties and extracts optional values (which can also be provided oroverridden as
+ * System properties in case the file doesn't exist):
+ *
+ *
+ *
+ * loader.path
: a comma-separated list of classpath directories
+ * (containing file resources and/or archives in *.jar or *.zip). Defaults to
+ * lib
(i.e. a directory in the current working directory)loader.main
: the main method to delegate execution to once the class
+ * loader is set up. No default, but will fall back to looking in a
+ * MANIFEST.MF
if there is one.
+ * + *
+ * + * @author Dave Syer + */ +public class PropertiesLauncher extends Launcher { + + /** + * Properties key for main class + */ + public static final String MAIN = "loader.main"; + + /** + * Properties key for classpath entries (directories possibly containing jars) + */ + public static final String PATH = "loader.path"; + + public static final String HOME = "loader.home"; + + public static String CONFIG_NAME = "loader.config.name"; + + public static String CONFIG_LOCATION = "loader.config.location"; + + private Logger logger = Logger.getLogger(Launcher.class.getName()); + + private static final Listapplication.properties
either on the current classpath or in the
+ * current working directory.
+ *
+ * @see org.springframework.boot.loader.Launcher#launch(java.lang.String[],
+ * org.springframework.boot.loader.Archive)
+ */
+ @Override
+ protected void launch(String[] args, Archive archive) throws Exception {
+ initialize();
+ super.launch(args, archive);
+ }
+
+ protected void initialize() throws Exception {
+ String config = SystemPropertyUtils.resolvePlaceholders(System.getProperty(
+ CONFIG_NAME, "application")) + ".properties";
+ while (config.startsWith("/")) {
+ config = config.substring(1);
+ }
+ this.logger.fine("Trying default location: " + config);
+ InputStream resource = getClass().getResourceAsStream("/" + config);
+ if (resource == null) {
+
+ config = SystemPropertyUtils.resolvePlaceholders(System.getProperty(
+ CONFIG_LOCATION, config));
+
+ if (config.startsWith("classpath:")) {
+
+ config = config.substring("classpath:".length());
+ while (config.startsWith("/")) {
+ config = config.substring(1);
+ }
+ config = "/" + config;
+ this.logger.fine("Trying classpath: " + config);
+ resource = getClass().getResourceAsStream(config);
+
+ }
+ else {
+
+ if (config.startsWith("file:")) {
+
+ config = config.substring("file:".length());
+ if (config.startsWith("//")) {
+ config = config.substring(2);
+ }
+
+ }
+ if (!config.contains(":")) {
+
+ File file = new File(config);
+ this.logger.fine("Trying file: " + config);
+ if (file.canRead()) {
+ resource = new FileInputStream(file);
+ }
+
+ }
+ else {
+
+ URL url = new URL(config);
+ if (exists(url)) {
+ URLConnection con = url.openConnection();
+ try {
+ resource = con.getInputStream();
+ }
+ catch (IOException ex) {
+ // Close the HTTP connection (if applicable).
+ if (con instanceof HttpURLConnection) {
+ ((HttpURLConnection) con).disconnect();
+ }
+ throw ex;
+ }
+ }
+ }
+ }
+ }
+ if (resource != null) {
+ this.logger.info("Found: " + config);
+ this.properties.load(resource);
+ try {
+ String path = System.getProperty(PATH);
+ if (path == null) {
+ path = this.properties.getProperty(PATH);
+ }
+ if (path != null) {
+ path = SystemPropertyUtils.resolvePlaceholders(path, true);
+ this.paths = new ArrayList
+ * Values for substitution can be supplied using a {@link Properties} instance or using a
+ * {@link PlaceholderResolver}.
+ *
+ * @author Juergen Hoeller
+ * @author Rob Harrop
+ * @since 3.0
+ */
+public class PropertyPlaceholderHelper {
+
+ private static final Map
+ * A text may contain {@code $ ...}} placeholders, to be resolved as system properties:
+ * e.g. {@code $ user.dir}}. Default values can be supplied using the ":" separator
+ * between key and value.
+ *
+ * @author Juergen Hoeller
+ * @author Rob Harrop
+ * @author Dave Syer
+ * @since 1.2.5
+ * @see #PLACEHOLDER_PREFIX
+ * @see #PLACEHOLDER_SUFFIX
+ * @see System#getProperty(String)
+ */
+public abstract class SystemPropertyUtils {
+
+ /** Prefix for system property placeholders: "${" */
+ public static final String PLACEHOLDER_PREFIX = "${";
+
+ /** Suffix for system property placeholders: "}" */
+ public static final String PLACEHOLDER_SUFFIX = "}";
+
+ /** Value separator for system property placeholders: ":" */
+ public static final String VALUE_SEPARATOR = ":";
+
+ private static final PropertyPlaceholderHelper strictHelper = new PropertyPlaceholderHelper(
+ PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX, VALUE_SEPARATOR, false);
+
+ private static final PropertyPlaceholderHelper nonStrictHelper = new PropertyPlaceholderHelper(
+ PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX, VALUE_SEPARATOR, true);
+
+ /**
+ * Resolve ${...} placeholders in the given text, replacing them with corresponding
+ * system property values.
+ * @param text the String to resolve
+ * @return the resolved String
+ * @see #PLACEHOLDER_PREFIX
+ * @see #PLACEHOLDER_SUFFIX
+ * @throws IllegalArgumentException if there is an unresolvable placeholder
+ */
+ public static String resolvePlaceholders(String text) {
+ return resolvePlaceholders(text, false);
+ }
+
+ /**
+ * Resolve ${...} placeholders in the given text, replacing them with corresponding
+ * system property values. Unresolvable placeholders with no default value are ignored
+ * and passed through unchanged if the flag is set to true.
+ * @param text the String to resolve
+ * @param ignoreUnresolvablePlaceholders flag to determine is unresolved placeholders
+ * are ignored
+ * @return the resolved String
+ * @see #PLACEHOLDER_PREFIX
+ * @see #PLACEHOLDER_SUFFIX
+ * @throws IllegalArgumentException if there is an unresolvable placeholder and the
+ * flag is false
+ */
+ public static String resolvePlaceholders(String text,
+ boolean ignoreUnresolvablePlaceholders) {
+ PropertyPlaceholderHelper helper = (ignoreUnresolvablePlaceholders ? nonStrictHelper
+ : strictHelper);
+ return helper.replacePlaceholders(text, new SystemPropertyPlaceholderResolver(
+ text));
+ }
+
+ private static class SystemPropertyPlaceholderResolver implements PlaceholderResolver {
+
+ private final String text;
+
+ public SystemPropertyPlaceholderResolver(String text) {
+ this.text = text;
+ }
+
+ @Override
+ public String resolvePlaceholder(String placeholderName) {
+ try {
+ String propVal = System.getProperty(placeholderName);
+ if (propVal == null) {
+ // Fall back to searching the system environment.
+ propVal = System.getenv(placeholderName);
+ }
+ return propVal;
+ }
+ catch (Throwable ex) {
+ System.err.println("Could not resolve placeholder '" + placeholderName
+ + "' in [" + this.text + "] as system property: " + ex);
+ return null;
+ }
+ }
+ }
+
+}
${name}
with the corresponding
+ * property from the supplied {@link Properties}.
+ * @param value the value containing the placeholders to be replaced.
+ * @param properties the {@code Properties} to use for replacement.
+ * @return the supplied value with placeholders replaced inline.
+ */
+ public String replacePlaceholders(String value, final Properties properties) {
+ Assert.notNull(properties, "Argument 'properties' must not be null.");
+ return replacePlaceholders(value, new PlaceholderResolver() {
+ @Override
+ public String resolvePlaceholder(String placeholderName) {
+ return properties.getProperty(placeholderName);
+ }
+ });
+ }
+
+ /**
+ * Replaces all placeholders of format {@code $ name} with the value returned from the
+ * supplied {@link PlaceholderResolver}.
+ * @param value the value containing the placeholders to be replaced.
+ * @param placeholderResolver the {@code PlaceholderResolver} to use for replacement.
+ * @return the supplied value with placeholders replaced inline.
+ */
+ public String replacePlaceholders(String value,
+ PlaceholderResolver placeholderResolver) {
+ Assert.notNull(value, "Argument 'value' must not be null.");
+ return parseStringValue(value, placeholderResolver, new HashSet