package act.conf;
/*-
* #%L
* ACT Framework
* %%
* Copyright (C) 2014 - 2017 ActFramework
* %%
* 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.
* #L%
*/
import act.Act;
import act.app.ProjectLayout;
import act.app.RuntimeDirs;
import act.util.SysProps;
import org.osgl.logging.L;
import org.osgl.logging.Logger;
import org.osgl.util.C;
import org.osgl.util.IO;
import org.osgl.util.S;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import static act.conf.ConfigKey.KEY_COMMON_CONF_TAG;
/**
* Loading configurations from conf file or conf dir
*/
public abstract class ConfLoader<T extends Config> {
private static Logger logger = L.get(ConfLoader.class);
// trim "act." from conf keys
private static Map<String, Object> processConf(Map<String, ?> conf) {
Map<String, Object> m = new HashMap<String, Object>(conf.size());
for (String s : conf.keySet()) {
Object o = conf.get(s);
if (s.startsWith("act.")) s = s.substring(4);
m.put(s, o);
}
return m;
}
public T load(File resourceRoot) {
// load conf from disk
Map<String, ?> rawConf = null == resourceRoot ? C.newMap() : loadConfFromDisk(resourceRoot);
// load conf from System.properties
Properties sysProps = System.getProperties();
rawConf.putAll((Map) sysProps);
// strip off "act." prefix if has any
rawConf = processConf(rawConf);
// initialize the configuration with all loaded data
return create(rawConf);
}
protected abstract T create(Map<String, ?> rawConf);
protected abstract String confFileName();
private Map loadConfFromDisk(File conf) {
if (conf.isDirectory()) {
return loadConfFromDir(conf);
} else {
return loadConfFromFile(conf);
}
}
private Map loadConfFromFile(File conf) {
if (!conf.canRead()) {
logger.warn("Cannot read conf file[%s]", conf.getAbsolutePath());
return C.newMap();
}
InputStream is = null;
if (null == conf) {
ClassLoader cl = Act.class.getClassLoader();
is = cl.getResourceAsStream("/" + confFileName());
} else {
try {
is = new FileInputStream(conf);
} catch (IOException e) {
logger.warn(e, "Error opening conf file:" + conf);
}
}
if (null != is) {
Properties p = new Properties();
try {
p.load(is);
return p;
} catch (Exception e) {
logger.warn(e, "Error loading %s", confFileName());
} finally {
IO.close(is);
}
}
return C.newMap();
}
/**
* Return the "common" configuration set name. By default it is "common"
* @return the "common" conf set name
*/
public static String common() {
String common = SysProps.get(KEY_COMMON_CONF_TAG);
if (S.blank(common)) {
common = "common";
}
return common;
}
/**
* Return the name of the current conf set
* @return the conf set name
*/
public static String confSetName() {
String profile = SysProps.get(AppConfigKey.PROFILE.key());
if (S.blank(profile)) {
profile = Act.mode().name().toLowerCase();
}
return profile;
}
private Map loadConfFromDir(File resourceDir) {
if (!resourceDir.exists()) {
logger.warn("Cannot read conf dir[%s]", resourceDir.getAbsolutePath());
return C.newMap();
}
Map map = C.newMap();
/*
* Load from resources root
*/
map.putAll(loadConfFromDir_(resourceDir));
/*
* Load from resources/conf root
*/
File confDir = ProjectLayout.Utils.file(resourceDir, RuntimeDirs.CONF);
map.putAll(loadConfFromDir_(confDir));
/*
* try load from resources/conf/common conf
*/
String common = common();
File commonConfDir = new File(confDir, common);
if (commonConfDir.isDirectory()) {
map.putAll(loadConfFromDir_(commonConfDir));
}
/*
* try to load conf from profile conf dir, e.g. ${conf_root}/uat or
* ${conf_root}/dev etc
*/
String profile = confSetName();
logger.debug("Loading conf profile: %s", profile);
File taggedConfDir = new File(confDir, profile);
if (taggedConfDir.exists() && taggedConfDir.isDirectory()) {
map.putAll(loadConfFromDir_(taggedConfDir));
}
return map;
}
private Map loadConfFromDir_(File confDir) {
File[] confFiles = confDir.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".properties") || name.endsWith(".conf");
}
});
if (null == confFiles) {
return C.map();
} else {
Map map = C.newMap();
int n = confFiles.length;
for (int i = 0; i < n; ++i) {
map.putAll(loadConfFromFile(confFiles[i]));
}
return map;
}
}
}