Refactor ConfigInitializer and improve map type config (#4321)

* Refactor ConfigInitializer

* Rename some variable names and add some java docs

Co-authored-by: kezhenxu94 <kezhenxu94@163.com>
Co-authored-by: 吴晟 Wu Sheng <wu.sheng@foxmail.com>
This commit is contained in:
John Niang 2020-02-06 17:09:39 +08:00 committed by GitHub
parent 69d238e613
commit 41c63672c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 121 additions and 47 deletions

View File

@ -21,9 +21,13 @@ package org.apache.skywalking.apm.util;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.logging.Logger;
@ -44,38 +48,36 @@ public class ConfigInitializer {
for (Field field : recentConfigType.getFields()) {
if (Modifier.isPublic(field.getModifiers()) && Modifier.isStatic(field.getModifiers())) {
String configKey = (parentDesc + "." + field.getName()).toLowerCase();
/**
* Map config format is, config_key[map_key]=map_value
* Such as plugin.opgroup.resttemplate.rule[abc]=/url/path
*/
if (field.getType().equals(Map.class)) {
Map map = (Map)field.get(null);
for (Object key : properties.keySet()) {
String stringKey = key.toString();
if (stringKey.startsWith(configKey + "[") && stringKey.endsWith("]")) {
String itemKey = stringKey.substring(configKey.length() + 1, stringKey.length() - 1);
map.put(itemKey, properties.getProperty(stringKey));
}
Class<?> type = field.getType();
if (type.equals(Map.class)) {
/*
* Map config format is, config_key[map_key]=map_value
* Such as plugin.opgroup.resttemplate.rule[abc]=/url/path
*/
// Deduct two generic types of the map
ParameterizedType genericType = (ParameterizedType)field.getGenericType();
Type[] argumentTypes = genericType.getActualTypeArguments();
Type keyType = null;
Type valueType = null;
if (argumentTypes != null && argumentTypes.length == 2) {
// Get key type and value type of the map
keyType = argumentTypes[0];
valueType = argumentTypes[1];
}
Map map = (Map)field.get(null);
// Set the map from config key and properties
setForMapType(configKey, map, properties, keyType, valueType);
} else {
/**
/*
* Others typical field type
*/
String value = properties.getProperty(configKey);
if (value != null) {
Class<?> type = field.getType();
if (type.equals(int.class))
field.set(null, Integer.valueOf(value));
else if (type.equals(String.class))
field.set(null, value);
else if (type.equals(long.class))
field.set(null, Long.valueOf(value));
else if (type.equals(boolean.class))
field.set(null, Boolean.valueOf(value));
else if (type.equals(List.class))
field.set(null, convert2List(value));
else if (type.isEnum())
field.set(null, Enum.valueOf((Class<Enum>)type, value.toUpperCase()));
// Convert the value into real type
Object convertedValue = convertToTypicalType(type, value);
if (convertedValue != null) {
field.set(null, convertedValue);
}
}
}
@ -87,28 +89,108 @@ public class ConfigInitializer {
}
}
private static List convert2List(String value) {
List result = new LinkedList();
if (StringUtil.isEmpty(value)) {
return result;
/**
* Convert string value to typical type.
* @param type type to convert
* @param value string value to be converted
* @return converted value or null
*/
private static Object convertToTypicalType(Type type, String value) {
if (value == null || type == null) {
return null;
}
Object result = null;
if (String.class.equals(type)) {
result = value;
} else if (int.class.equals(type) || Integer.class.equals(type)) {
result = Integer.valueOf(value);
} else if (long.class.equals(type) || Long.class.equals(type)) {
result = Long.valueOf(value);
} else if (boolean.class.equals(type) || Boolean.class.equals(type)) {
result = Boolean.valueOf(value);
} else if (float.class.equals(type) || Float.class.equals(type)) {
result = Boolean.valueOf(value);
} else if (double.class.equals(type) || Double.class.equals(type)) {
result = Double.valueOf(value);
} else if (List.class.equals(type)) {
result = convert2List(value);
} else if (type instanceof Class) {
Class<?> clazz = (Class<?>)type;
if (clazz.isEnum()) {
result = Enum.valueOf((Class<Enum>)type, value.toUpperCase());
}
}
return result;
}
/**
* Set map items.
* @param configKey config key must not be null
* @param map map to set must not be null
* @param properties properties must not be null
* @param keyType key type of the map
* @param valueType value type of the map
*/
private static void setForMapType(String configKey, Map<Object, Object> map, Properties properties,
final Type keyType,
final Type valueType) {
Objects.requireNonNull(configKey);
Objects.requireNonNull(map);
Objects.requireNonNull(properties);
String prefix = configKey + "[";
String suffix = "]";
properties.forEach((propertyKey, propertyValue) -> {
String propertyStringKey = propertyKey.toString();
if (propertyStringKey.startsWith(prefix) && propertyStringKey.endsWith(suffix)) {
String itemKey = propertyStringKey.substring(prefix.length(), propertyStringKey.length() - suffix.length());
Object keyObj;
Object valueObj;
keyObj = convertToTypicalType(keyType, itemKey);
valueObj = convertToTypicalType(valueType, propertyValue.toString());
if (keyObj == null) {
keyObj = itemKey;
}
if (valueObj == null) {
valueObj = propertyValue;
}
map.put(keyObj, valueObj);
}
});
}
private static List<String> convert2List(String value) {
if (StringUtil.isEmpty(value)) {
return Collections.emptyList();
}
List<String> result = new LinkedList<>();
String[] segments = value.split(",");
for (String segment : segments) {
String trimmedSegment = segment.trim();
if (!StringUtil.isEmpty(trimmedSegment)) {
if (StringUtil.isNotEmpty(trimmedSegment)) {
result.add(trimmedSegment);
}
}
return result;
}
}
class ConfigDesc {
private LinkedList<String> descs = new LinkedList<String>();
private LinkedList<String> descs = new LinkedList<>();
void append(String currentDesc) {
descs.addLast(currentDesc);
if (StringUtil.isNotEmpty(currentDesc)) {
descs.addLast(currentDesc);
}
}
void removeLastDesc() {
@ -117,18 +199,6 @@ class ConfigDesc {
@Override
public String toString() {
if (descs.size() == 0) {
return "";
}
StringBuilder ret = new StringBuilder(descs.getFirst());
boolean first = true;
for (String desc : descs) {
if (first) {
first = false;
continue;
}
ret.append(".").append(desc);
}
return ret.toString();
return String.join(".", descs);
}
}

View File

@ -66,12 +66,16 @@ public class SnifferConfigInitializerTest {
@Test
public void testConfigOverriding() throws AgentPackageNotFoundException, ConfigNotFoundException {
System.setProperty("skywalking.agent.service_name", "testAppFromSystem");
System.setProperty("skywalking.agent.instance_properties[key1]", "value1");
System.setProperty("skywalking.agent.instance_properties[key2]", "value2");
System.setProperty("skywalking.collector.backend_service", "127.0.0.1:8090");
String agentOptions = "agent.service_name=testAppFromAgentOptions,logging.level=debug";
SnifferConfigInitializer.initialize(agentOptions);
assertThat(Config.Agent.SERVICE_NAME, is("testAppFromAgentOptions"));
assertThat(Config.Collector.BACKEND_SERVICE, is("127.0.0.1:8090"));
assertThat(Config.Logging.LEVEL, is(LogLevel.DEBUG));
assertThat(Config.Agent.INSTANCE_PROPERTIES.get("key1"), is("value1"));
assertThat(Config.Agent.INSTANCE_PROPERTIES.get("key2"), is("value2"));
}
@Test