All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.jetty.start.Props Maven / Gradle / Ivy

There is a newer version: 12.0.13
Show newest version
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//

package org.eclipse.jetty.start;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Stack;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.jetty.start.Props.Prop;

import static org.eclipse.jetty.start.UsageException.ERR_BAD_ARG;

/**
 * Management of Properties.
 * 

* This is larger in scope than the standard {@link java.util.Properties}, as it will also handle tracking the origin of each property, if it was overridden, * and also allowing for ${property} expansion. */ public final class Props implements Iterable { private static final Pattern __propertyPattern = Pattern.compile("(?<=[^$]|^)\\$\\{([^}]*)\\}"); public static class Prop { public String key; public String value; public String source; public Prop(String key, String value, String source) { this.key = key; this.value = value; this.source = source; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("Prop [key="); builder.append(key); builder.append(", value="); builder.append(value); builder.append(", source="); builder.append(source); builder.append("]"); return builder.toString(); } } public static final String ORIGIN_SYSPROP = ""; public static String getValue(String arg) { int idx = arg.indexOf('='); if (idx == (-1)) { throw new UsageException(ERR_BAD_ARG, "Argument is missing a required value: %s", arg); } String value = arg.substring(idx + 1).trim(); if (value.length() <= 0) { throw new UsageException(ERR_BAD_ARG, "Argument is missing a required value: %s", arg); } return value; } public static List getValues(String arg) { String v = getValue(arg); ArrayList l = new ArrayList<>(); for (String s : v.split(",")) { if (s != null) { s = s.trim(); if (s.length() > 0) { l.add(s); } } } return l; } private Map props = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); private List sysPropTracking = new ArrayList<>(); public void addAll(Props other) { this.props.putAll(other.props); this.sysPropTracking.addAll(other.sysPropTracking); } /** * Add a potential argument as a property. *

* If arg is not a property, ignore it. * * @param arg the argument to parse for a potential property * @param source the source for this argument (to track origin of property from) * @return true if the property was added, false if the property wasn't added */ public boolean addPossibleProperty(String arg, String source) { // Start property (syntax similar to System property) if (arg.startsWith("-D")) { String[] assign = arg.substring(2).split("=", 2); switch (assign.length) { case 2: setSystemProperty(assign[0], assign[1]); setProperty(assign[0], assign[1], source); return true; case 1: setSystemProperty(assign[0], ""); setProperty(assign[0], "", source); return true; default: return false; } } // Is this a raw property declaration? int idx = arg.indexOf('='); if (idx >= 0) { String key = arg.substring(0, idx); String value = arg.substring(idx + 1); setProperty(key, value, source); return true; } // All other strings are ignored return false; } public String cleanReference(String property) { String name = property.trim(); if (name.startsWith("${") && name.endsWith("}")) { name = name.substring(2, name.length() - 1); } return name.trim(); } public boolean containsKey(String key) { Prop prop = props.get(key); return prop != null && prop.value != null; } public String expand(String str) { return expand(str, new Stack()); } private String expand(String str, Stack seenStack) { if (str == null) { return str; } if (str.indexOf("${") < 0) { // Contains no potential expressions. return str; } Matcher mat = __propertyPattern.matcher(str); StringBuilder expanded = new StringBuilder(); int offset = 0; String property; String value; while (mat.find(offset)) { property = mat.group(1); // Loop detection if (seenStack.contains(property)) { StringBuilder err = new StringBuilder(); err.append("Property expansion loop detected: "); int idx = seenStack.lastIndexOf(property); for (int i = idx; i < seenStack.size(); i++) { err.append(seenStack.get(i)); err.append(" -> "); } err.append(property); throw new PropsException(err.toString()); } // find property name expanded.append(str.subSequence(offset, mat.start())); // get property value value = getString(property); if (value == null) { StartLog.trace("Unable to expand: %s", property); expanded.append(mat.group()); } else { // recursively expand seenStack.push(property); value = expand(value, seenStack); seenStack.pop(); expanded.append(value); } // update offset offset = mat.end(); } // leftover expanded.append(str.substring(offset)); // special case for "$$" if (expanded.indexOf("$$") >= 0) { return expanded.toString().replaceAll("\\$\\$", "\\$"); } return expanded.toString(); } public Prop getProp(String key) { return getProp(key, true); } public Prop getProp(String key, boolean searchSystemProps) { Prop prop = props.get(key); if ((prop == null) && searchSystemProps) { // try system property prop = getSystemProperty(key); } return prop; } public String getString(String key) { if (key == null) { throw new PropsException("Cannot get value for null key"); } String name = cleanReference(key); if (name.length() == 0) { throw new PropsException("Cannot get value for empty key"); } Prop prop = getProp(name); if (prop == null) { return null; } return prop.value; } public String getString(String key, String defVal) { String val = getString(key); if (val == null) { return defVal; } return val; } private Prop getSystemProperty(String key) { String value = System.getProperty(key); if (value == null) { return null; } return new Prop(key, value, ORIGIN_SYSPROP); } public static boolean hasPropertyKey(String name) { return __propertyPattern.matcher(name).find(); } @Override public Iterator iterator() { return props.values().iterator(); } public void reset() { props.clear(); } public void setProperty(Prop prop) { props.put(prop.key, prop); } public void setProperty(String key, String value, String origin) { props.put(key, new Prop(key, value, origin)); } public int size() { return props.size(); } public void store(OutputStream stream, String comments) throws IOException { Properties props = new Properties(); // add all Props as normal properties, with expansion performed. for (Prop prop : this) { props.setProperty(prop.key, expand(prop.value)); } // write normal properties file props.store(stream, comments); } public void setSystemProperty(String key, String value) { System.setProperty(key, value); sysPropTracking.add(key); } @Override public String toString() { return props.toString(); } public static Props load(ClassLoader classLoader, String resourceName) { StartLog.debug("Looking for classloader resource: %s", resourceName); return load(classLoader.getResource(resourceName)); } public static Props load(URL url) { Props props = new Props(); if (url != null) { StartLog.debug("Loading Props: %s", url.toExternalForm()); try (InputStream in = url.openStream()) { Properties properties = new Properties(); properties.load(in); String urlStr = url.toExternalForm(); properties.stringPropertyNames().forEach((name) -> props.setProperty(name, properties.getProperty(name), urlStr)); } catch (IOException x) { StartLog.debug(x); } } return props; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy