![JAR search and dependency download from the Maven repository](/logo.png)
io.github.lab515.utils.Profiles Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of qray Show documentation
Show all versions of qray Show documentation
remoting ondemand in java
package io.github.lab515.utils;
import io.github.lab515.textbot.expr.Evaluator;
import io.github.lab515.textbot.expr.Oper;
import java.util.*;
/**
* This is the hierachy profile settings, which support syntax as below
* \@{} defines a scope, which can be inherited from othe scope with name (profile name)
*
* @author yang peng
*/
public class Profiles {
/**
* expose the property handler interface for external integration
*/
static class PropertyEvaluator extends Evaluator {
private static LinkedHashMap apiResults = new LinkedHashMap();
public boolean resolveMode = false;
private String checkResult(String key, String val) {
String ret = null;
synchronized (apiResults) {
ret = apiResults.get(key);
if (val != null) apiResults.put(key, val);
}
return ret;
}
private HashSet tracks;
private Properties props;
private LinkedHashMap vars;
public PropertyEvaluator(HashSet tt, Properties pp, LinkedHashMap vv) {
tracks = tt;
props = pp;
vars = vv;
}
@Override
protected void accessVariable(String varName, Oper out, Object uo) {
out.isNum = false;
out.Val = getVariable(props, varName, true, resolveMode, tracks, vars);
if (out.Val == null) out.Val = "";
}
@Override
protected void processAPI(String apiName, List paras, Oper out, Object uo) {
out.isNum = false;
out.Val = "";
}
}
/**
* the default conifg loaded from the base profile
*/
private static Properties _props = null;
/**
* default binding profileProps,
*/
private static Properties _bindingProps = null;
/**
* default overwrite properties
*/
private static Properties _ovProps = null;
private static boolean _defImmutable = true; // fix the capillary client + qrayclient mixed profiling issue
public static void setDefaultImmutable(boolean val) {
if (!val || _props != null) _defImmutable = val;
}
// no use for profiles, only for old framework enahcnement
//private static String _ovPrefix = null;
private static String checkRemoverName(String name) throws Exception {
StringBuilder sb = new StringBuilder();
String[] arr = name.split(",");
for (String ar : arr) {
ar = checkProfileName(ar, true);
if (ar != null) {
if (sb.length() > 0) sb.append(",");
sb.append(ar);
}
}
return sb.length() > 0 ? sb.toString() : null;
}
private static String checkProfileName(String name, boolean propMode) throws Exception {
if (name == null || (name = name.trim()).length() < 1) return "";
for (int i = 0; i < name.length(); i++) {
char c = name.charAt(i);
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (i > 0 && c >= '0' && c <= '9') || (i > 0 && c == '.' && propMode))) {
if (propMode) return null;
throw new Exception("invalid profile name: " + name);
}
}
return name;
}
private static String trimNormal(String str) {
if (str == null || str.length() < 1) return str;
char[] t = str.toCharArray();
int st = 0;
int sz = str.length();
while (st < sz && t[st] > 4 && t[st] <= ' ') st++;
while (sz-- > 0 && t[sz] > 4 && t[sz] <= ' ') ;
sz++;
if (sz > st) return str.substring(st, sz);
else return "";
}
// add: escape char \\ handling 2019-5-20, keep compatibility with java properties
private static String preProcessProperties(String src) {
if (src == null)
return null;
char[] cs = src.toCharArray();
StringBuilder sb = new StringBuilder();
char lst = ' ';
for (int i = 0; i < cs.length; i++) {
char c = cs[i];
if (lst == '^' || lst == '\\') {
if (c == '{' || c == '}') sb.append(c == '{' ? '\0' : '\1');
else if (c == '$') sb.append('\2');
else if (c == '#') sb.append('\3');
else if (c == '\n') {
} // do nothing, connected string
else if (lst == '\\') { // \0 \1 will be '0'
if (c == 't') sb.append('\t');
else if (c == 'n') sb.append('\4'); // special treatment as well
else if (c == 'r') sb.append('\r');
else if (c == 'b') sb.append('\b');
else if (c == 'f') sb.append('\f');
else sb.append(c);
} else sb.append(c);
lst = ' '; // reset
} else {
if (c != '^' && c != '\\') sb.append(c);
lst = c;
}
}
if (lst == '^' || lst == '\\') sb.append(lst); // add it anyway
src = sb.toString();
sb.setLength(0);
String[] arr = src.split("\n");
String line = null;
String prefix = null;
String singlePrefix = null;
String last = "";
for (int i = 0; i < arr.length; i++) {
line = trimNormal(arr[i]);
int pos = line.indexOf('#');
if (pos == 0) continue;
else if (pos > 0) {
line = trimNormal(line.substring(0, pos)); // .trim() may remove the $# escapers
}
if (line.length() < 1 && (prefix != null && singlePrefix != null)) {
sb.append("\4");
} else if (line.endsWith("\\")) {
// fix: make sure not a translator
int p = 1;
while (line.charAt(line.length() - 1 - p) == '\\')
p++;
if ((p % 2) != 0) {
line = line.substring(0, line.length() - 1);
if (i < arr.length - 1) {
arr[i + 1] = line + arr[i + 1];
line = "";
}
}
}
if (prefix != null) {
if (singlePrefix == null) {
pos = line.indexOf('{');
if (pos > 0) {
singlePrefix = prefix;
prefix = trimNormal(line.substring(0, pos));
if (prefix.length() > 0 && prefix.endsWith("=")) {
sb.append(singlePrefix);
sb.append(prefix);
arr[i] = line.substring(pos + 1);
i--;
continue;
}
prefix = singlePrefix;
singlePrefix = null;
}
}
pos = line.indexOf('}');
if (pos >= 0) {
arr[i] = line.substring(pos + 1);
line = trimNormal(line.substring(0, pos));
if (singlePrefix != null) {
sb.append(line);
sb.append("\n");
} else {
if (line.length() > 0) {
sb.append(prefix);
sb.append(line);
sb.append("\n");
}
}
prefix = singlePrefix;
singlePrefix = null;
// check if it's a {, it means it's just null
if (prefix != null && prefix.equalsIgnoreCase("{"))
prefix = null;
i--; // let it process rest
} else {
if (singlePrefix != null) {
sb.append(line);
sb.append("\4");
} else {
sb.append(prefix);
sb.append(line);
sb.append("\n");
}
}
} else {
// first of all, find the { if have
pos = line.indexOf('{');
if (pos >= 0) {
prefix = trimNormal(line.substring(0, pos));
if (prefix.length() < 1) {
prefix = last;
if (prefix.length() > 0) {
sb.setLength(sb.length() - prefix.length() - 1); // remove
// last
// +
// \n
}
} else if (prefix.endsWith("=")) {
singlePrefix = "{";
sb.append(prefix);
}
if (singlePrefix == null && prefix.length() > 0 && !prefix.endsWith("."))
prefix += ".";
arr[i] = line.substring(pos + 1);
i--;
} else {
sb.append(line);
sb.append("\n");
last = line;
}
}
}
src = sb.toString();
sb.setLength(0);
src = src.replace('\0', '{').replace('\1', '}').replace('\3', '#');
return src;
}
/**
* load properties based on a name of file, will look into 3 places
*/
private static Properties loadProperties(String content, Properties ret) {
Properties defProfiles = ret;
String ss = preProcessProperties(content);
if (ss == null) {
return null;
}
if (defProfiles == null) {
defProfiles = new Properties();
}
// change, we do manual load for customization
String[] arr = ss.split("\n");
for (String ar : arr) {
ar = ar.replace('\4', '\n'); // add the \n stuff
int p = ar.indexOf('=');
if (p < 1) continue;
ss = trimNormal(ar.substring(0, p));
if (ss.length() < 1) continue;
defProfiles.put(ss, ar.substring(p + 1));
}
return defProfiles;
}
public static void setOverwrittenProps(Properties ovProps) {
_ovProps = ovProps;
}
public static void switchProfile(String name) throws Exception {
loadProfile(name, null, false, true);
}
public static void switchProfile(String name, boolean includeSys) throws Exception {
loadProfile(name, null, includeSys, true);
}
/**
* load profile by default, no reload, include systemprops
*
* @param name
* @return
*/
public static Properties loadProfile(String name) throws Exception {
return loadProfile(name, null, true, false);
}
/**
* Default method to load certain profile
*
* @param name
* @param reloadContent
* @param includeSysProps
* @return
*/
public static Properties loadProfile(String name, String reloadContent, boolean includeSysProps, boolean setAsDefault)
throws Exception {
Properties conf = _props;
if (reloadContent != null) {
conf = loadProperties(reloadContent, null);
if (setAsDefault && (_props == null || !_defImmutable)) {
_props = conf;
}
}
if (conf == null) {
// load the default profiles again, in case any issue comes up
return null;
}
Properties p1 = null;
if (includeSysProps) {
p1 = new Properties(System.getProperties());
}
HashSet tracks = new HashSet();
LinkedHashMap vars = new LinkedHashMap();
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
// supported variables: now, now.year, now.weekday, now.date,now.hour,etc
vars.put("cxt.ms", Long.toString(calendar.getTimeInMillis()));
vars.put("cxt.year", Integer.toString(calendar.get(Calendar.YEAR)));
vars.put("cxt.month", Integer.toString(calendar.get(Calendar.MONTH)));
vars.put("cxt.day", Integer.toString(calendar.get(Calendar.DAY_OF_MONTH)));
vars.put("cxt.weekday", Integer.toString(calendar.get(Calendar.DAY_OF_WEEK) - 1)); // As SUNDAY == 1, MONDAY == 2
vars.put("cxt.hours", Integer.toString(calendar.get(Calendar.HOUR_OF_DAY)));
vars.put("cxt.minutes", Integer.toString(calendar.get(Calendar.MINUTE)));
vars.put("cxt.seconds", Integer.toString(calendar.get(Calendar.SECOND)));
//FIX: add overwritten proerties before init as well
if (_ovProps != null) {
if(p1 == null)p1 = new Properties();
copyProps(_ovProps, p1, true);
}
p1 = loadProfileInternal(name, null, conf, p1, vars, tracks);
// Add: overwriteen props
if (_ovProps != null) {
//p1.putAll(_ovProps);
copyProps(_ovProps, p1, true);
}
// ok, handle the variable, mapping
String key = null;
String val = null;
// ADD: deferred processing, include removing
LinkedList allList = new LinkedList();
for (Object s : p1.keySet()) {
key = (String) s;
if (key.startsWith("-")) {
allList.addLast(key);
} else if (key.startsWith("?"))
allList.addFirst(key);
}
// all defered
for (String s : allList) {
val = p1.getProperty(s);
if (key.startsWith("-")) {
if (val != null && val.length() > 0) {
tracks.clear();
val = getVariable(p1, val, false, true, tracks, vars);
if (val == null || val.length() < 1) val = "false";
}
if (val == null || val.length() < 1 || Evaluator.getBoolean(val)) {
for (String a : key.substring(1).split(",")) {
p1.remove(val); // remove it
//ret.remove("?" + val);
}
}
} else {
key = s.substring(1);
tracks.clear();
getVariable(p1, key, true, true, tracks, vars);
}
p1.remove(s);
}
if (setAsDefault && (conf == _props && (_bindingProps == null || !_defImmutable))) {
if (_bindingProps == null)
_bindingProps = new Properties();
else _bindingProps.clear();
// FIX, putAll doesn't work with system properties
//_bindingProps.putAll(p1);
copyProps(p1, _bindingProps, true);
}
return p1;
}
private static void copyProps(Properties src, Properties tar, boolean overwrite) {
Enumeration> en = src.propertyNames();
while (en.hasMoreElements()) {
String n = (String) en.nextElement();
String v = src.getProperty(n);
if (!overwrite && tar.getProperty(n) != null) continue;
tar.setProperty(n, v);
}
}
/**
* the actual profile loader method, recursively call, make sure the profile
* has been loaded based on the hierachy defiition
*
* @param name
* @param loaded
* @param conf
* @param add
* @return
*/
private static Properties loadProfileInternal(String name, Map loaded, Properties conf,
Properties add, LinkedHashMap vars, HashSet tracks) throws Exception {
// name could be a variables, or contains multiple names, or just a normal stuff
if (name == null) name = "";
Properties ret = null;
if (name.length() > 0) {
tracks.clear();
if (name.indexOf('$') >= 0) {
if (add == null) add = new Properties();
name = getVariable(add, name, false, false, tracks, vars);
}
if (name.indexOf('+') >= 0) {
String[] prfs = name.split("\\+");
for (String prf : prfs) {
prf = checkProfileName(prf, false);
if (prf.length() > 0) {
ret = loadProfileInternal(prf, loaded, conf, add, vars, tracks);
add = ret;
}
}
if (ret == null) ret = loadProfileInternal("", loaded, conf, add, vars, tracks);
} else {
name = checkProfileName(name, false);
if (loaded != null && loaded.containsKey(name)) {
ret = add;
if (ret == null) ret = new Properties();
}
}
if (ret != null) return ret;
}
ret = add;
if (ret == null) ret = new Properties();
boolean checkProps = false;
String mapServer = name;
String baseServer = mapServer.length() < 1 ? "" : conf.getProperty("@" + mapServer);
if (baseServer != null) {
baseServer = baseServer.trim();
if (baseServer.equals(mapServer)) baseServer = "";
} else {
//FIX: 2018-12-13, profile. declaration is optional now
if (mapServer.length() > 0) {
//throw new Exception("profile not exists: " + mapServer);
checkProps = true;
}
baseServer = ""; // set to root
}
if (loaded == null) loaded = new LinkedHashMap();
loaded.put(mapServer, mapServer); // loading state marked
if (!baseServer.equals(mapServer)) ret = loadProfileInternal(baseServer, loaded, conf, ret, vars, tracks);
String prefix = mapServer.length() > 0 ? "@" + mapServer : null;
String key = null;
String val = null;
LinkedList allVars = new LinkedList();
int cnt = 0;
for (Object o : conf.keySet()) {
key = (String) o;
if (prefix != null && key.startsWith(prefix)) { // this is
key = key.substring(prefix.length()).trim();
if (!key.startsWith(".")) continue;
key = key.substring(1).trim();
} else if (prefix != null || key.startsWith("@")) continue;
checkProps = false;
if (key.startsWith("-")) {
// check names as well
val = checkRemoverName(key.substring(1));
if (val != null) {
allVars.addLast(val);
// possible variable
allVars.addLast((String) conf.get(o));
}
} else {
key = checkProfileName(key, true);
if (key == null) continue;
val = (String) conf.get(o);
if (val == null) val = "";
if (val.indexOf('$') >= 0) {
if (val.startsWith("=")) {
ret.put(key, val.substring(1));
ret.put("?" + key, "="); // defered
} else {
allVars.addFirst(val);
allVars.addFirst(key);
cnt += 2;
ret.put(key, val);
ret.put("?" + key, "$");
}
} else {
// it might be a defer, but doesnt matter
if (val.startsWith("=")) val = val.substring(1);
ret.put(key, val.replace('\2', '$').trim());
ret.remove("?" + key); // remove flag
}
}
}
// check if property defined
if (checkProps) throw new Exception("profile not exists: " + mapServer);
// process the rest stuff, map over variable
key = null;
for (String s : allVars) {
cnt--;
if (key == null) {
key = s;
continue;
}
val = s;
if (cnt < 0) {
if (val.indexOf('$') >= 0) {
if (val.startsWith("=")) {
// add it
ret.put("-" + key, val.substring(1)); // defered, might be - or normal
key = null;
} else {
tracks.clear();
val = getVariable(ret, val, false, false, tracks, vars);
if (val == null || val.length() < 1) val = "false";
}
} else {
if (val.startsWith("=")) val = val.substring(1).replace('\2', '$').trim();
}
if (key != null && (val == null || val.length() < 1 || Evaluator.getBoolean(val))) {
for (String a : key.split(",")) {
ret.remove(val); // remove it
ret.remove("?" + val);
}
}
} else {
tracks.clear();
val = getVariable(ret, key, true, false, tracks, vars);
}
key = null;
}
allVars.clear();
loaded.remove(mapServer);
return ret;
}
private static String getVariable(Properties props, String data, boolean nameMode, boolean resolveAll, HashSet tracks, LinkedHashMap vars) {
if (data == null)
return "";
data = trimNormal(data);
if (data.length() < 1) return "";
String val = null;
String flag = null;
if (nameMode) { // for map mode, we just need to figure out the data
if (tracks.contains(data)) data = "[O:" + data + "]";
else {
val = props.getProperty(data); //
flag = props.getProperty("?" + data); // get the flag
if (val == null) val = "[!:" + data + "]";
else if (flag != null) {
// deferred
if (resolveAll || flag.startsWith("$")) { // "=, $"
tracks.add(data);
val = getVariable(props, val, false, resolveAll, tracks, vars);
props.put(data, val);
props.remove("?" + data);
} else val = "[D:" + data + "]";
}
data = val;
}
} else {
String[] arr = ("-" + data + "-").split("\\$");
int len = arr.length;
if (len < 3)
return data; // incorrect format!!
arr[0] = arr[0].substring(1);
arr[len - 1] = arr[len - 1].substring(0, arr[len - 1].length() - 1);
int c = len >> 1;
int pos = 0;
for (int i = 0; i < c; i++) {
val = arr[i * 2 + 1];
arr[i * 2 + 1] = "";
if (val.length() < 1)
arr[i * 2 + 1] = "$";
else if (i * 2 + 1 == len - 1)
arr[i * 2 + 1] = "$" + arr[i * 2 + 1];
else {
val = val.replace('\2', '$').trim();
if (val.length() < 1)
continue; // no change
// replace the exisitng stuff with new one
PropertyEvaluator pe = new PropertyEvaluator(tracks, props, vars);
pe.resolveMode = resolveAll;
val = pe.evaluate(val, vars);
if (val == null) val = "";
arr[i * 2 + 1] = val;
}
}
StringBuilder sb = new StringBuilder();
for (String s : arr)
sb.append(s);
data = sb.toString().replace('\2', '$').trim();
}
return data;
}
/**
* get default binding property
*
* @param name
* @return
*/
public static String getProperty(String name) {
if (name == null || _bindingProps == null)
return null;
return _bindingProps.getProperty(name);
}
/**
* @return the default binding properties
*/
public static Properties getProperties() {
Properties ret = new Properties();
if (_bindingProps != null) {
ret.putAll(_bindingProps);
}
return ret;
}
/**
* set the default binding property
*
* @param name
* @param value
*/
public static void setProperty(String name, String value) {
if (name == null || _bindingProps == null)
return;
_bindingProps.setProperty(name, value);
}
public static void main(String[] args) throws Exception {
String profileContent = "a=12\n" +
"b= =12\n" +
"c=12^{\n" +
"aa==$b+a$\n" +
//"@b=\n" +
"@b{\n" +
" a=$b$^$\n" +
"}\n" +
"@b.-a";
Properties ss = Profiles.loadProfile("b", profileContent, false, true);
for (Object s : ss.keySet()) {
System.out.println(s + ":" + ss.get(s));
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy