/*
* Copyright (c) 2002-2012 Alibaba Group Holding Limited.
* All rights reserved.
*
* 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.alibaba.citrus.service.configuration.support;
import static com.alibaba.citrus.util.Assert.*;
import static com.alibaba.citrus.util.CollectionUtil.*;
import static com.alibaba.citrus.util.StringUtil.*;
import java.util.List;
import java.util.Properties;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.StringUtils;
/**
* 扩展Spring的
* {@link org.springframework.beans.factory.config.PropertyPlaceholderConfigurer}
* ,增加默认值的功能。
* <p>
* 例如:<code>${placeholder:defaultValue}</code>,假如placeholder的值不存在,则默认取得
* <code>defaultValue</code>。
* </p>
* <p>
* 此外,该类自身的location也可以包含placeholder且支持默认值,例如:
* </p>
* <p/>
* <pre>
* <services:property-placeholder location="${props:default.properties}" />
* </pre>
* <p>
* 假如未指定-Dprops=xyz,那么就取默认值:<code>default.properties</code>。
* </p>
*
* @author Michael Zhou
*/
public class PropertyPlaceholderConfigurer extends
org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
implements ResourceLoaderAware,
InitializingBean {
private static final String PLACEHOLDER_PREFIX = "${";
private static final String PLACEHOLDER_SUFFIX = "}";
private ResourceLoader loader;
private String locationNames;
public PropertyPlaceholderConfigurer() {
setIgnoreUnresolvablePlaceholders(true); // 默认值
}
public void setResourceLoader(ResourceLoader loader) {
this.loader = loader;
}
public void setLocationNames(String locations) {
this.locationNames = locations;
}
public void afterPropertiesSet() throws Exception {
assertNotNull(loader, "no resourceLoader");
if (locationNames != null) {
locationNames = resolveSystemPropertyPlaceholders(locationNames);
}
if (StringUtils.hasLength(locationNames)) {
String[] locations = StringUtils.commaDelimitedListToStringArray(locationNames);
List<Resource> resources = createArrayList(locations.length);
for (String location : locations) {
location = trimToNull(location);
if (location != null) {
resources.add(loader.getResource(location));
}
}
super.setLocations(resources.toArray(new Resource[resources.size()]));
}
}
private String resolveSystemPropertyPlaceholders(String text) {
StringBuilder buf = new StringBuilder(text);
for (int startIndex = buf.indexOf(PLACEHOLDER_PREFIX); startIndex >= 0; ) {
int endIndex = buf.indexOf(PLACEHOLDER_SUFFIX, startIndex + PLACEHOLDER_PREFIX.length());
if (endIndex != -1) {
String placeholder = buf.substring(startIndex + PLACEHOLDER_PREFIX.length(), endIndex);
int nextIndex = endIndex + PLACEHOLDER_SUFFIX.length();
try {
String value = resolveSystemPropertyPlaceholder(placeholder);
if (value != null) {
buf.replace(startIndex, endIndex + PLACEHOLDER_SUFFIX.length(), value);
nextIndex = startIndex + value.length();
} else {
System.err.println("Could not resolve placeholder '" + placeholder + "' in [" + text
+ "] as system property: neither system property nor environment variable found");
}
} catch (Throwable ex) {
System.err.println("Could not resolve placeholder '" + placeholder + "' in [" + text
+ "] as system property: " + ex);
}
startIndex = buf.indexOf(PLACEHOLDER_PREFIX, nextIndex);
} else {
startIndex = -1;
}
}
return buf.toString();
}
private String resolveSystemPropertyPlaceholder(String placeholder) {
DefaultablePlaceholder dp = new DefaultablePlaceholder(placeholder);
String value = System.getProperty(dp.placeholder);
if (value == null) {
value = System.getenv(dp.placeholder);
}
if (value == null) {
value = dp.defaultValue;
}
return value;
}
@Override
protected String resolvePlaceholder(String placeholder, Properties props, int systemPropertiesMode) {
DefaultablePlaceholder dp = new DefaultablePlaceholder(placeholder);
String value = super.resolvePlaceholder(dp.placeholder, props, systemPropertiesMode);
if (value == null) {
value = dp.defaultValue;
}
return value;
}
private static class DefaultablePlaceholder {
private final String defaultValue;
private final String placeholder;
public DefaultablePlaceholder(String placeholder) {
int commaIndex = placeholder.indexOf(":");
String defaultValue = null;
if (commaIndex >= 0) {
defaultValue = trimToEmpty(placeholder.substring(commaIndex + 1));
placeholder = trimToEmpty(placeholder.substring(0, commaIndex));
}
this.placeholder = placeholder;
this.defaultValue = defaultValue;
}
}
}