/**
* Copyright 2011-2017 Asakusa Framework Team.
*
* 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.
*/
package com.asakusafw.yaess.core;
import java.text.MessageFormat;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Resolves variables in form of <code>${variable_name}</code>.
* @since 0.2.2
* @version 0.7.4
*/
public class VariableResolver {
static final Logger LOG = LoggerFactory.getLogger(VariableResolver.class);
private static final Pattern VARIABLE = Pattern.compile("\\$\\{(.*?)\\}");
private static final char SEPARATOR_DEFAULT_VALUE = '-';
private final Map<String, String> entries;
/**
* Creates a new instance.
* @param entries the variable key and its value pairs
* @throws IllegalArgumentException if any parameter is {@code null}
*/
public VariableResolver(Map<String, String> entries) {
if (entries == null) {
throw new IllegalArgumentException("entries must not be null"); //$NON-NLS-1$
}
this.entries = Collections.unmodifiableMap(new TreeMap<>(entries));
}
/**
* Creates a new instance from environment variables and system properties.
* If both have same entry, the system properties takes precedence over the environment variables.
* @return the created instance
*/
public static VariableResolver system() {
Map<String, String> entries = new HashMap<>();
entries.putAll(System.getenv());
for (Map.Entry<Object, Object> entry : System.getProperties().entrySet()) {
Object key = entry.getKey();
Object value = entry.getValue();
if (key instanceof String && value instanceof String) {
entries.put((String) key, (String) value);
}
}
return new VariableResolver(entries);
}
/**
* Replaces parameters in the target string.
* The parameters are represented as <code>${variable-name}</code>.
* @param string target string
* @param strict {@code false} to keep undefined parameters,
* or {@code true} to raise an exception
* @return replaced string
* @throws IllegalArgumentException if undefined parameters exist on strict mode,
* or any parameters contain {@code null}
*/
public String replace(String string, boolean strict) {
if (string == null) {
throw new IllegalArgumentException("string must not be null"); //$NON-NLS-1$
}
StringBuilder buf = new StringBuilder();
int start = 0;
Matcher matcher = VARIABLE.matcher(string);
while (matcher.find(start)) {
String placeholder = matcher.group(1);
String replacement = resolve(placeholder);
if (replacement == null) {
if (strict) {
throw new IllegalArgumentException(MessageFormat.format(
"parameter \"{0}\" is not defined in the list: {1}",
placeholder,
this));
} else {
buf.append(string.substring(start, matcher.start() + 1));
}
start = matcher.start() + 1;
} else {
buf.append(string.substring(start, matcher.start()));
buf.append(replacement);
start = matcher.end();
}
}
buf.append(string.substring(start));
return buf.toString();
}
private String resolve(String placeholder) {
String name;
String defaultValue;
int defaultAt = placeholder.indexOf(SEPARATOR_DEFAULT_VALUE);
if (defaultAt < 0) {
name = placeholder;
defaultValue = null;
} else {
name = placeholder.substring(0, defaultAt);
defaultValue = placeholder.substring(defaultAt + 1);
}
String replacement = entries.get(name);
if (replacement != null) {
return replacement;
}
return defaultValue;
}
@Override
public String toString() {
return entries.toString();
}
}