diff --git a/README.adoc b/README.adoc
index 32ca80a..b305fbe 100644
--- a/README.adoc
+++ b/README.adoc
@@ -4,6 +4,8 @@ image:https://api.travis-ci.org/xbib/content.svg[title="Build status", link="htt
image:https://img.shields.io/sonar/http/nemo.sonarqube.com/org.xbib%3Acontent/coverage.svg?style=flat-square[title="Coverage", link="https://sonarqube.com/dashboard/index?id=org.xbib%3Acontent"]
image:https://maven-badges.herokuapp.com/maven-central/org.xbib/content/badge.svg[title="Maven Central", link="http://search.maven.org/#search%7Cga%7C1%7Cxbib%20content"]
image:https://img.shields.io/badge/License-Apache%202.0-blue.svg[title="Apache License 2.0", link="https://opensource.org/licenses/Apache-2.0"]
+image:https://img.shields.io/twitter/url/https/twitter.com/xbib.svg?style=social&label=Follow%20%40xbib[title="Twitter", link="https://twitter.com/xbib"]
+image:https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif[title="PayPal", link="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=GVHFQYZ9WZ8HG"]
This is a Java library for processing structured data ("content") in the most popular formats, such as
JSON, SMILE-JSON, YAML, XML, CSV, and also semantic descriptions in RDF (N-Triples, Turtle, RDF/XML).
diff --git a/build.gradle b/build.gradle
index 05ab537..3685b3c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -14,7 +14,7 @@ ext {
allprojects {
group = 'org.xbib'
- version = '1.0.5'
+ version = '1.0.6'
apply plugin: 'java'
apply plugin: 'maven'
diff --git a/content-core/src/main/java/org/xbib/content/io/BytesStreamOutput.java b/content-core/src/main/java/org/xbib/content/io/BytesStreamOutput.java
index b8f7f6d..4a50eab 100644
--- a/content-core/src/main/java/org/xbib/content/io/BytesStreamOutput.java
+++ b/content-core/src/main/java/org/xbib/content/io/BytesStreamOutput.java
@@ -96,6 +96,9 @@ public class BytesStreamOutput extends OutputStream {
if (length == 0) {
return;
}
+ if ((long)count + length > Integer.MAX_VALUE) {
+ throw new IllegalArgumentException("overflow, stream output larger than " + Integer.MAX_VALUE);
+ }
int newcount = count + length;
if (newcount > buf.length) {
buf = Arrays.copyOf(buf, oversize(newcount));
diff --git a/content-core/src/main/java/org/xbib/content/settings/PlaceholderResolver.java b/content-core/src/main/java/org/xbib/content/settings/PlaceholderResolver.java
new file mode 100644
index 0000000..aed8c71
--- /dev/null
+++ b/content-core/src/main/java/org/xbib/content/settings/PlaceholderResolver.java
@@ -0,0 +1,16 @@
+package org.xbib.content.settings;
+
+/**
+ * Strategy interface used to resolve replacement values for placeholders contained in Strings.
+ */
+@FunctionalInterface
+public interface PlaceholderResolver {
+
+ /**
+ * Resolves the supplied placeholder name into the replacement value.
+ *
+ * @param placeholderName the name of the placeholder to resolve.
+ * @return the replacement value or null
if no replacement is to be made.
+ */
+ String resolvePlaceholder(String placeholderName);
+}
\ No newline at end of file
diff --git a/content-core/src/main/java/org/xbib/content/settings/PropertyPlaceholder.java b/content-core/src/main/java/org/xbib/content/settings/PropertyPlaceholder.java
new file mode 100644
index 0000000..0a2a219
--- /dev/null
+++ b/content-core/src/main/java/org/xbib/content/settings/PropertyPlaceholder.java
@@ -0,0 +1,120 @@
+package org.xbib.content.settings;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ *
+ */
+public class PropertyPlaceholder {
+
+ private final String placeholderPrefix;
+
+ private final String placeholderSuffix;
+
+ private final boolean ignoreUnresolvablePlaceholders;
+
+ /**
+ * Creates a new PropertyPlaceholderHelper
that uses the supplied prefix and suffix.
+ *
+ * @param placeholderPrefix the prefix that denotes the start of a placeholder.
+ * @param placeholderSuffix the suffix that denotes the end of a placeholder.
+ * @param ignoreUnresolvablePlaceholders indicates whether unresolvable placeholders should be ignored
+ * (true
) or cause an exception (false
).
+ */
+ public PropertyPlaceholder(String placeholderPrefix, String placeholderSuffix,
+ boolean ignoreUnresolvablePlaceholders) {
+ this.placeholderPrefix = placeholderPrefix;
+ this.placeholderSuffix = placeholderSuffix;
+ this.ignoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders;
+ }
+
+
+ /**
+ * Replaces all placeholders of format ${name}
with the value returned from the supplied {@link
+ * PlaceholderResolver}.
+ *
+ * @param value the value containing the placeholders to be replaced.
+ * @param placeholderResolver the PlaceholderResolver
to use for replacement.
+ * @return the supplied value with placeholders replaced inline.
+ */
+ public String replacePlaceholders(String value, PlaceholderResolver placeholderResolver) {
+ return parseStringValue(value, placeholderResolver, new HashSet());
+ }
+
+ protected String parseStringValue(String strVal, PlaceholderResolver placeholderResolver,
+ Set visitedPlaceholders) {
+ StringBuilder buf = new StringBuilder(strVal);
+ int startIndex = strVal.indexOf(this.placeholderPrefix);
+ while (startIndex != -1) {
+ int endIndex = findPlaceholderEndIndex(buf, startIndex);
+ if (endIndex != -1) {
+ String placeholder = buf.substring(startIndex + this.placeholderPrefix.length(), endIndex);
+ if (!visitedPlaceholders.add(placeholder)) {
+ throw new IllegalArgumentException(
+ "Circular placeholder reference '" + placeholder + "' in property definitions");
+ }
+ // Recursive invocation, parsing placeholders contained in the placeholder key.
+ placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);
+ // Now obtain the value for the fully resolved key...
+ int defaultValueIdx = placeholder.indexOf(':');
+ String defaultValue = null;
+ if (defaultValueIdx != -1) {
+ defaultValue = placeholder.substring(defaultValueIdx + 1);
+ placeholder = placeholder.substring(0, defaultValueIdx);
+ }
+ String propVal = placeholderResolver.resolvePlaceholder(placeholder);
+ if (propVal == null) {
+ propVal = defaultValue;
+ }
+ if (propVal != null) {
+ // Recursive invocation, parsing placeholders contained in the
+ // previously resolved placeholder value.
+ propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders);
+ buf.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
+ startIndex = buf.indexOf(this.placeholderPrefix, startIndex + propVal.length());
+ } else if (this.ignoreUnresolvablePlaceholders) {
+ // Proceed with unprocessed value.
+ startIndex = buf.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());
+ } else {
+ throw new IllegalArgumentException("Could not resolve placeholder '" + placeholder + "'");
+ }
+ visitedPlaceholders.remove(placeholder);
+ } else {
+ startIndex = -1;
+ }
+ }
+ return buf.toString();
+ }
+
+ private int findPlaceholderEndIndex(CharSequence buf, int startIndex) {
+ int index = startIndex + this.placeholderPrefix.length();
+ int withinNestedPlaceholder = 0;
+ while (index < buf.length()) {
+ if (substringMatch(buf, index, this.placeholderSuffix)) {
+ if (withinNestedPlaceholder > 0) {
+ withinNestedPlaceholder--;
+ index = index + this.placeholderPrefix.length() - 1;
+ } else {
+ return index;
+ }
+ } else if (substringMatch(buf, index, this.placeholderPrefix)) {
+ withinNestedPlaceholder++;
+ index = index + this.placeholderPrefix.length();
+ } else {
+ index++;
+ }
+ }
+ return -1;
+ }
+
+ private boolean substringMatch(CharSequence str, int index, CharSequence substring) {
+ for (int j = 0; j < substring.length(); j++) {
+ int i = index + j;
+ if (i >= str.length() || str.charAt(i) != substring.charAt(j)) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/content-core/src/main/java/org/xbib/content/settings/Settings.java b/content-core/src/main/java/org/xbib/content/settings/Settings.java
index 482a874..a44f1a0 100644
--- a/content-core/src/main/java/org/xbib/content/settings/Settings.java
+++ b/content-core/src/main/java/org/xbib/content/settings/Settings.java
@@ -23,11 +23,9 @@ import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -687,26 +685,31 @@ public class Settings {
* @return builder
*/
public Builder replacePropertyPlaceholders() {
- PropertyPlaceholder propertyPlaceholder = new PropertyPlaceholder("${", "}", false);
- PropertyPlaceholder.PlaceholderResolver placeholderResolver = placeholderName -> {
- // system property
- String value = System.getProperty(placeholderName);
- if (value != null) {
- return value;
- }
- // environment
- value = System.getenv(placeholderName);
- if (value != null) {
- return value;
- }
- // current date
- try {
- return DateTimeFormatter.ofPattern(placeholderName).format(LocalDate.now());
- } catch (IllegalArgumentException | DateTimeException e) {
- logger.log(Level.FINER, e.getMessage(), e);
- return map.get(placeholderName);
- }
- };
+ return replacePropertyPlaceholders(new PropertyPlaceholder("${", "}", false),
+ placeholderName -> {
+ // system property
+ String value = System.getProperty(placeholderName);
+ if (value != null) {
+ return value;
+ }
+ // environment
+ value = System.getenv(placeholderName);
+ if (value != null) {
+ return value;
+ }
+ // current date
+ try {
+ return DateTimeFormatter.ofPattern(placeholderName).format(LocalDate.now());
+ } catch (IllegalArgumentException | DateTimeException e) {
+ logger.log(Level.FINER, e.getMessage(), e);
+ return map.get(placeholderName);
+ }
+ }
+ );
+ }
+
+ public Builder replacePropertyPlaceholders(PropertyPlaceholder propertyPlaceholder,
+ PlaceholderResolver placeholderResolver) {
for (Map.Entry entry : map.entrySet()) {
map.put(entry.getKey(), propertyPlaceholder.replacePlaceholders(entry.getValue(), placeholderResolver));
}
@@ -717,133 +720,4 @@ public class Settings {
return new Settings(map);
}
}
-
- private static class PropertyPlaceholder {
-
- private final String placeholderPrefix;
-
- private final String placeholderSuffix;
-
- private final boolean ignoreUnresolvablePlaceholders;
-
- /**
- * Creates a new PropertyPlaceholderHelper
that uses the supplied prefix and suffix.
- *
- * @param placeholderPrefix the prefix that denotes the start of a placeholder.
- * @param placeholderSuffix the suffix that denotes the end of a placeholder.
- * @param ignoreUnresolvablePlaceholders indicates whether unresolvable placeholders should be ignored
- * (true
) or cause an exception (false
).
- */
- public PropertyPlaceholder(String placeholderPrefix, String placeholderSuffix,
- boolean ignoreUnresolvablePlaceholders) {
- this.placeholderPrefix = placeholderPrefix;
- this.placeholderSuffix = placeholderSuffix;
- this.ignoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders;
- }
-
-
- /**
- * Replaces all placeholders of format ${name}
with the value returned from the supplied {@link
- * PlaceholderResolver}.
- *
- * @param value the value containing the placeholders to be replaced.
- * @param placeholderResolver the PlaceholderResolver
to use for replacement.
- * @return the supplied value with placeholders replaced inline.
- */
- public String replacePlaceholders(String value, PlaceholderResolver placeholderResolver) {
- return parseStringValue(value, placeholderResolver, new HashSet());
- }
-
- protected String parseStringValue(String strVal, PlaceholderResolver placeholderResolver,
- Set visitedPlaceholders) {
- StringBuilder buf = new StringBuilder(strVal);
- int startIndex = strVal.indexOf(this.placeholderPrefix);
- while (startIndex != -1) {
- int endIndex = findPlaceholderEndIndex(buf, startIndex);
- if (endIndex != -1) {
- String placeholder = buf.substring(startIndex + this.placeholderPrefix.length(), endIndex);
- if (!visitedPlaceholders.add(placeholder)) {
- throw new IllegalArgumentException(
- "Circular placeholder reference '" + placeholder + "' in property definitions");
- }
- // Recursive invocation, parsing placeholders contained in the placeholder key.
- placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);
-
- // Now obtain the value for the fully resolved key...
- int defaultValueIdx = placeholder.indexOf(':');
- String defaultValue = null;
- if (defaultValueIdx != -1) {
- defaultValue = placeholder.substring(defaultValueIdx + 1);
- placeholder = placeholder.substring(0, defaultValueIdx);
- }
- String propVal = placeholderResolver.resolvePlaceholder(placeholder);
- if (propVal == null) {
- propVal = defaultValue;
- }
- if (propVal != null) {
- // Recursive invocation, parsing placeholders contained in the
- // previously resolved placeholder value.
- propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders);
- buf.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
- startIndex = buf.indexOf(this.placeholderPrefix, startIndex + propVal.length());
- } else if (this.ignoreUnresolvablePlaceholders) {
- // Proceed with unprocessed value.
- startIndex = buf.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());
- } else {
- throw new IllegalArgumentException("Could not resolve placeholder '" + placeholder + "'");
- }
- visitedPlaceholders.remove(placeholder);
- } else {
- startIndex = -1;
- }
- }
- return buf.toString();
- }
-
- private int findPlaceholderEndIndex(CharSequence buf, int startIndex) {
- int index = startIndex + this.placeholderPrefix.length();
- int withinNestedPlaceholder = 0;
- while (index < buf.length()) {
- if (substringMatch(buf, index, this.placeholderSuffix)) {
- if (withinNestedPlaceholder > 0) {
- withinNestedPlaceholder--;
- index = index + this.placeholderPrefix.length() - 1;
- } else {
- return index;
- }
- } else if (substringMatch(buf, index, this.placeholderPrefix)) {
- withinNestedPlaceholder++;
- index = index + this.placeholderPrefix.length();
- } else {
- index++;
- }
- }
- return -1;
- }
-
- private boolean substringMatch(CharSequence str, int index, CharSequence substring) {
- for (int j = 0; j < substring.length(); j++) {
- int i = index + j;
- if (i >= str.length() || str.charAt(i) != substring.charAt(j)) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Strategy interface used to resolve replacement values for placeholders contained in Strings.
- */
- @FunctionalInterface
- public interface PlaceholderResolver {
-
- /**
- * Resolves the supplied placeholder name into the replacement value.
- *
- * @param placeholderName the name of the placeholder to resolve.
- * @return the replacement value or null
if no replacement is to be made.
- */
- String resolvePlaceholder(String placeholderName);
- }
- }
}