blob: 06113c3bc735c2f1ce80f517c3d3b9fda89f0326 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 org.apache.doris.common;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.FileReader;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ConfigBase {
private static final Logger LOG = LogManager.getLogger(ConfigBase.class);
@Retention(RetentionPolicy.RUNTIME)
public static @interface ConfField {
String value() default "";
boolean mutable() default false;
boolean masterOnly() default false;
String comment() default "";
}
public static Properties props;
public static Class<? extends ConfigBase> confClass;
public void init(String propfile) throws Exception {
props = new Properties();
confClass = this.getClass();
props.load(new FileReader(propfile));
replacedByEnv();
setFields();
}
public static HashMap<String, String> dump() throws Exception {
HashMap<String, String> map = new HashMap<String, String>();
Field[] fields = confClass.getFields();
for (Field f : fields) {
if (f.getAnnotation(ConfField.class) == null) {
continue;
}
if (f.getType().isArray()) {
switch (f.getType().getSimpleName()) {
case "short[]":
map.put(f.getName(), Arrays.toString((short[]) f.get(null)));
break;
case "int[]":
map.put(f.getName(), Arrays.toString((int[]) f.get(null)));
break;
case "long[]":
map.put(f.getName(), Arrays.toString((long[]) f.get(null)));
break;
case "double[]":
map.put(f.getName(), Arrays.toString((double[]) f.get(null)));
break;
case "boolean[]":
map.put(f.getName(), Arrays.toString((boolean[]) f.get(null)));
break;
case "String[]":
map.put(f.getName(), Arrays.toString((String[]) f.get(null)));
break;
default:
throw new Exception("unknown type: " + f.getType().getSimpleName());
}
} else {
map.put(f.getName(), f.get(null).toString());
}
}
return map;
}
private static void replacedByEnv() throws Exception {
Pattern pattern = Pattern.compile("\\$\\{([^\\}]*)\\}");
for (String key : props.stringPropertyNames()) {
String value = props.getProperty(key);
Matcher m = pattern.matcher(value);
while (m.find()) {
String envValue = System.getProperty(m.group(1));
envValue = (envValue != null) ? envValue : System.getenv(m.group(1));
if (envValue != null) {
value = value.replace("${" + m.group(1) + "}", envValue);
} else {
throw new Exception("no such env variable: " + m.group(1));
}
}
props.setProperty(key, value);
}
}
private static void setFields() throws Exception {
Field[] fields = confClass.getFields();
for (Field f : fields) {
// ensure that field has "@ConfField" annotation
ConfField anno = f.getAnnotation(ConfField.class);
if (anno == null) {
continue;
}
// ensure that field has property string
String confKey = anno.value().equals("") ? f.getName() : anno.value();
String confVal = props.getProperty(confKey);
if (Strings.isNullOrEmpty(confVal)) {
continue;
}
setConfigField(f, confVal);
}
}
public static void setConfigField(Field f, String confVal) throws IllegalAccessException, Exception {
confVal = confVal.trim();
String[] sa = confVal.split(",");
for (int i = 0; i < sa.length; i++) {
sa[i] = sa[i].trim();
}
// set config field
switch (f.getType().getSimpleName()) {
case "short":
f.setShort(null, Short.parseShort(confVal));
break;
case "int":
f.setInt(null, Integer.parseInt(confVal));
break;
case "long":
f.setLong(null, Long.parseLong(confVal));
break;
case "double":
f.setDouble(null, Double.parseDouble(confVal));
break;
case "boolean":
f.setBoolean(null, Boolean.parseBoolean(confVal));
break;
case "String":
f.set(null, confVal);
break;
case "short[]":
short[] sha = new short[sa.length];
for (int i = 0; i < sha.length; i++) {
sha[i] = Short.parseShort(sa[i]);
}
f.set(null, sha);
break;
case "int[]":
int[] ia = new int[sa.length];
for (int i = 0; i < ia.length; i++) {
ia[i] = Integer.parseInt(sa[i]);
}
f.set(null, ia);
break;
case "long[]":
long[] la = new long[sa.length];
for (int i = 0; i < la.length; i++) {
la[i] = Long.parseLong(sa[i]);
}
f.set(null, la);
break;
case "double[]":
double[] da = new double[sa.length];
for (int i = 0; i < da.length; i++) {
da[i] = Double.parseDouble(sa[i]);
}
f.set(null, da);
break;
case "boolean[]":
boolean[] ba = new boolean[sa.length];
for (int i = 0; i < ba.length; i++) {
ba[i] = Boolean.parseBoolean(sa[i]);
}
f.set(null, ba);
break;
case "String[]":
f.set(null, sa);
break;
default:
throw new Exception("unknown type: " + f.getType().getSimpleName());
}
}
public static Map<String, Field> getAllMutableConfigs() {
Map<String, Field> mutableConfigs = Maps.newHashMap();
Field fields[] = ConfigBase.confClass.getFields();
for (Field field : fields) {
ConfField confField = field.getAnnotation(ConfField.class);
if (confField == null) {
continue;
}
if (!confField.mutable()) {
continue;
}
mutableConfigs.put(confField.value().equals("") ? field.getName() : confField.value(), field);
}
return mutableConfigs;
}
public synchronized static void setMutableConfig(String key, String value) throws DdlException {
Map<String, Field> mutableConfigs = getAllMutableConfigs();
Field field = mutableConfigs.get(key);
if (field == null) {
throw new DdlException("Config '" + key + "' does not exist or is not mutable");
}
try {
ConfigBase.setConfigField(field, value);
} catch (Exception e) {
throw new DdlException("Failed to set config '" + key + "'. err: " + e.getMessage());
}
LOG.info("set config {} to {}", key, value);
}
public synchronized static List<List<String>> getConfigInfo() throws DdlException {
List<List<String>> configs = Lists.newArrayList();
Field[] fields = confClass.getFields();
for (Field f : fields) {
List<String> config = Lists.newArrayList();
ConfField anno = f.getAnnotation(ConfField.class);
if (anno == null) {
continue;
}
String confKey = anno.value().equals("") ? f.getName() : anno.value();
String confVal;
try {
confVal = String.valueOf(f.get(null));
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new DdlException("Failed to get config '" + confKey + "'. err: " + e.getMessage());
}
config.add(confKey);
config.add(Strings.nullToEmpty(confVal));
config.add(f.getType().getSimpleName());
config.add(String.valueOf(anno.mutable()));
config.add(String.valueOf(anno.masterOnly()));
config.add(anno.comment());
configs.add(config);
}
return configs;
}
public synchronized static boolean checkIsMasterOnly(String key) {
Map<String, Field> mutableConfigs = getAllMutableConfigs();
Field f = mutableConfigs.get(key);
if (f == null) {
return false;
}
ConfField anno = f.getAnnotation(ConfField.class);
if (anno == null) {
return false;
}
return anno.masterOnly();
}
}