com.ctrip.framework.apollo.spring.property.PlaceholderHelper Maven / Gradle / Ivy
The newest version!
package com.ctrip.framework.apollo.spring.property;
import com.google.common.base.Strings;
import com.google.common.collect.Sets;
import java.util.Set;
import java.util.Stack;
import java.util.Objects;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanExpressionContext;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.Scope;
import org.springframework.util.StringUtils;
/**
* Placeholder helper functions.
*/
public class PlaceholderHelper {
private static final String PLACEHOLDER_PREFIX = "${";
private static final String PLACEHOLDER_SUFFIX = "}";
private static final String VALUE_SEPARATOR = ":";
private static final String SIMPLE_PLACEHOLDER_PREFIX = "{";
private static final String EXPRESSION_PREFIX = "#{";
private static final String EXPRESSION_SUFFIX = "}";
/**
* Resolve placeholder property values, e.g.
* "${somePropertyValue}" "the actual property value"
*/
public Object resolvePropertyValue(ConfigurableBeanFactory beanFactory, String beanName, String placeholder) {
// resolve string value
String strVal = beanFactory.resolveEmbeddedValue(placeholder);
BeanDefinition bd = (beanFactory.containsBean(beanName) ? beanFactory
.getMergedBeanDefinition(beanName) : null);
// resolve expressions like "#{systemProperties.myProp}"
return evaluateBeanDefinitionString(beanFactory, strVal, bd);
}
private Object evaluateBeanDefinitionString(ConfigurableBeanFactory beanFactory, String value,
BeanDefinition beanDefinition) {
if (beanFactory.getBeanExpressionResolver() == null) {
return value;
}
Scope scope = (beanDefinition != null ? beanFactory
.getRegisteredScope(beanDefinition.getScope()) : null);
return beanFactory.getBeanExpressionResolver()
.evaluate(value, new BeanExpressionContext(beanFactory, scope));
}
/**
* Extract keys from placeholder, e.g.
*
* ${some.key} => "some.key"
* ${some.key:${some.other.key:100}} => "some.key", "some.other.key"
* ${${some.key}} => "some.key"
* ${${some.key:other.key}} => "some.key"
* ${${some.key}:${another.key}} => "some.key", "another.key"
* #{new java.text.SimpleDateFormat('${some.key}').parse('${another.key}')} => "some.key", "another.key"
*
*/
public Set extractPlaceholderKeys(String propertyString) {
Set placeholderKeys = Sets.newHashSet();
if (Strings.isNullOrEmpty(propertyString) || (!isNormalizedPlaceholder(propertyString) && !isExpressionWithPlaceholder(propertyString))) {
return placeholderKeys;
}
Stack stack = new Stack<>();
stack.push(propertyString);
while (!stack.isEmpty()) {
String strVal = stack.pop();
int startIndex = strVal.indexOf(PLACEHOLDER_PREFIX);
if (startIndex == -1) {
placeholderKeys.add(strVal);
continue;
}
int endIndex = findPlaceholderEndIndex(strVal, startIndex);
if (endIndex == -1) {
// invalid placeholder?
continue;
}
String placeholderCandidate = strVal.substring(startIndex + PLACEHOLDER_PREFIX.length(), endIndex);
// ${some.key:other.key}
if (placeholderCandidate.startsWith(PLACEHOLDER_PREFIX)) {
stack.push(placeholderCandidate);
} else {
// some.key:${some.other.key:100}
int separatorIndex = placeholderCandidate.indexOf(VALUE_SEPARATOR);
if (separatorIndex == -1) {
stack.push(placeholderCandidate);
} else {
stack.push(placeholderCandidate.substring(0, separatorIndex));
String defaultValuePart =
normalizeToPlaceholder(placeholderCandidate.substring(separatorIndex + VALUE_SEPARATOR.length()));
if (!Strings.isNullOrEmpty(defaultValuePart)) {
stack.push(defaultValuePart);
}
}
}
// has remaining part, e.g. ${a}.${b}
if (endIndex + PLACEHOLDER_SUFFIX.length() < strVal.length() - 1) {
String remainingPart = normalizeToPlaceholder(strVal.substring(endIndex + PLACEHOLDER_SUFFIX.length()));
if (!Strings.isNullOrEmpty(remainingPart)) {
stack.push(remainingPart);
}
}
}
return placeholderKeys;
}
private boolean isNormalizedPlaceholder(String propertyString) {
return propertyString.startsWith(PLACEHOLDER_PREFIX) && propertyString.endsWith(PLACEHOLDER_SUFFIX);
}
private boolean isExpressionWithPlaceholder(String propertyString) {
return propertyString.startsWith(EXPRESSION_PREFIX) && propertyString.endsWith(EXPRESSION_SUFFIX)
&& propertyString.contains(PLACEHOLDER_PREFIX);
}
private String normalizeToPlaceholder(String strVal) {
int startIndex = strVal.indexOf(PLACEHOLDER_PREFIX);
if (startIndex == -1) {
return null;
}
int endIndex = strVal.lastIndexOf(PLACEHOLDER_SUFFIX);
if (endIndex == -1) {
return null;
}
return strVal.substring(startIndex, endIndex + PLACEHOLDER_SUFFIX.length());
}
private int findPlaceholderEndIndex(CharSequence buf, int startIndex) {
int index = startIndex + PLACEHOLDER_PREFIX.length();
int withinNestedPlaceholder = 0;
while (index < buf.length()) {
if (StringUtils.substringMatch(buf, index, PLACEHOLDER_SUFFIX)) {
if (withinNestedPlaceholder > 0) {
withinNestedPlaceholder--;
index = index + PLACEHOLDER_SUFFIX.length();
} else {
return index;
}
} else if (StringUtils.substringMatch(buf, index, SIMPLE_PLACEHOLDER_PREFIX)) {
withinNestedPlaceholder++;
index = index + SIMPLE_PLACEHOLDER_PREFIX.length();
} else {
index++;
}
}
return -1;
}
}