You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ab...@apache.org on 2018/05/08 21:15:31 UTC
[45/50] [abbrv] lucene-solr:jira/solr-11779: LUCENE-8261:
InterpolatedProperties.interpolate and recursive property references.
LUCENE-8261: InterpolatedProperties.interpolate and recursive property references.
Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/445c0aa4
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/445c0aa4
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/445c0aa4
Branch: refs/heads/jira/solr-11779
Commit: 445c0aa47e9962754c93bde1e07a24cd271e7d31
Parents: f9942b5
Author: Dawid Weiss <dw...@apache.org>
Authored: Mon May 7 13:22:11 2018 +0200
Committer: Dawid Weiss <dw...@apache.org>
Committed: Mon May 7 13:22:11 2018 +0200
----------------------------------------------------------------------
lucene/CHANGES.txt | 3 +
.../dependencies/InterpolatedProperties.java | 127 ++++++++++++++++---
2 files changed, 114 insertions(+), 16 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/445c0aa4/lucene/CHANGES.txt
----------------------------------------------------------------------
diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index ed6cc26..5ded39a 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -183,6 +183,9 @@ Bug Fixes
Other
+* LUCENE-8261: InterpolatedProperties.interpolate and recursive property
+ references. (Steve Rowe, Dawid Weiss)
+
* LUCENE-8228: removed obsolete IndexDeletionPolicy clone() requirements from
the javadoc. (Dawid Weiss)
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/445c0aa4/lucene/tools/src/java/org/apache/lucene/dependencies/InterpolatedProperties.java
----------------------------------------------------------------------
diff --git a/lucene/tools/src/java/org/apache/lucene/dependencies/InterpolatedProperties.java b/lucene/tools/src/java/org/apache/lucene/dependencies/InterpolatedProperties.java
index 159a803..2d5ca41 100644
--- a/lucene/tools/src/java/org/apache/lucene/dependencies/InterpolatedProperties.java
+++ b/lucene/tools/src/java/org/apache/lucene/dependencies/InterpolatedProperties.java
@@ -19,17 +19,28 @@ package org.apache.lucene.dependencies;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
import java.util.Map;
import java.util.Properties;
+import java.util.Set;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import java.util.stream.Collectors;
/**
* Parse a properties file, performing non-recursive Ant-like
* property value interpolation, and return the resulting Properties.
*/
public class InterpolatedProperties extends Properties {
- private static final Pattern PROPERTY_REFERENCE_PATTERN = Pattern.compile("\\$\\{([^}]+)\\}");
+ private static final Pattern PROPERTY_REFERENCE_PATTERN = Pattern.compile("\\$\\{(?<name>[^}]+)\\}");
/**
* Loads the properties file via {@link Properties#load(InputStream)},
@@ -46,26 +57,110 @@ public class InterpolatedProperties extends Properties {
*/
@Override
public void load(Reader reader) throws IOException {
- super.load(reader);
- interpolate();
+ Properties p = new Properties();
+ p.load(reader);
+
+ LinkedHashMap<String, String> props = new LinkedHashMap<>();
+ Enumeration<?> e = p.propertyNames();
+ while (e.hasMoreElements()) {
+ String key = (String) e.nextElement();
+ props.put(key, p.getProperty(key));
+ }
+
+ resolve(props).forEach((k, v) -> this.setProperty(k, v));
}
- /**
- * Perform non-recursive Ant-like property value interpolation
- */
- private void interpolate() {
- StringBuffer buffer = new StringBuffer();
- for (Map.Entry<?,?> entry : entrySet()) {
- buffer.setLength(0);
- Matcher matcher = PROPERTY_REFERENCE_PATTERN.matcher(entry.getValue().toString());
+ private static Map<String,String> resolve(Map<String,String> props) {
+ LinkedHashMap<String, String> resolved = new LinkedHashMap<>();
+ HashSet<String> recursive = new HashSet<>();
+ props.forEach((k, v) -> {
+ resolve(props, resolved, recursive, k, v);
+ });
+ return resolved;
+ }
+
+ private static String resolve(Map<String,String> props,
+ LinkedHashMap<String, String> resolved,
+ Set<String> recursive,
+ String key,
+ String value) {
+ if (value == null) {
+ throw new IllegalArgumentException("Missing replaced property key: " + key);
+ }
+
+ if (recursive.contains(key)) {
+ throw new IllegalArgumentException("Circular recursive property resolution: " + recursive);
+ }
+
+ if (!resolved.containsKey(key)) {
+ recursive.add(key);
+ StringBuffer buffer = new StringBuffer();
+ Matcher matcher = PROPERTY_REFERENCE_PATTERN.matcher(value);
while (matcher.find()) {
- String interpolatedValue = getProperty(matcher.group(1));
- if (null != interpolatedValue) {
- matcher.appendReplacement(buffer, interpolatedValue);
- }
+ String referenced = matcher.group("name");
+ String concrete = resolve(props, resolved, recursive, referenced, props.get(referenced));
+ matcher.appendReplacement(buffer, Matcher.quoteReplacement(concrete));
}
matcher.appendTail(buffer);
- setProperty((String) entry.getKey(), buffer.toString());
+ resolved.put(key, buffer.toString());
+ recursive.remove(key);
+ }
+ assert resolved.get(key).equals(value);
+ return resolved.get(key);
+ }
+
+ public static void main(String [] args) {
+ {
+ Map<String, String> props = new LinkedHashMap<>();
+ props.put("a", "${b}");
+ props.put("b", "${c}");
+ props.put("c", "foo");
+ props.put("d", "${a}/${b}/${c}");
+ assertEquals(resolve(props), "a=foo", "b=foo", "c=foo", "d=foo/foo/foo");
+ }
+
+ {
+ Map<String, String> props = new LinkedHashMap<>();
+ props.put("a", "foo");
+ props.put("b", "${a}");
+ assertEquals(resolve(props), "a=foo", "b=foo");
+ }
+
+ {
+ Map<String, String> props = new LinkedHashMap<>();
+ props.put("a", "${b}");
+ props.put("b", "${c}");
+ props.put("c", "${a}");
+ try {
+ resolve(props);
+ } catch (IllegalArgumentException e) {
+ // Expected, circular reference.
+ if (!e.getMessage().contains("Circular recursive")) {
+ throw new AssertionError();
+ }
+ }
+ }
+
+ {
+ Map<String, String> props = new LinkedHashMap<>();
+ props.put("a", "${b}");
+ try {
+ resolve(props);
+ } catch (IllegalArgumentException e) {
+ // Expected, no referenced value.
+ if (!e.getMessage().contains("Missing replaced")) {
+ throw new AssertionError();
+ }
+ }
+ }
+ }
+
+ private static void assertEquals(Map<String,String> resolved, String... keyValuePairs) {
+ List<String> result = resolved.entrySet().stream().sorted((a, b) -> a.getKey().compareTo(b.getKey()))
+ .map(e -> e.getKey() + "=" + e.getValue())
+ .collect(Collectors.toList());
+ if (!result.equals(Arrays.asList(keyValuePairs))) {
+ throw new AssertionError("Mismatch: \n" + result + "\nExpected: " + Arrays.asList(keyValuePairs));
}
}
}