mirror of
https://gitee.com/arthas/arthas.git
synced 2024-12-02 04:08:34 +08:00
support ArthasEnvironment. #986
This commit is contained in:
parent
558137a581
commit
f5270aba36
@ -134,6 +134,7 @@
|
||||
<groupId>com.taobao.middleware</groupId>
|
||||
<artifactId>logger.api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
@ -161,6 +162,12 @@
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.benf</groupId>
|
||||
<artifactId>cfr</artifactId>
|
||||
|
226
core/src/main/java/com/taobao/arthas/core/env/AbstractPropertyResolver.java
vendored
Normal file
226
core/src/main/java/com/taobao/arthas/core/env/AbstractPropertyResolver.java
vendored
Normal file
@ -0,0 +1,226 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.taobao.arthas.core.env;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Abstract base class for resolving properties against any underlying source.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
public abstract class AbstractPropertyResolver implements ConfigurablePropertyResolver {
|
||||
|
||||
protected ConfigurableConversionService conversionService = new DefaultConversionService();
|
||||
|
||||
private PropertyPlaceholderHelper nonStrictHelper;
|
||||
|
||||
private PropertyPlaceholderHelper strictHelper;
|
||||
|
||||
private boolean ignoreUnresolvableNestedPlaceholders = false;
|
||||
|
||||
private String placeholderPrefix = SystemPropertyUtils.PLACEHOLDER_PREFIX;
|
||||
|
||||
private String placeholderSuffix = SystemPropertyUtils.PLACEHOLDER_SUFFIX;
|
||||
|
||||
private String valueSeparator = SystemPropertyUtils.VALUE_SEPARATOR;
|
||||
|
||||
private final Set<String> requiredProperties = new LinkedHashSet<String>();
|
||||
|
||||
public ConfigurableConversionService getConversionService() {
|
||||
return this.conversionService;
|
||||
}
|
||||
|
||||
public void setConversionService(ConfigurableConversionService conversionService) {
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the prefix that placeholders replaced by this resolver must begin with.
|
||||
* <p>
|
||||
* The default is "${".
|
||||
*
|
||||
* @see org.springframework.util.SystemPropertyUtils#PLACEHOLDER_PREFIX
|
||||
*/
|
||||
@Override
|
||||
public void setPlaceholderPrefix(String placeholderPrefix) {
|
||||
this.placeholderPrefix = placeholderPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the suffix that placeholders replaced by this resolver must end with.
|
||||
* <p>
|
||||
* The default is "}".
|
||||
*
|
||||
* @see org.springframework.util.SystemPropertyUtils#PLACEHOLDER_SUFFIX
|
||||
*/
|
||||
@Override
|
||||
public void setPlaceholderSuffix(String placeholderSuffix) {
|
||||
this.placeholderSuffix = placeholderSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the separating character between the placeholders replaced by this
|
||||
* resolver and their associated default value, or {@code null} if no such
|
||||
* special character should be processed as a value separator.
|
||||
* <p>
|
||||
* The default is ":".
|
||||
*
|
||||
* @see org.springframework.util.SystemPropertyUtils#VALUE_SEPARATOR
|
||||
*/
|
||||
@Override
|
||||
public void setValueSeparator(String valueSeparator) {
|
||||
this.valueSeparator = valueSeparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to throw an exception when encountering an unresolvable
|
||||
* placeholder nested within the value of a given property. A {@code false}
|
||||
* value indicates strict resolution, i.e. that an exception will be thrown. A
|
||||
* {@code true} value indicates that unresolvable nested placeholders should be
|
||||
* passed through in their unresolved ${...} form.
|
||||
* <p>
|
||||
* The default is {@code false}.
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
@Override
|
||||
public void setIgnoreUnresolvableNestedPlaceholders(boolean ignoreUnresolvableNestedPlaceholders) {
|
||||
this.ignoreUnresolvableNestedPlaceholders = ignoreUnresolvableNestedPlaceholders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRequiredProperties(String... requiredProperties) {
|
||||
for (String key : requiredProperties) {
|
||||
this.requiredProperties.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateRequiredProperties() {
|
||||
MissingRequiredPropertiesException ex = new MissingRequiredPropertiesException();
|
||||
for (String key : this.requiredProperties) {
|
||||
if (this.getProperty(key) == null) {
|
||||
ex.addMissingRequiredProperty(key);
|
||||
}
|
||||
}
|
||||
if (!ex.getMissingRequiredProperties().isEmpty()) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsProperty(String key) {
|
||||
return (getProperty(key) != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProperty(String key) {
|
||||
return getProperty(key, String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProperty(String key, String defaultValue) {
|
||||
String value = getProperty(key);
|
||||
return (value != null ? value : defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getProperty(String key, Class<T> targetType, T defaultValue) {
|
||||
T value = getProperty(key, targetType);
|
||||
return (value != null ? value : defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRequiredProperty(String key) throws IllegalStateException {
|
||||
String value = getProperty(key);
|
||||
if (value == null) {
|
||||
throw new IllegalStateException("Required key '" + key + "' not found");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getRequiredProperty(String key, Class<T> valueType) throws IllegalStateException {
|
||||
T value = getProperty(key, valueType);
|
||||
if (value == null) {
|
||||
throw new IllegalStateException("Required key '" + key + "' not found");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resolvePlaceholders(String text) {
|
||||
if (this.nonStrictHelper == null) {
|
||||
this.nonStrictHelper = createPlaceholderHelper(true);
|
||||
}
|
||||
return doResolvePlaceholders(text, this.nonStrictHelper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
|
||||
if (this.strictHelper == null) {
|
||||
this.strictHelper = createPlaceholderHelper(false);
|
||||
}
|
||||
return doResolvePlaceholders(text, this.strictHelper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve placeholders within the given string, deferring to the value of
|
||||
* {@link #setIgnoreUnresolvableNestedPlaceholders} to determine whether any
|
||||
* unresolvable placeholders should raise an exception or be ignored.
|
||||
* <p>
|
||||
* Invoked from {@link #getProperty} and its variants, implicitly resolving
|
||||
* nested placeholders. In contrast, {@link #resolvePlaceholders} and
|
||||
* {@link #resolveRequiredPlaceholders} do <i>not</i> delegate to this method
|
||||
* but rather perform their own handling of unresolvable placeholders, as
|
||||
* specified by each of those methods.
|
||||
*
|
||||
* @since 3.2
|
||||
* @see #setIgnoreUnresolvableNestedPlaceholders
|
||||
*/
|
||||
protected String resolveNestedPlaceholders(String value) {
|
||||
return (this.ignoreUnresolvableNestedPlaceholders ? resolvePlaceholders(value)
|
||||
: resolveRequiredPlaceholders(value));
|
||||
}
|
||||
|
||||
private PropertyPlaceholderHelper createPlaceholderHelper(boolean ignoreUnresolvablePlaceholders) {
|
||||
return new PropertyPlaceholderHelper(this.placeholderPrefix, this.placeholderSuffix, this.valueSeparator,
|
||||
ignoreUnresolvablePlaceholders);
|
||||
}
|
||||
|
||||
private String doResolvePlaceholders(String text, PropertyPlaceholderHelper helper) {
|
||||
return helper.replacePlaceholders(text, new PropertyPlaceholderHelper.PlaceholderResolver() {
|
||||
public String resolvePlaceholder(String placeholderName) {
|
||||
return getPropertyAsRawString(placeholderName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the specified property as a raw String, i.e. without resolution of
|
||||
* nested placeholders.
|
||||
*
|
||||
* @param key the property name to resolve
|
||||
* @return the property value or {@code null} if none found
|
||||
*/
|
||||
protected abstract String getPropertyAsRawString(String key);
|
||||
|
||||
}
|
122
core/src/main/java/com/taobao/arthas/core/env/ArthasEnvironment.java
vendored
Normal file
122
core/src/main/java/com/taobao/arthas/core/env/ArthasEnvironment.java
vendored
Normal file
@ -0,0 +1,122 @@
|
||||
package com.taobao.arthas.core.env;
|
||||
|
||||
import java.security.AccessControlException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hengyunabc 2019-12-27
|
||||
*
|
||||
*/
|
||||
public class ArthasEnvironment implements Environment {
|
||||
/** System environment property source name: {@value}. */
|
||||
public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";
|
||||
|
||||
/** JVM system properties property source name: {@value}. */
|
||||
public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";
|
||||
|
||||
private final MutablePropertySources propertySources = new MutablePropertySources();
|
||||
|
||||
private final ConfigurablePropertyResolver propertyResolver = new PropertySourcesPropertyResolver(
|
||||
this.propertySources);
|
||||
|
||||
public ArthasEnvironment() {
|
||||
propertySources
|
||||
.addLast(new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
|
||||
propertySources.addLast(
|
||||
new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given property source object with lowest precedence.
|
||||
*/
|
||||
public void addLast(PropertySource<?> propertySource) {
|
||||
this.propertySources.addLast(propertySource);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public Map<String, Object> getSystemProperties() {
|
||||
try {
|
||||
return (Map) System.getProperties();
|
||||
} catch (AccessControlException ex) {
|
||||
return (Map) new ReadOnlySystemAttributesMap() {
|
||||
@Override
|
||||
protected String getSystemAttribute(String attributeName) {
|
||||
try {
|
||||
return System.getProperty(attributeName);
|
||||
} catch (AccessControlException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public Map<String, Object> getSystemEnvironment() {
|
||||
try {
|
||||
return (Map) System.getenv();
|
||||
} catch (AccessControlException ex) {
|
||||
return (Map) new ReadOnlySystemAttributesMap() {
|
||||
@Override
|
||||
protected String getSystemAttribute(String attributeName) {
|
||||
try {
|
||||
return System.getenv(attributeName);
|
||||
} catch (AccessControlException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Implementation of PropertyResolver interface
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public boolean containsProperty(String key) {
|
||||
return this.propertyResolver.containsProperty(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProperty(String key) {
|
||||
return this.propertyResolver.getProperty(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProperty(String key, String defaultValue) {
|
||||
return this.propertyResolver.getProperty(key, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getProperty(String key, Class<T> targetType) {
|
||||
return this.propertyResolver.getProperty(key, targetType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getProperty(String key, Class<T> targetType, T defaultValue) {
|
||||
return this.propertyResolver.getProperty(key, targetType, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRequiredProperty(String key) throws IllegalStateException {
|
||||
return this.propertyResolver.getRequiredProperty(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getRequiredProperty(String key, Class<T> targetType) throws IllegalStateException {
|
||||
return this.propertyResolver.getRequiredProperty(key, targetType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resolvePlaceholders(String text) {
|
||||
return this.propertyResolver.resolvePlaceholders(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
|
||||
return this.propertyResolver.resolveRequiredPlaceholders(text);
|
||||
}
|
||||
|
||||
}
|
37
core/src/main/java/com/taobao/arthas/core/env/ConfigurableConversionService.java
vendored
Normal file
37
core/src/main/java/com/taobao/arthas/core/env/ConfigurableConversionService.java
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.taobao.arthas.core.env;
|
||||
|
||||
/**
|
||||
* Configuration interface to be implemented by most if not all
|
||||
* {@link ConversionService} types. Consolidates the read-only operations
|
||||
* exposed by {@link ConversionService} and the mutating operations of
|
||||
* {@link ConverterRegistry} to allow for convenient ad-hoc addition and removal
|
||||
* of {@link org.springframework.core.convert.converter.Converter Converters}
|
||||
* through. The latter is particularly useful when working against a
|
||||
* {@link org.springframework.core.env.ConfigurableEnvironment
|
||||
* ConfigurableEnvironment} instance in application context bootstrapping code.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see org.springframework.core.env.ConfigurablePropertyResolver#getConversionService()
|
||||
* @see org.springframework.core.env.ConfigurableEnvironment
|
||||
* @see org.springframework.context.ConfigurableApplicationContext#getEnvironment()
|
||||
*/
|
||||
public interface ConfigurableConversionService extends ConversionService {
|
||||
|
||||
}
|
111
core/src/main/java/com/taobao/arthas/core/env/ConfigurablePropertyResolver.java
vendored
Normal file
111
core/src/main/java/com/taobao/arthas/core/env/ConfigurablePropertyResolver.java
vendored
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.taobao.arthas.core.env;
|
||||
|
||||
/**
|
||||
* Configuration interface to be implemented by most if not all
|
||||
* {@link PropertyResolver} types. Provides facilities for accessing and
|
||||
* customizing the {@link org.springframework.core.convert.ConversionService
|
||||
* ConversionService} used when converting property values from one type to
|
||||
* another.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface ConfigurablePropertyResolver extends PropertyResolver {
|
||||
|
||||
/**
|
||||
* Return the {@link ConfigurableConversionService} used when performing type
|
||||
* conversions on properties.
|
||||
* <p>
|
||||
* The configurable nature of the returned conversion service allows for the
|
||||
* convenient addition and removal of individual {@code Converter} instances:
|
||||
*
|
||||
* <pre class="code">
|
||||
* ConfigurableConversionService cs = env.getConversionService();
|
||||
* cs.addConverter(new FooConverter());
|
||||
* </pre>
|
||||
*
|
||||
* @see PropertyResolver#getProperty(String, Class)
|
||||
* @see org.springframework.core.convert.converter.ConverterRegistry#addConverter
|
||||
*/
|
||||
ConfigurableConversionService getConversionService();
|
||||
|
||||
/**
|
||||
* Set the {@link ConfigurableConversionService} to be used when performing type
|
||||
* conversions on properties.
|
||||
* <p>
|
||||
* <strong>Note:</strong> as an alternative to fully replacing the
|
||||
* {@code ConversionService}, consider adding or removing individual
|
||||
* {@code Converter} instances by drilling into {@link #getConversionService()}
|
||||
* and calling methods such as {@code #addConverter}.
|
||||
*
|
||||
* @see PropertyResolver#getProperty(String, Class)
|
||||
* @see #getConversionService()
|
||||
* @see org.springframework.core.convert.converter.ConverterRegistry#addConverter
|
||||
*/
|
||||
void setConversionService(ConfigurableConversionService conversionService);
|
||||
|
||||
/**
|
||||
* Set the prefix that placeholders replaced by this resolver must begin with.
|
||||
*/
|
||||
void setPlaceholderPrefix(String placeholderPrefix);
|
||||
|
||||
/**
|
||||
* Set the suffix that placeholders replaced by this resolver must end with.
|
||||
*/
|
||||
void setPlaceholderSuffix(String placeholderSuffix);
|
||||
|
||||
/**
|
||||
* Specify the separating character between the placeholders replaced by this
|
||||
* resolver and their associated default value, or {@code null} if no such
|
||||
* special character should be processed as a value separator.
|
||||
*/
|
||||
void setValueSeparator(String valueSeparator);
|
||||
|
||||
/**
|
||||
* Set whether to throw an exception when encountering an unresolvable
|
||||
* placeholder nested within the value of a given property. A {@code false}
|
||||
* value indicates strict resolution, i.e. that an exception will be thrown. A
|
||||
* {@code true} value indicates that unresolvable nested placeholders should be
|
||||
* passed through in their unresolved ${...} form.
|
||||
* <p>
|
||||
* Implementations of {@link #getProperty(String)} and its variants must inspect
|
||||
* the value set here to determine correct behavior when property values contain
|
||||
* unresolvable placeholders.
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
void setIgnoreUnresolvableNestedPlaceholders(boolean ignoreUnresolvableNestedPlaceholders);
|
||||
|
||||
/**
|
||||
* Specify which properties must be present, to be verified by
|
||||
* {@link #validateRequiredProperties()}.
|
||||
*/
|
||||
void setRequiredProperties(String... requiredProperties);
|
||||
|
||||
/**
|
||||
* Validate that each of the properties specified by
|
||||
* {@link #setRequiredProperties} is present and resolves to a non-{@code null}
|
||||
* value.
|
||||
*
|
||||
* @throws MissingRequiredPropertiesException if any of the required properties
|
||||
* are not resolvable.
|
||||
*/
|
||||
void validateRequiredProperties() throws MissingRequiredPropertiesException;
|
||||
|
||||
}
|
63
core/src/main/java/com/taobao/arthas/core/env/ConversionService.java
vendored
Normal file
63
core/src/main/java/com/taobao/arthas/core/env/ConversionService.java
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* 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.taobao.arthas.core.env;
|
||||
|
||||
/**
|
||||
* A service interface for type conversion. This is the entry point into the
|
||||
* convert system. Call {@link #convert(Object, Class)} to perform a thread-safe
|
||||
* type conversion using this system.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Phillip Webb
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface ConversionService {
|
||||
|
||||
/**
|
||||
* Return {@code true} if objects of {@code sourceType} can be converted to the
|
||||
* {@code targetType}.
|
||||
* <p>
|
||||
* If this method returns {@code true}, it means {@link #convert(Object, Class)}
|
||||
* is capable of converting an instance of {@code sourceType} to
|
||||
* {@code targetType}.
|
||||
* <p>
|
||||
* Special note on collections, arrays, and maps types: For conversion between
|
||||
* collection, array, and map types, this method will return {@code true} even
|
||||
* though a convert invocation may still generate a {@link ConversionException}
|
||||
* if the underlying elements are not convertible. Callers are expected to
|
||||
* handle this exceptional case when working with collections and maps.
|
||||
*
|
||||
* @param sourceType the source type to convert from (may be {@code null} if
|
||||
* source is {@code null})
|
||||
* @param targetType the target type to convert to (required)
|
||||
* @return {@code true} if a conversion can be performed, {@code false} if not
|
||||
* @throws IllegalArgumentException if {@code targetType} is {@code null}
|
||||
*/
|
||||
boolean canConvert(Class<?> sourceType, Class<?> targetType);
|
||||
|
||||
/**
|
||||
* Convert the given {@code source} to the specified {@code targetType}.
|
||||
*
|
||||
* @param source the source object to convert (may be {@code null})
|
||||
* @param targetType the target type to convert to (required)
|
||||
* @return the converted object, an instance of targetType
|
||||
* @throws ConversionException if a conversion exception occurred
|
||||
* @throws IllegalArgumentException if targetType is {@code null}
|
||||
*/
|
||||
<T> T convert(Object source, Class<T> targetType);
|
||||
|
||||
}
|
17
core/src/main/java/com/taobao/arthas/core/env/DefaultConversionService.java
vendored
Normal file
17
core/src/main/java/com/taobao/arthas/core/env/DefaultConversionService.java
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
package com.taobao.arthas.core.env;
|
||||
|
||||
public class DefaultConversionService implements ConfigurableConversionService {
|
||||
|
||||
@Override
|
||||
public boolean canConvert(Class<?> sourceType, Class<?> targetType) {
|
||||
// TODO Auto-generated method stub
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T convert(Object source, Class<T> targetType) {
|
||||
// TODO Auto-generated method stub
|
||||
return (T) source;
|
||||
}
|
||||
|
||||
}
|
85
core/src/main/java/com/taobao/arthas/core/env/EnumerablePropertySource.java
vendored
Normal file
85
core/src/main/java/com/taobao/arthas/core/env/EnumerablePropertySource.java
vendored
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.taobao.arthas.core.env;
|
||||
|
||||
/**
|
||||
* A {@link PropertySource} implementation capable of interrogating its
|
||||
* underlying source object to enumerate all possible property name/value pairs.
|
||||
* Exposes the {@link #getPropertyNames()} method to allow callers to introspect
|
||||
* available properties without having to access the underlying source object.
|
||||
* This also facilitates a more efficient implementation of
|
||||
* {@link #containsProperty(String)}, in that it can call
|
||||
* {@link #getPropertyNames()} and iterate through the returned array rather
|
||||
* than attempting a call to {@link #getProperty(String)} which may be more
|
||||
* expensive. Implementations may consider caching the result of
|
||||
* {@link #getPropertyNames()} to fully exploit this performance opportunity.
|
||||
*
|
||||
* <p>
|
||||
* Most framework-provided {@code PropertySource} implementations are
|
||||
* enumerable; a counter-example would be {@code JndiPropertySource} where, due
|
||||
* to the nature of JNDI it is not possible to determine all possible property
|
||||
* names at any given time; rather it is only possible to try to access a
|
||||
* property (via {@link #getProperty(String)}) in order to evaluate whether it
|
||||
* is present or not.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
* @param <T> the source type
|
||||
*/
|
||||
public abstract class EnumerablePropertySource<T> extends PropertySource<T> {
|
||||
|
||||
public EnumerablePropertySource(String name, T source) {
|
||||
super(name, source);
|
||||
}
|
||||
|
||||
protected EnumerablePropertySource(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this {@code PropertySource} contains a property with the given
|
||||
* name.
|
||||
* <p>
|
||||
* This implementation checks for the presence of the given name within the
|
||||
* {@link #getPropertyNames()} array.
|
||||
*
|
||||
* @param name the name of the property to find
|
||||
*/
|
||||
@Override
|
||||
public boolean containsProperty(String name) {
|
||||
String[] propertyNames = getPropertyNames();
|
||||
if (propertyNames == null) {
|
||||
return false;
|
||||
}
|
||||
for (String temp : propertyNames) {
|
||||
if (temp.equals(name)) {
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the names of all properties contained by the {@linkplain #getSource()
|
||||
* source} object (never {@code null}).
|
||||
*/
|
||||
public abstract String[] getPropertyNames();
|
||||
|
||||
}
|
5
core/src/main/java/com/taobao/arthas/core/env/Environment.java
vendored
Normal file
5
core/src/main/java/com/taobao/arthas/core/env/Environment.java
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
package com.taobao.arthas.core.env;
|
||||
|
||||
public interface Environment extends PropertyResolver {
|
||||
|
||||
}
|
52
core/src/main/java/com/taobao/arthas/core/env/MapPropertySource.java
vendored
Normal file
52
core/src/main/java/com/taobao/arthas/core/env/MapPropertySource.java
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.taobao.arthas.core.env;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.logging.log4j.util.PropertiesPropertySource;
|
||||
|
||||
/**
|
||||
* {@link PropertySource} that reads keys and values from a {@code Map} object.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
* @see PropertiesPropertySource
|
||||
*/
|
||||
public class MapPropertySource extends EnumerablePropertySource<Map<String, Object>> {
|
||||
|
||||
public MapPropertySource(String name, Map<String, Object> source) {
|
||||
super(name, source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getProperty(String name) {
|
||||
return this.source.get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsProperty(String name) {
|
||||
return this.source.containsKey(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getPropertyNames() {
|
||||
return this.source.keySet().toArray(new String[0]);
|
||||
}
|
||||
|
||||
}
|
57
core/src/main/java/com/taobao/arthas/core/env/MissingRequiredPropertiesException.java
vendored
Normal file
57
core/src/main/java/com/taobao/arthas/core/env/MissingRequiredPropertiesException.java
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.taobao.arthas.core.env;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Exception thrown when required properties are not found.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see ConfigurablePropertyResolver#setRequiredProperties(String...)
|
||||
* @see ConfigurablePropertyResolver#validateRequiredProperties()
|
||||
* @see org.springframework.context.support.AbstractApplicationContext#prepareRefresh()
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class MissingRequiredPropertiesException extends IllegalStateException {
|
||||
|
||||
private final Set<String> missingRequiredProperties = new LinkedHashSet<String>();
|
||||
|
||||
void addMissingRequiredProperty(String key) {
|
||||
this.missingRequiredProperties.add(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "The following properties were declared as required but could not be resolved: "
|
||||
+ getMissingRequiredProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the set of properties marked as required but not present upon
|
||||
* validation.
|
||||
*
|
||||
* @see ConfigurablePropertyResolver#setRequiredProperties(String...)
|
||||
* @see ConfigurablePropertyResolver#validateRequiredProperties()
|
||||
*/
|
||||
public Set<String> getMissingRequiredProperties() {
|
||||
return this.missingRequiredProperties;
|
||||
}
|
||||
|
||||
}
|
306
core/src/main/java/com/taobao/arthas/core/env/MutablePropertySources.java
vendored
Normal file
306
core/src/main/java/com/taobao/arthas/core/env/MutablePropertySources.java
vendored
Normal file
@ -0,0 +1,306 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* 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.taobao.arthas.core.env;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
|
||||
/**
|
||||
* Default implementation of the {@link PropertySources} interface. Allows
|
||||
* manipulation of contained property sources and provides a constructor for
|
||||
* copying an existing {@code PropertySources} instance.
|
||||
*
|
||||
* <p>
|
||||
* Where <em>precedence</em> is mentioned in methods such as {@link #addFirst}
|
||||
* and {@link #addLast}, this is with regard to the order in which property
|
||||
* sources will be searched when resolving a given property with a
|
||||
* {@link PropertyResolver}.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see PropertySourcesPropertyResolver
|
||||
*/
|
||||
public class MutablePropertySources implements PropertySources {
|
||||
|
||||
static final String NON_EXISTENT_PROPERTY_SOURCE_MESSAGE = "PropertySource named [%s] does not exist";
|
||||
static final String ILLEGAL_RELATIVE_ADDITION_MESSAGE = "PropertySource named [%s] cannot be added relative to itself";
|
||||
|
||||
private final LinkedList<PropertySource<?>> propertySourceList = new LinkedList<PropertySource<?>>();
|
||||
|
||||
/**
|
||||
* Create a new {@link MutablePropertySources} object.
|
||||
*/
|
||||
public MutablePropertySources() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code MutablePropertySources} from the given propertySources
|
||||
* object, preserving the original order of contained {@code PropertySource}
|
||||
* objects.
|
||||
*/
|
||||
public MutablePropertySources(PropertySources propertySources) {
|
||||
this();
|
||||
for (PropertySource<?> propertySource : propertySources) {
|
||||
this.addLast(propertySource);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean contains(String name) {
|
||||
return this.propertySourceList.contains(PropertySource.named(name));
|
||||
}
|
||||
|
||||
public PropertySource<?> get(String name) {
|
||||
int index = this.propertySourceList.indexOf(PropertySource.named(name));
|
||||
return index == -1 ? null : this.propertySourceList.get(index);
|
||||
}
|
||||
|
||||
public Iterator<PropertySource<?>> iterator() {
|
||||
return this.propertySourceList.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given property source object with highest precedence.
|
||||
*/
|
||||
public void addFirst(PropertySource<?> propertySource) {
|
||||
// if (logger.isDebugEnabled()) {
|
||||
// logger.debug(String.format("Adding [%s] PropertySource with highest search precedence",
|
||||
// propertySource.getName()));
|
||||
// }
|
||||
removeIfPresent(propertySource);
|
||||
this.propertySourceList.addFirst(propertySource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given property source object with lowest precedence.
|
||||
*/
|
||||
public void addLast(PropertySource<?> propertySource) {
|
||||
// if (logger.isDebugEnabled()) {
|
||||
// logger.debug(String.format("Adding [%s] PropertySource with lowest search precedence",
|
||||
// propertySource.getName()));
|
||||
// }
|
||||
removeIfPresent(propertySource);
|
||||
this.propertySourceList.addLast(propertySource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given property source object with precedence immediately higher than
|
||||
* the named relative property source.
|
||||
*/
|
||||
public void addBefore(String relativePropertySourceName, PropertySource<?> propertySource) {
|
||||
// if (logger.isDebugEnabled()) {
|
||||
// logger.debug(String.format("Adding [%s] PropertySource with search precedence immediately higher than [%s]",
|
||||
// propertySource.getName(), relativePropertySourceName));
|
||||
// }
|
||||
assertLegalRelativeAddition(relativePropertySourceName, propertySource);
|
||||
removeIfPresent(propertySource);
|
||||
int index = assertPresentAndGetIndex(relativePropertySourceName);
|
||||
addAtIndex(index, propertySource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given property source object with precedence immediately lower than
|
||||
* the named relative property source.
|
||||
*/
|
||||
public void addAfter(String relativePropertySourceName, PropertySource<?> propertySource) {
|
||||
// if (logger.isDebugEnabled()) {
|
||||
// logger.debug(String.format("Adding [%s] PropertySource with search precedence immediately lower than [%s]",
|
||||
// propertySource.getName(), relativePropertySourceName));
|
||||
// }
|
||||
assertLegalRelativeAddition(relativePropertySourceName, propertySource);
|
||||
removeIfPresent(propertySource);
|
||||
int index = assertPresentAndGetIndex(relativePropertySourceName);
|
||||
addAtIndex(index + 1, propertySource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the precedence of the given property source, {@code -1} if not found.
|
||||
*/
|
||||
public int precedenceOf(PropertySource<?> propertySource) {
|
||||
return this.propertySourceList.indexOf(propertySource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove and return the property source with the given name, {@code null} if
|
||||
* not found.
|
||||
*
|
||||
* @param name the name of the property source to find and remove
|
||||
*/
|
||||
public PropertySource<?> remove(String name) {
|
||||
// if (logger.isDebugEnabled()) {
|
||||
// logger.debug(String.format("Removing [%s] PropertySource", name));
|
||||
// }
|
||||
int index = this.propertySourceList.indexOf(PropertySource.named(name));
|
||||
return index == -1 ? null : this.propertySourceList.remove(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the property source with the given name with the given property
|
||||
* source object.
|
||||
*
|
||||
* @param name the name of the property source to find and replace
|
||||
* @param propertySource the replacement property source
|
||||
* @throws IllegalArgumentException if no property source with the given name is
|
||||
* present
|
||||
* @see #contains
|
||||
*/
|
||||
public void replace(String name, PropertySource<?> propertySource) {
|
||||
// if (logger.isDebugEnabled()) {
|
||||
// logger.debug(String.format("Replacing [%s] PropertySource with [%s]",
|
||||
// name, propertySource.getName()));
|
||||
// }
|
||||
int index = assertPresentAndGetIndex(name);
|
||||
this.propertySourceList.set(index, propertySource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of {@link PropertySource} objects contained.
|
||||
*/
|
||||
public int size() {
|
||||
return this.propertySourceList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String[] names = new String[this.size()];
|
||||
for (int i = 0; i < size(); i++) {
|
||||
names[i] = this.propertySourceList.get(i).getName();
|
||||
}
|
||||
return String.format("[%s]", arrayToCommaDelimitedString(names));
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the given property source is not being added relative to itself.
|
||||
*/
|
||||
protected void assertLegalRelativeAddition(String relativePropertySourceName, PropertySource<?> propertySource) {
|
||||
// String newPropertySourceName = propertySource.getName();
|
||||
// Assert.isTrue(!relativePropertySourceName.equals(newPropertySourceName),
|
||||
// String.format(ILLEGAL_RELATIVE_ADDITION_MESSAGE, newPropertySourceName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given property source if it is present.
|
||||
*/
|
||||
protected void removeIfPresent(PropertySource<?> propertySource) {
|
||||
if (this.propertySourceList.contains(propertySource)) {
|
||||
this.propertySourceList.remove(propertySource);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given property source at a particular index in the list.
|
||||
*/
|
||||
private void addAtIndex(int index, PropertySource<?> propertySource) {
|
||||
removeIfPresent(propertySource);
|
||||
this.propertySourceList.add(index, propertySource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the named property source is present and return its index.
|
||||
*
|
||||
* @param name the {@linkplain PropertySource#getName() name of the property
|
||||
* source} to find
|
||||
* @throws IllegalArgumentException if the named property source is not present
|
||||
*/
|
||||
private int assertPresentAndGetIndex(String name) {
|
||||
int index = this.propertySourceList.indexOf(PropertySource.named(name));
|
||||
// Assert.isTrue(index >= 0, String.format(NON_EXISTENT_PROPERTY_SOURCE_MESSAGE, name));
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to return a String array as a delimited (e.g. CSV) String.
|
||||
* E.g. useful for {@code toString()} implementations.
|
||||
*
|
||||
* @param arr the array to display
|
||||
* @param delim the delimiter to use (probably a ",")
|
||||
* @return the delimited String
|
||||
*/
|
||||
private static String arrayToDelimitedString(Object[] arr, String delim) {
|
||||
if (arr == null || arr.length == 0) {
|
||||
return "";
|
||||
}
|
||||
if (arr.length == 1) {
|
||||
return nullSafeToString(arr[0]);
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < arr.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(delim);
|
||||
}
|
||||
sb.append(arr[i]);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a String representation of the specified Object.
|
||||
* <p>
|
||||
* Builds a String representation of the contents in case of an array. Returns
|
||||
* {@code "null"} if {@code obj} is {@code null}.
|
||||
*
|
||||
* @param obj the object to build a String representation for
|
||||
* @return a String representation of {@code obj}
|
||||
*/
|
||||
private static String nullSafeToString(Object obj) {
|
||||
if (obj == null) {
|
||||
return "null";
|
||||
}
|
||||
if (obj instanceof String) {
|
||||
return (String) obj;
|
||||
}
|
||||
if (obj instanceof Object[]) {
|
||||
return nullSafeToString((Object[]) obj);
|
||||
}
|
||||
if (obj instanceof boolean[]) {
|
||||
return nullSafeToString((boolean[]) obj);
|
||||
}
|
||||
if (obj instanceof byte[]) {
|
||||
return nullSafeToString((byte[]) obj);
|
||||
}
|
||||
if (obj instanceof char[]) {
|
||||
return nullSafeToString((char[]) obj);
|
||||
}
|
||||
if (obj instanceof double[]) {
|
||||
return nullSafeToString((double[]) obj);
|
||||
}
|
||||
if (obj instanceof float[]) {
|
||||
return nullSafeToString((float[]) obj);
|
||||
}
|
||||
if (obj instanceof int[]) {
|
||||
return nullSafeToString((int[]) obj);
|
||||
}
|
||||
if (obj instanceof long[]) {
|
||||
return nullSafeToString((long[]) obj);
|
||||
}
|
||||
if (obj instanceof short[]) {
|
||||
return nullSafeToString((short[]) obj);
|
||||
}
|
||||
String str = obj.toString();
|
||||
return (str != null ? str : "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to return a String array as a CSV String. E.g. useful for
|
||||
* {@code toString()} implementations.
|
||||
*
|
||||
* @param arr the array to display
|
||||
* @return the delimited String
|
||||
*/
|
||||
private static String arrayToCommaDelimitedString(Object[] arr) {
|
||||
return arrayToDelimitedString(arr, ",");
|
||||
}
|
||||
}
|
56
core/src/main/java/com/taobao/arthas/core/env/PropertiesPropertySource.java
vendored
Normal file
56
core/src/main/java/com/taobao/arthas/core/env/PropertiesPropertySource.java
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.taobao.arthas.core.env;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* {@link PropertySource} implementation that extracts properties from a
|
||||
* {@link java.util.Properties} object.
|
||||
*
|
||||
* <p>
|
||||
* Note that because a {@code Properties} object is technically an
|
||||
* {@code <Object, Object>} {@link java.util.Hashtable Hashtable}, one may
|
||||
* contain non-{@code String} keys or values. This implementation, however is
|
||||
* restricted to accessing only {@code String}-based keys and values, in the
|
||||
* same fashion as {@link Properties#getProperty} and
|
||||
* {@link Properties#setProperty}.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
public class PropertiesPropertySource extends MapPropertySource {
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public PropertiesPropertySource(String name, Properties source) {
|
||||
super(name, (Map) source);
|
||||
}
|
||||
|
||||
protected PropertiesPropertySource(String name, Map<String, Object> source) {
|
||||
super(name, source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getPropertyNames() {
|
||||
synchronized (this.source) {
|
||||
return super.getPropertyNames();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
244
core/src/main/java/com/taobao/arthas/core/env/PropertyPlaceholderHelper.java
vendored
Normal file
244
core/src/main/java/com/taobao/arthas/core/env/PropertyPlaceholderHelper.java
vendored
Normal file
@ -0,0 +1,244 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.taobao.arthas.core.env;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Utility class for working with Strings that have placeholder values in them.
|
||||
* A placeholder takes the form {@code ${name}}. Using
|
||||
* {@code PropertyPlaceholderHelper} these placeholders can be substituted for
|
||||
* user-supplied values.
|
||||
* <p>
|
||||
* Values for substitution can be supplied using a {@link Properties} instance
|
||||
* or using a {@link PlaceholderResolver}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Rob Harrop
|
||||
* @since 3.0
|
||||
*/
|
||||
public class PropertyPlaceholderHelper {
|
||||
|
||||
private static final Map<String, String> wellKnownSimplePrefixes = new HashMap<String, String>(4);
|
||||
|
||||
static {
|
||||
wellKnownSimplePrefixes.put("}", "{");
|
||||
wellKnownSimplePrefixes.put("]", "[");
|
||||
wellKnownSimplePrefixes.put(")", "(");
|
||||
}
|
||||
|
||||
private final String placeholderPrefix;
|
||||
|
||||
private final String placeholderSuffix;
|
||||
|
||||
private final String simplePrefix;
|
||||
|
||||
private final String valueSeparator;
|
||||
|
||||
private final boolean ignoreUnresolvablePlaceholders;
|
||||
|
||||
/**
|
||||
* Creates a new {@code PropertyPlaceholderHelper} that uses the supplied prefix
|
||||
* and suffix. Unresolvable placeholders are ignored.
|
||||
*
|
||||
* @param placeholderPrefix the prefix that denotes the start of a placeholder
|
||||
* @param placeholderSuffix the suffix that denotes the end of a placeholder
|
||||
*/
|
||||
public PropertyPlaceholderHelper(String placeholderPrefix, String placeholderSuffix) {
|
||||
this(placeholderPrefix, placeholderSuffix, null, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code 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 valueSeparator the separating character between the
|
||||
* placeholder variable and the associated
|
||||
* default value, if any
|
||||
* @param ignoreUnresolvablePlaceholders indicates whether unresolvable
|
||||
* placeholders should be ignored
|
||||
* ({@code true}) or cause an exception
|
||||
* ({@code false})
|
||||
*/
|
||||
public PropertyPlaceholderHelper(String placeholderPrefix, String placeholderSuffix, String valueSeparator,
|
||||
boolean ignoreUnresolvablePlaceholders) {
|
||||
|
||||
this.placeholderPrefix = placeholderPrefix;
|
||||
this.placeholderSuffix = placeholderSuffix;
|
||||
String simplePrefixForSuffix = wellKnownSimplePrefixes.get(this.placeholderSuffix);
|
||||
if (simplePrefixForSuffix != null && this.placeholderPrefix.endsWith(simplePrefixForSuffix)) {
|
||||
this.simplePrefix = simplePrefixForSuffix;
|
||||
} else {
|
||||
this.simplePrefix = this.placeholderPrefix;
|
||||
}
|
||||
this.valueSeparator = valueSeparator;
|
||||
this.ignoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces all placeholders of format {@code ${name}} with the corresponding
|
||||
* property from the supplied {@link Properties}.
|
||||
*
|
||||
* @param value the value containing the placeholders to be replaced
|
||||
* @param properties the {@code Properties} to use for replacement
|
||||
* @return the supplied value with placeholders replaced inline
|
||||
*/
|
||||
public String replacePlaceholders(String value, final Properties properties) {
|
||||
return replacePlaceholders(value, new PlaceholderResolver() {
|
||||
public String resolvePlaceholder(String placeholderName) {
|
||||
return properties.getProperty(placeholderName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces all placeholders of format {@code ${name}} with the value returned
|
||||
* from the supplied {@link PlaceholderResolver}.
|
||||
*
|
||||
* @param value the value containing the placeholders to be
|
||||
* replaced
|
||||
* @param placeholderResolver the {@code PlaceholderResolver} to use for
|
||||
* replacement
|
||||
* @return the supplied value with placeholders replaced inline
|
||||
*/
|
||||
public String replacePlaceholders(String value, PlaceholderResolver placeholderResolver) {
|
||||
return parseStringValue(value, placeholderResolver, null);
|
||||
}
|
||||
|
||||
protected String parseStringValue(String value, PlaceholderResolver placeholderResolver,
|
||||
Set<String> visitedPlaceholders) {
|
||||
|
||||
int startIndex = value.indexOf(this.placeholderPrefix);
|
||||
if (startIndex == -1) {
|
||||
return value;
|
||||
}
|
||||
|
||||
StringBuilder result = new StringBuilder(value);
|
||||
while (startIndex != -1) {
|
||||
int endIndex = findPlaceholderEndIndex(result, startIndex);
|
||||
if (endIndex != -1) {
|
||||
String placeholder = result.substring(startIndex + this.placeholderPrefix.length(), endIndex);
|
||||
String originalPlaceholder = placeholder;
|
||||
if (visitedPlaceholders == null) {
|
||||
visitedPlaceholders = new HashSet<String>(4);
|
||||
}
|
||||
if (!visitedPlaceholders.add(originalPlaceholder)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Circular placeholder reference '" + originalPlaceholder + "' 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...
|
||||
String propVal = placeholderResolver.resolvePlaceholder(placeholder);
|
||||
if (propVal == null && this.valueSeparator != null) {
|
||||
int separatorIndex = placeholder.indexOf(this.valueSeparator);
|
||||
if (separatorIndex != -1) {
|
||||
String actualPlaceholder = placeholder.substring(0, separatorIndex);
|
||||
String defaultValue = placeholder.substring(separatorIndex + this.valueSeparator.length());
|
||||
propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder);
|
||||
if (propVal == null) {
|
||||
propVal = defaultValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (propVal != null) {
|
||||
// Recursive invocation, parsing placeholders contained in the
|
||||
// previously resolved placeholder value.
|
||||
propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders);
|
||||
result.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
|
||||
startIndex = result.indexOf(this.placeholderPrefix, startIndex + propVal.length());
|
||||
} else if (this.ignoreUnresolvablePlaceholders) {
|
||||
// Proceed with unprocessed value.
|
||||
startIndex = result.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Could not resolve placeholder '" + placeholder + "'" + " in value \"" + value + "\"");
|
||||
}
|
||||
visitedPlaceholders.remove(originalPlaceholder);
|
||||
} else {
|
||||
startIndex = -1;
|
||||
}
|
||||
}
|
||||
return result.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.placeholderSuffix.length();
|
||||
} else {
|
||||
return index;
|
||||
}
|
||||
} else if (substringMatch(buf, index, this.simplePrefix)) {
|
||||
withinNestedPlaceholder++;
|
||||
index = index + this.simplePrefix.length();
|
||||
} else {
|
||||
index++;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether the given string matches the given substring at the given index.
|
||||
*
|
||||
* @param str the original string (or StringBuilder)
|
||||
* @param index the index in the original string to start matching against
|
||||
* @param substring the substring to match at the given index
|
||||
*/
|
||||
public static boolean substringMatch(CharSequence str, int index, CharSequence substring) {
|
||||
if (index + substring.length() > str.length()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < substring.length(); i++) {
|
||||
if (str.charAt(index + i) != substring.charAt(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strategy interface used to resolve replacement values for placeholders
|
||||
* contained in Strings.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface PlaceholderResolver {
|
||||
|
||||
/**
|
||||
* Resolve the supplied placeholder name to the replacement value.
|
||||
*
|
||||
* @param placeholderName the name of the placeholder to resolve
|
||||
* @return the replacement value, or {@code null} if no replacement is to be
|
||||
* made
|
||||
*/
|
||||
String resolvePlaceholder(String placeholderName);
|
||||
}
|
||||
|
||||
}
|
123
core/src/main/java/com/taobao/arthas/core/env/PropertyResolver.java
vendored
Normal file
123
core/src/main/java/com/taobao/arthas/core/env/PropertyResolver.java
vendored
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.taobao.arthas.core.env;
|
||||
|
||||
/**
|
||||
* Interface for resolving properties against any underlying source.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
* @see Environment
|
||||
* @see PropertySourcesPropertyResolver
|
||||
*/
|
||||
public interface PropertyResolver {
|
||||
|
||||
/**
|
||||
* Return whether the given property key is available for resolution, i.e. if
|
||||
* the value for the given key is not {@code null}.
|
||||
*/
|
||||
boolean containsProperty(String key);
|
||||
|
||||
/**
|
||||
* Return the property value associated with the given key, or {@code null} if
|
||||
* the key cannot be resolved.
|
||||
*
|
||||
* @param key the property name to resolve
|
||||
* @see #getProperty(String, String)
|
||||
* @see #getProperty(String, Class)
|
||||
* @see #getRequiredProperty(String)
|
||||
*/
|
||||
String getProperty(String key);
|
||||
|
||||
/**
|
||||
* Return the property value associated with the given key, or
|
||||
* {@code defaultValue} if the key cannot be resolved.
|
||||
*
|
||||
* @param key the property name to resolve
|
||||
* @param defaultValue the default value to return if no value is found
|
||||
* @see #getRequiredProperty(String)
|
||||
* @see #getProperty(String, Class)
|
||||
*/
|
||||
String getProperty(String key, String defaultValue);
|
||||
|
||||
/**
|
||||
* Return the property value associated with the given key, or {@code null} if
|
||||
* the key cannot be resolved.
|
||||
*
|
||||
* @param key the property name to resolve
|
||||
* @param targetType the expected type of the property value
|
||||
* @see #getRequiredProperty(String, Class)
|
||||
*/
|
||||
<T> T getProperty(String key, Class<T> targetType);
|
||||
|
||||
/**
|
||||
* Return the property value associated with the given key, or
|
||||
* {@code defaultValue} if the key cannot be resolved.
|
||||
*
|
||||
* @param key the property name to resolve
|
||||
* @param targetType the expected type of the property value
|
||||
* @param defaultValue the default value to return if no value is found
|
||||
* @see #getRequiredProperty(String, Class)
|
||||
*/
|
||||
<T> T getProperty(String key, Class<T> targetType, T defaultValue);
|
||||
|
||||
/**
|
||||
* Return the property value associated with the given key (never {@code null}).
|
||||
*
|
||||
* @throws IllegalStateException if the key cannot be resolved
|
||||
* @see #getRequiredProperty(String, Class)
|
||||
*/
|
||||
String getRequiredProperty(String key) throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Return the property value associated with the given key, converted to the
|
||||
* given targetType (never {@code null}).
|
||||
*
|
||||
* @throws IllegalStateException if the given key cannot be resolved
|
||||
*/
|
||||
<T> T getRequiredProperty(String key, Class<T> targetType) throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Resolve ${...} placeholders in the given text, replacing them with
|
||||
* corresponding property values as resolved by {@link #getProperty}.
|
||||
* Unresolvable placeholders with no default value are ignored and passed
|
||||
* through unchanged.
|
||||
*
|
||||
* @param text the String to resolve
|
||||
* @return the resolved String (never {@code null})
|
||||
* @throws IllegalArgumentException if given text is {@code null}
|
||||
* @see #resolveRequiredPlaceholders
|
||||
* @see org.springframework.util.SystemPropertyUtils#resolvePlaceholders(String)
|
||||
*/
|
||||
String resolvePlaceholders(String text);
|
||||
|
||||
/**
|
||||
* Resolve ${...} placeholders in the given text, replacing them with
|
||||
* corresponding property values as resolved by {@link #getProperty}.
|
||||
* Unresolvable placeholders with no default value will cause an
|
||||
* IllegalArgumentException to be thrown.
|
||||
*
|
||||
* @return the resolved String (never {@code null})
|
||||
* @throws IllegalArgumentException if given text is {@code null} or if any
|
||||
* placeholders are unresolvable
|
||||
* @see org.springframework.util.SystemPropertyUtils#resolvePlaceholders(String,
|
||||
* boolean)
|
||||
*/
|
||||
String resolveRequiredPlaceholders(String text) throws IllegalArgumentException;
|
||||
|
||||
}
|
327
core/src/main/java/com/taobao/arthas/core/env/PropertySource.java
vendored
Normal file
327
core/src/main/java/com/taobao/arthas/core/env/PropertySource.java
vendored
Normal file
@ -0,0 +1,327 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.taobao.arthas.core.env;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.sun.tools.javac.util.Log;
|
||||
|
||||
/**
|
||||
* Abstract base class representing a source of name/value property pairs. The
|
||||
* underlying {@linkplain #getSource() source object} may be of any type
|
||||
* {@code T} that encapsulates properties. Examples include
|
||||
* {@link java.util.Properties} objects, {@link java.util.Map} objects,
|
||||
* {@code ServletContext} and {@code ServletConfig} objects (for access to init
|
||||
* parameters). Explore the {@code PropertySource} type hierarchy to see
|
||||
* provided implementations.
|
||||
*
|
||||
* <p>
|
||||
* {@code PropertySource} objects are not typically used in isolation, but
|
||||
* rather through a {@link PropertySources} object, which aggregates property
|
||||
* sources and in conjunction with a {@link PropertyResolver} implementation
|
||||
* that can perform precedence-based searches across the set of
|
||||
* {@code PropertySources}.
|
||||
*
|
||||
* <p>
|
||||
* {@code PropertySource} identity is determined not based on the content of
|
||||
* encapsulated properties, but rather based on the {@link #getName() name} of
|
||||
* the {@code PropertySource} alone. This is useful for manipulating
|
||||
* {@code PropertySource} objects when in collection contexts. See operations in
|
||||
* {@link MutablePropertySources} as well as the {@link #named(String)} and
|
||||
* {@link #toString()} methods for details.
|
||||
*
|
||||
* <p>
|
||||
* Note that when working
|
||||
* with @{@link org.springframework.context.annotation.Configuration
|
||||
* Configuration} classes that
|
||||
* the @{@link org.springframework.context.annotation.PropertySource
|
||||
* PropertySource} annotation provides a convenient and declarative way of
|
||||
* adding property sources to the enclosing {@code Environment}.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @param <T> the source type
|
||||
* @see PropertySources
|
||||
* @see PropertyResolver
|
||||
* @see PropertySourcesPropertyResolver
|
||||
* @see MutablePropertySources
|
||||
* @see org.springframework.context.annotation.PropertySource
|
||||
*/
|
||||
public abstract class PropertySource<T> {
|
||||
|
||||
protected final String name;
|
||||
|
||||
protected final T source;
|
||||
|
||||
/**
|
||||
* Create a new {@code PropertySource} with the given name and source object.
|
||||
*/
|
||||
public PropertySource(String name, T source) {
|
||||
this.name = name;
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code PropertySource} with the given name and with a new
|
||||
* {@code Object} instance as the underlying source.
|
||||
* <p>
|
||||
* Often useful in testing scenarios when creating anonymous implementations
|
||||
* that never query an actual source but rather return hard-coded values.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public PropertySource(String name) {
|
||||
this(name, (T) new Object());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of this {@code PropertySource}.
|
||||
*/
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying source object for this {@code PropertySource}.
|
||||
*/
|
||||
public T getSource() {
|
||||
return this.source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this {@code PropertySource} contains the given name.
|
||||
* <p>
|
||||
* This implementation simply checks for a {@code null} return value from
|
||||
* {@link #getProperty(String)}. Subclasses may wish to implement a more
|
||||
* efficient algorithm if possible.
|
||||
*
|
||||
* @param name the property name to find
|
||||
*/
|
||||
public boolean containsProperty(String name) {
|
||||
return (getProperty(name) != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value associated with the given name, or {@code null} if not
|
||||
* found.
|
||||
*
|
||||
* @param name the property to find
|
||||
* @see PropertyResolver#getRequiredProperty(String)
|
||||
*/
|
||||
public abstract Object getProperty(String name);
|
||||
|
||||
/**
|
||||
* This {@code PropertySource} object is equal to the given object if:
|
||||
* <ul>
|
||||
* <li>they are the same instance
|
||||
* <li>the {@code name} properties for both objects are equal
|
||||
* </ul>
|
||||
* <p>
|
||||
* No properties other than {@code name} are evaluated.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return (this == other
|
||||
|| (other instanceof PropertySource && nullSafeEquals(this.name, ((PropertySource<?>) other).name)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a hash code derived from the {@code name} property of this
|
||||
* {@code PropertySource} object.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.name.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce concise output (type and name) if the current log level does not
|
||||
* include debug. If debug is enabled, produce verbose output including the hash
|
||||
* code of the PropertySource instance and every name/value property pair.
|
||||
* <p>
|
||||
* This variable verbosity is useful as a property source such as system
|
||||
* properties or environment variables may contain an arbitrary number of
|
||||
* property pairs, potentially leading to difficult to read exception and log
|
||||
* messages.
|
||||
*
|
||||
* @see Log#isDebugEnabled()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + " {name='" + this.name + "'}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code PropertySource} implementation intended for collection
|
||||
* comparison purposes only.
|
||||
* <p>
|
||||
* Primarily for internal use, but given a collection of {@code PropertySource}
|
||||
* objects, may be used as follows:
|
||||
*
|
||||
* <pre class="code">
|
||||
* {
|
||||
* @code
|
||||
* List<PropertySource<?>> sources = new ArrayList<PropertySource<?>>();
|
||||
* sources.add(new MapPropertySource("sourceA", mapA));
|
||||
* sources.add(new MapPropertySource("sourceB", mapB));
|
||||
* assert sources.contains(PropertySource.named("sourceA"));
|
||||
* assert sources.contains(PropertySource.named("sourceB"));
|
||||
* assert !sources.contains(PropertySource.named("sourceC"));
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* The returned {@code PropertySource} will throw
|
||||
* {@code UnsupportedOperationException} if any methods other than
|
||||
* {@code equals(Object)}, {@code hashCode()}, and {@code toString()} are
|
||||
* called.
|
||||
*
|
||||
* @param name the name of the comparison {@code PropertySource} to be created
|
||||
* and returned.
|
||||
*/
|
||||
public static PropertySource<?> named(String name) {
|
||||
return new ComparisonPropertySource(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given objects are equal, returning {@code true} if both are
|
||||
* {@code null} or {@code false} if only one is {@code null}.
|
||||
* <p>
|
||||
* Compares arrays with {@code Arrays.equals}, performing an equality check
|
||||
* based on the array elements rather than the array reference.
|
||||
*
|
||||
* @param o1 first Object to compare
|
||||
* @param o2 second Object to compare
|
||||
* @return whether the given objects are equal
|
||||
* @see Object#equals(Object)
|
||||
* @see java.util.Arrays#equals
|
||||
*/
|
||||
public static boolean nullSafeEquals(Object o1, Object o2) {
|
||||
if (o1 == o2) {
|
||||
return true;
|
||||
}
|
||||
if (o1 == null || o2 == null) {
|
||||
return false;
|
||||
}
|
||||
if (o1.equals(o2)) {
|
||||
return true;
|
||||
}
|
||||
if (o1.getClass().isArray() && o2.getClass().isArray()) {
|
||||
return arrayEquals(o1, o2);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the given arrays with {@code Arrays.equals}, performing an equality
|
||||
* check based on the array elements rather than the array reference.
|
||||
*
|
||||
* @param o1 first array to compare
|
||||
* @param o2 second array to compare
|
||||
* @return whether the given objects are equal
|
||||
* @see #nullSafeEquals(Object, Object)
|
||||
* @see java.util.Arrays#equals
|
||||
*/
|
||||
private static boolean arrayEquals(Object o1, Object o2) {
|
||||
if (o1 instanceof Object[] && o2 instanceof Object[]) {
|
||||
return Arrays.equals((Object[]) o1, (Object[]) o2);
|
||||
}
|
||||
if (o1 instanceof boolean[] && o2 instanceof boolean[]) {
|
||||
return Arrays.equals((boolean[]) o1, (boolean[]) o2);
|
||||
}
|
||||
if (o1 instanceof byte[] && o2 instanceof byte[]) {
|
||||
return Arrays.equals((byte[]) o1, (byte[]) o2);
|
||||
}
|
||||
if (o1 instanceof char[] && o2 instanceof char[]) {
|
||||
return Arrays.equals((char[]) o1, (char[]) o2);
|
||||
}
|
||||
if (o1 instanceof double[] && o2 instanceof double[]) {
|
||||
return Arrays.equals((double[]) o1, (double[]) o2);
|
||||
}
|
||||
if (o1 instanceof float[] && o2 instanceof float[]) {
|
||||
return Arrays.equals((float[]) o1, (float[]) o2);
|
||||
}
|
||||
if (o1 instanceof int[] && o2 instanceof int[]) {
|
||||
return Arrays.equals((int[]) o1, (int[]) o2);
|
||||
}
|
||||
if (o1 instanceof long[] && o2 instanceof long[]) {
|
||||
return Arrays.equals((long[]) o1, (long[]) o2);
|
||||
}
|
||||
if (o1 instanceof short[] && o2 instanceof short[]) {
|
||||
return Arrays.equals((short[]) o1, (short[]) o2);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code PropertySource} to be used as a placeholder in cases where an actual
|
||||
* property source cannot be eagerly initialized at application context creation
|
||||
* time. For example, a {@code ServletContext}-based property source must wait
|
||||
* until the {@code ServletContext} object is available to its enclosing
|
||||
* {@code ApplicationContext}. In such cases, a stub should be used to hold the
|
||||
* intended default position/order of the property source, then be replaced
|
||||
* during context refresh.
|
||||
*
|
||||
* @see org.springframework.context.support.AbstractApplicationContext#initPropertySources()
|
||||
* @see org.springframework.web.context.support.StandardServletEnvironment
|
||||
* @see org.springframework.web.context.support.ServletContextPropertySource
|
||||
*/
|
||||
public static class StubPropertySource extends PropertySource<Object> {
|
||||
|
||||
public StubPropertySource(String name) {
|
||||
super(name, new Object());
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns {@code null}.
|
||||
*/
|
||||
@Override
|
||||
public String getProperty(String name) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see PropertySource#named(String)
|
||||
*/
|
||||
static class ComparisonPropertySource extends StubPropertySource {
|
||||
|
||||
private static final String USAGE_ERROR = "ComparisonPropertySource instances are for use with collection comparison only";
|
||||
|
||||
public ComparisonPropertySource(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getSource() {
|
||||
throw new UnsupportedOperationException(USAGE_ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsProperty(String name) {
|
||||
throw new UnsupportedOperationException(USAGE_ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProperty(String name) {
|
||||
throw new UnsupportedOperationException(USAGE_ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s [name='%s']", getClass().getSimpleName(), this.name);
|
||||
}
|
||||
}
|
||||
}
|
45
core/src/main/java/com/taobao/arthas/core/env/PropertySources.java
vendored
Normal file
45
core/src/main/java/com/taobao/arthas/core/env/PropertySources.java
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.taobao.arthas.core.env;
|
||||
|
||||
/**
|
||||
* Holder containing one or more {@link PropertySource} objects.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
* @see PropertySource
|
||||
*/
|
||||
public interface PropertySources extends Iterable<PropertySource<?>> {
|
||||
|
||||
/**
|
||||
* Return whether a property source with the given name is contained.
|
||||
*
|
||||
* @param name the {@linkplain PropertySource#getName() name of the property
|
||||
* source} to find
|
||||
*/
|
||||
boolean contains(String name);
|
||||
|
||||
/**
|
||||
* Return the property source with the given name, {@code null} if not found.
|
||||
*
|
||||
* @param name the {@linkplain PropertySource#getName() name of the property
|
||||
* source} to find
|
||||
*/
|
||||
PropertySource<?> get(String name);
|
||||
|
||||
}
|
129
core/src/main/java/com/taobao/arthas/core/env/PropertySourcesPropertyResolver.java
vendored
Normal file
129
core/src/main/java/com/taobao/arthas/core/env/PropertySourcesPropertyResolver.java
vendored
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.taobao.arthas.core.env;
|
||||
|
||||
/**
|
||||
* {@link PropertyResolver} implementation that resolves property values against
|
||||
* an underlying set of {@link PropertySources}.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
* @see PropertySource
|
||||
* @see PropertySources
|
||||
* @see AbstractEnvironment
|
||||
*/
|
||||
public class PropertySourcesPropertyResolver extends AbstractPropertyResolver {
|
||||
|
||||
private final PropertySources propertySources;
|
||||
|
||||
/**
|
||||
* Create a new resolver against the given property sources.
|
||||
*
|
||||
* @param propertySources the set of {@link PropertySource} objects to use
|
||||
*/
|
||||
public PropertySourcesPropertyResolver(PropertySources propertySources) {
|
||||
this.propertySources = propertySources;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsProperty(String key) {
|
||||
if (this.propertySources != null) {
|
||||
for (PropertySource<?> propertySource : this.propertySources) {
|
||||
if (propertySource.containsProperty(key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProperty(String key) {
|
||||
return getProperty(key, String.class, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getProperty(String key, Class<T> targetValueType) {
|
||||
return getProperty(key, targetValueType, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getPropertyAsRawString(String key) {
|
||||
return getProperty(key, String.class, false);
|
||||
}
|
||||
|
||||
// protected <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {
|
||||
// if (this.propertySources != null) {
|
||||
// for (PropertySource<?> propertySource : this.propertySources) {
|
||||
// Object value = propertySource.getProperty(key);
|
||||
// if (value != null) {
|
||||
// if (resolveNestedPlaceholders && value instanceof String) {
|
||||
// value = resolveNestedPlaceholders((String) value);
|
||||
// }
|
||||
// logKeyFound(key, propertySource, value);
|
||||
// return convertValueIfNecessary(value, targetValueType);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
|
||||
protected <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {
|
||||
if (this.propertySources != null) {
|
||||
for (PropertySource<?> propertySource : this.propertySources) {
|
||||
Object value;
|
||||
if ((value = propertySource.getProperty(key)) != null) {
|
||||
Class<?> valueType = value.getClass();
|
||||
if (resolveNestedPlaceholders && value instanceof String) {
|
||||
value = resolveNestedPlaceholders((String) value);
|
||||
}
|
||||
if (!this.conversionService.canConvert(valueType, targetValueType)) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Cannot convert value [%s] from source type [%s] to target type [%s]",
|
||||
value, valueType.getSimpleName(), targetValueType.getSimpleName()));
|
||||
}
|
||||
return this.conversionService.convert(value, targetValueType);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the given key as found in the given {@link PropertySource}, resulting in
|
||||
* the given value.
|
||||
* <p>
|
||||
* The default implementation writes a debug log message with key and source. As
|
||||
* of 4.3.3, this does not log the value anymore in order to avoid accidental
|
||||
* logging of sensitive settings. Subclasses may override this method to change
|
||||
* the log level and/or log message, including the property's value if desired.
|
||||
*
|
||||
* @param key the key found
|
||||
* @param propertySource the {@code PropertySource} that the key has been found
|
||||
* in
|
||||
* @param value the corresponding value
|
||||
* @since 4.3.1
|
||||
*/
|
||||
protected void logKeyFound(String key, PropertySource<?> propertySource, Object value) {
|
||||
// if (logger.isDebugEnabled()) {
|
||||
// logger.debug("Found key '" + key + "' in PropertySource '" + propertySource.getName() +
|
||||
// "' with value of type " + value.getClass().getSimpleName());
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
123
core/src/main/java/com/taobao/arthas/core/env/ReadOnlySystemAttributesMap.java
vendored
Normal file
123
core/src/main/java/com/taobao/arthas/core/env/ReadOnlySystemAttributesMap.java
vendored
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.taobao.arthas.core.env;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Read-only {@code Map<String, String>} implementation that is backed by system
|
||||
* properties or environment variables.
|
||||
*
|
||||
* <p>
|
||||
* Used by {@link AbstractApplicationContext} when a {@link SecurityManager}
|
||||
* prohibits access to {@link System#getProperties()} or
|
||||
* {@link System#getenv()}. It is for this reason that the implementations of
|
||||
* {@link #keySet()}, {@link #entrySet()}, and {@link #values()} always return
|
||||
* empty even though {@link #get(Object)} may in fact return non-null if the
|
||||
* current security manager allows access to individual keys.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Chris Beams
|
||||
* @since 3.0
|
||||
*/
|
||||
abstract class ReadOnlySystemAttributesMap implements Map<String, String> {
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return (get(key) != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value to which the specified key is mapped, or {@code null} if
|
||||
* this map contains no mapping for the key.
|
||||
*
|
||||
* @param key the name of the system attribute to retrieve
|
||||
* @throws IllegalArgumentException if given key is non-String
|
||||
*/
|
||||
@Override
|
||||
public String get(Object key) {
|
||||
if (!(key instanceof String)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Type of key [" + key.getClass().getName() + "] must be java.lang.String");
|
||||
}
|
||||
return getSystemAttribute((String) key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method that returns the underlying system attribute.
|
||||
* <p>
|
||||
* Implementations typically call {@link System#getProperty(String)} or
|
||||
* {@link System#getenv(String)} here.
|
||||
*/
|
||||
protected abstract String getSystemAttribute(String attributeName);
|
||||
|
||||
// Unsupported
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String put(String key, String value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String remove(Object key) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> keySet() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends String, ? extends String> map) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> values() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<String, String>> entrySet() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
}
|
157
core/src/main/java/com/taobao/arthas/core/env/SystemEnvironmentPropertySource.java
vendored
Normal file
157
core/src/main/java/com/taobao/arthas/core/env/SystemEnvironmentPropertySource.java
vendored
Normal file
@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.taobao.arthas.core.env;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Specialization of {@link MapPropertySource} designed for use with
|
||||
* {@linkplain AbstractEnvironment#getSystemEnvironment() system environment
|
||||
* variables}. Compensates for constraints in Bash and other shells that do not
|
||||
* allow for variables containing the period character and/or hyphen character;
|
||||
* also allows for uppercase variations on property names for more idiomatic
|
||||
* shell use.
|
||||
*
|
||||
* <p>
|
||||
* For example, a call to {@code getProperty("foo.bar")} will attempt to find a
|
||||
* value for the original property or any 'equivalent' property, returning the
|
||||
* first found:
|
||||
* <ul>
|
||||
* <li>{@code foo.bar} - the original name</li>
|
||||
* <li>{@code foo_bar} - with underscores for periods (if any)</li>
|
||||
* <li>{@code FOO.BAR} - original, with upper case</li>
|
||||
* <li>{@code FOO_BAR} - with underscores and upper case</li>
|
||||
* </ul>
|
||||
* Any hyphen variant of the above would work as well, or even mix dot/hyphen
|
||||
* variants.
|
||||
*
|
||||
* <p>
|
||||
* The same applies for calls to {@link #containsProperty(String)}, which
|
||||
* returns {@code true} if any of the above properties are present, otherwise
|
||||
* {@code false}.
|
||||
*
|
||||
* <p>
|
||||
* This feature is particularly useful when specifying active or default
|
||||
* profiles as environment variables. The following is not allowable under Bash:
|
||||
*
|
||||
* <pre class="code">
|
||||
* spring.profiles.active=p1 java -classpath ... MyApp
|
||||
* </pre>
|
||||
*
|
||||
* However, the following syntax is permitted and is also more conventional:
|
||||
*
|
||||
* <pre class="code">
|
||||
* SPRING_PROFILES_ACTIVE=p1 java -classpath ... MyApp
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Enable debug- or trace-level logging for this class (or package) for messages
|
||||
* explaining when these 'property name resolutions' occur.
|
||||
*
|
||||
* <p>
|
||||
* This property source is included by default in {@link StandardEnvironment}
|
||||
* and all its subclasses.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
* @see StandardEnvironment
|
||||
* @see AbstractEnvironment#getSystemEnvironment()
|
||||
* @see AbstractEnvironment#ACTIVE_PROFILES_PROPERTY_NAME
|
||||
*/
|
||||
public class SystemEnvironmentPropertySource extends MapPropertySource {
|
||||
|
||||
/**
|
||||
* Create a new {@code SystemEnvironmentPropertySource} with the given name and
|
||||
* delegating to the given {@code MapPropertySource}.
|
||||
*/
|
||||
public SystemEnvironmentPropertySource(String name, Map<String, Object> source) {
|
||||
super(name, source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@code true} if a property with the given name or any
|
||||
* underscore/uppercase variant thereof exists in this property source.
|
||||
*/
|
||||
@Override
|
||||
public boolean containsProperty(String name) {
|
||||
return (getProperty(name) != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns {@code true} if a property with the given name or
|
||||
* any underscore/uppercase variant thereof exists in this property source.
|
||||
*/
|
||||
@Override
|
||||
public Object getProperty(String name) {
|
||||
String actualName = resolvePropertyName(name);
|
||||
return super.getProperty(actualName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if this property source contains a property with the given name,
|
||||
* or any underscore / uppercase variation thereof. Return the resolved name if
|
||||
* one is found or otherwise the original name. Never returns {@code null}.
|
||||
*/
|
||||
protected final String resolvePropertyName(String name) {
|
||||
String resolvedName = checkPropertyName(name);
|
||||
if (resolvedName != null) {
|
||||
return resolvedName;
|
||||
}
|
||||
String uppercasedName = name.toUpperCase();
|
||||
if (!name.equals(uppercasedName)) {
|
||||
resolvedName = checkPropertyName(uppercasedName);
|
||||
if (resolvedName != null) {
|
||||
return resolvedName;
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
private String checkPropertyName(String name) {
|
||||
// Check name as-is
|
||||
if (containsKey(name)) {
|
||||
return name;
|
||||
}
|
||||
// Check name with just dots replaced
|
||||
String noDotName = name.replace('.', '_');
|
||||
if (!name.equals(noDotName) && containsKey(noDotName)) {
|
||||
return noDotName;
|
||||
}
|
||||
// Check name with just hyphens replaced
|
||||
String noHyphenName = name.replace('-', '_');
|
||||
if (!name.equals(noHyphenName) && containsKey(noHyphenName)) {
|
||||
return noHyphenName;
|
||||
}
|
||||
// Check name with dots and hyphens replaced
|
||||
String noDotNoHyphenName = noDotName.replace('-', '_');
|
||||
if (!noDotName.equals(noDotNoHyphenName) && containsKey(noDotNoHyphenName)) {
|
||||
return noDotNoHyphenName;
|
||||
}
|
||||
// Give up
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean containsKey(String name) {
|
||||
return (isSecurityManagerPresent() ? this.source.keySet().contains(name) : this.source.containsKey(name));
|
||||
}
|
||||
|
||||
protected boolean isSecurityManagerPresent() {
|
||||
return (System.getSecurityManager() != null);
|
||||
}
|
||||
|
||||
}
|
116
core/src/main/java/com/taobao/arthas/core/env/SystemPropertyUtils.java
vendored
Normal file
116
core/src/main/java/com/taobao/arthas/core/env/SystemPropertyUtils.java
vendored
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.taobao.arthas.core.env;
|
||||
|
||||
/**
|
||||
* Helper class for resolving placeholders in texts. Usually applied to file
|
||||
* paths.
|
||||
*
|
||||
* <p>
|
||||
* A text may contain {@code ${...}} placeholders, to be resolved as system
|
||||
* properties: e.g. {@code ${user.dir}}. Default values can be supplied using
|
||||
* the ":" separator between key and value.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Rob Harrop
|
||||
* @author Dave Syer
|
||||
* @since 1.2.5
|
||||
* @see #PLACEHOLDER_PREFIX
|
||||
* @see #PLACEHOLDER_SUFFIX
|
||||
* @see System#getProperty(String)
|
||||
*/
|
||||
public abstract class SystemPropertyUtils {
|
||||
|
||||
/** Prefix for system property placeholders: "${". */
|
||||
public static final String PLACEHOLDER_PREFIX = "${";
|
||||
|
||||
/** Suffix for system property placeholders: "}". */
|
||||
public static final String PLACEHOLDER_SUFFIX = "}";
|
||||
|
||||
/** Value separator for system property placeholders: ":". */
|
||||
public static final String VALUE_SEPARATOR = ":";
|
||||
|
||||
private static final PropertyPlaceholderHelper strictHelper = new PropertyPlaceholderHelper(PLACEHOLDER_PREFIX,
|
||||
PLACEHOLDER_SUFFIX, VALUE_SEPARATOR, false);
|
||||
|
||||
private static final PropertyPlaceholderHelper nonStrictHelper = new PropertyPlaceholderHelper(PLACEHOLDER_PREFIX,
|
||||
PLACEHOLDER_SUFFIX, VALUE_SEPARATOR, true);
|
||||
|
||||
/**
|
||||
* Resolve {@code ${...}} placeholders in the given text, replacing them with
|
||||
* corresponding system property values.
|
||||
*
|
||||
* @param text the String to resolve
|
||||
* @return the resolved String
|
||||
* @throws IllegalArgumentException if there is an unresolvable placeholder
|
||||
* @see #PLACEHOLDER_PREFIX
|
||||
* @see #PLACEHOLDER_SUFFIX
|
||||
*/
|
||||
public static String resolvePlaceholders(String text) {
|
||||
return resolvePlaceholders(text, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve {@code ${...}} placeholders in the given text, replacing them with
|
||||
* corresponding system property values. Unresolvable placeholders with no
|
||||
* default value are ignored and passed through unchanged if the flag is set to
|
||||
* {@code true}.
|
||||
*
|
||||
* @param text the String to resolve
|
||||
* @param ignoreUnresolvablePlaceholders whether unresolved placeholders are to
|
||||
* be ignored
|
||||
* @return the resolved String
|
||||
* @throws IllegalArgumentException if there is an unresolvable placeholder
|
||||
* @see #PLACEHOLDER_PREFIX
|
||||
* @see #PLACEHOLDER_SUFFIX and the "ignoreUnresolvablePlaceholders" flag is
|
||||
* {@code false}
|
||||
*/
|
||||
public static String resolvePlaceholders(String text, boolean ignoreUnresolvablePlaceholders) {
|
||||
PropertyPlaceholderHelper helper = (ignoreUnresolvablePlaceholders ? nonStrictHelper : strictHelper);
|
||||
return helper.replacePlaceholders(text, new SystemPropertyPlaceholderResolver(text));
|
||||
}
|
||||
|
||||
/**
|
||||
* PlaceholderResolver implementation that resolves against system properties
|
||||
* and system environment variables.
|
||||
*/
|
||||
private static class SystemPropertyPlaceholderResolver implements PropertyPlaceholderHelper.PlaceholderResolver {
|
||||
|
||||
private final String text;
|
||||
|
||||
public SystemPropertyPlaceholderResolver(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resolvePlaceholder(String placeholderName) {
|
||||
try {
|
||||
String propVal = System.getProperty(placeholderName);
|
||||
if (propVal == null) {
|
||||
// Fall back to searching the system environment.
|
||||
propVal = System.getenv(placeholderName);
|
||||
}
|
||||
return propVal;
|
||||
} catch (Throwable ex) {
|
||||
System.err.println("Could not resolve placeholder '" + placeholderName + "' in [" + this.text
|
||||
+ "] as system property: " + ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
5
core/src/main/java/com/taobao/arthas/core/env/package-info.java
vendored
Normal file
5
core/src/main/java/com/taobao/arthas/core/env/package-info.java
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
/**
|
||||
* from org.springframework.core.env
|
||||
*/
|
||||
package com.taobao.arthas.core.env;
|
54
core/src/test/java/com/taobao/arthas/core/env/ArthasEnvironmentTest.java
vendored
Normal file
54
core/src/test/java/com/taobao/arthas/core/env/ArthasEnvironmentTest.java
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
package com.taobao.arthas.core.env;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hengyunabc 2019-12-27
|
||||
*
|
||||
*/
|
||||
public class ArthasEnvironmentTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
ArthasEnvironment arthasEnvironment = new ArthasEnvironment();
|
||||
|
||||
Assertions.assertThat(arthasEnvironment.resolvePlaceholders("hello, ${java.version}"))
|
||||
.isEqualTo("hello, " + System.getProperty("java.version"));
|
||||
|
||||
Assertions.assertThat(arthasEnvironment.resolvePlaceholders("hello, ${xxxxxxxxxxxxxxx}"))
|
||||
.isEqualTo("hello, ${xxxxxxxxxxxxxxx}");
|
||||
|
||||
System.setProperty("xxxxxxxxxxxxxxx", "vvv");
|
||||
|
||||
Assertions.assertThat(arthasEnvironment.resolvePlaceholders("hello, ${xxxxxxxxxxxxxxx}"))
|
||||
.isEqualTo("hello, vvv");
|
||||
|
||||
System.clearProperty("xxxxxxxxxxxxxxx");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_properties() {
|
||||
ArthasEnvironment arthasEnvironment = new ArthasEnvironment();
|
||||
|
||||
Properties properties1 = new Properties();
|
||||
Properties properties2 = new Properties();
|
||||
arthasEnvironment.addLast(new PropertiesPropertySource("test1", properties1));
|
||||
arthasEnvironment.addLast(new PropertiesPropertySource("test2", properties2));
|
||||
|
||||
properties2.put("test.key", "2222");
|
||||
|
||||
Assertions.assertThat(arthasEnvironment.resolvePlaceholders("hello, ${test.key}")).isEqualTo("hello, 2222");
|
||||
|
||||
properties1.put("java.version", "test");
|
||||
properties1.put("test.key", "test");
|
||||
|
||||
Assertions.assertThat(arthasEnvironment.resolvePlaceholders("hello, ${java.version}"))
|
||||
.isEqualTo("hello, " + System.getProperty("java.version"));
|
||||
|
||||
Assertions.assertThat(arthasEnvironment.resolvePlaceholders("hello, ${test.key}")).isEqualTo("hello, test");
|
||||
}
|
||||
}
|
7
pom.xml
7
pom.xml
@ -160,6 +160,13 @@
|
||||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<!-- use 2.9.1 for Java 7 projects -->
|
||||
<version>3.11.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
|
Loading…
Reference in New Issue
Block a user