Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.osohq.oso.Host Maven / Gradle / Ivy
package com.osohq.oso;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import org.json.JSONArray;
import org.json.JSONObject;
public class Host implements Cloneable {
private Ffi.Polar ffiPolar;
private Map> classes;
private Map instances;
// Set to true to accept an expression from the core in toJava.
protected boolean acceptExpression;
public Host(Ffi.Polar polarPtr) {
acceptExpression = false;
ffiPolar = polarPtr;
classes = new HashMap>();
instances = new HashMap();
}
@Override
public Host clone() {
Host host = new Host(ffiPolar);
host.classes.putAll(classes);
host.instances.putAll(instances);
host.acceptExpression = acceptExpression;
return host;
}
protected void setAcceptExpression(boolean acceptExpression) {
this.acceptExpression = acceptExpression;
}
/** Get a registered Java class. */
public Class getClass(String name) throws Exceptions.UnregisteredClassError {
if (classes.containsKey(name)) {
return classes.get(name);
} else {
throw new Exceptions.UnregisteredClassError(name);
}
}
/**
* Store a Java class in the cache by name.
*
* @param name The name used to reference the class from within Polar.
* @throws Exceptions.DuplicateClassAliasError If the name is already registered.
*/
public String cacheClass(Class cls, String name) throws Exceptions.DuplicateClassAliasError {
if (classes.containsKey(name)) {
throw new Exceptions.DuplicateClassAliasError(
name, classes.get(name).getName(), cls.getName());
}
classes.put(name, cls);
return name;
}
/** Get a cached Java instance. */
public Object getInstance(long instanceId) throws Exceptions.UnregisteredInstanceError {
if (hasInstance(instanceId)) {
return instances.get(instanceId);
} else {
throw new Exceptions.UnregisteredInstanceError(instanceId);
}
}
/** Determine if a Java instance has been cached. */
public boolean hasInstance(long instanceId) {
return instances.containsKey(instanceId);
}
/** Cache an instance of a Java class. */
public Long cacheInstance(Object instance, Long id) throws Exceptions.OsoException {
if (id == null) {
id = ffiPolar.newId();
}
instances.put(id, instance);
return id;
}
/** Make an instance of a Java class from a {@code List} of fields. */
public Object makeInstance(String className, List initargs, long id)
throws Exceptions.OsoException {
Constructor constructor = null;
// Try to find a constructor applicable to the supplied arguments.
Class cls = classes.get(className);
if (cls == null) {
throw new Exceptions.UnregisteredClassError(className);
}
Class[] argTypes =
initargs.stream()
.map(arg -> arg.getClass())
.collect(Collectors.toUnmodifiableList())
.toArray(new Class[0]);
search:
for (Constructor c : cls.getConstructors()) {
Class[] paramTypes = c.getParameterTypes();
if (argTypes.length == paramTypes.length) {
for (int i = 0; i < paramTypes.length; i++) {
if (!paramTypes[i].isAssignableFrom(argTypes[i])) {
continue search;
}
}
constructor = c;
break search;
}
}
if (constructor == null) throw new Exceptions.MissingConstructorError(className);
Object instance;
try {
instance = constructor.newInstance(initargs.toArray());
} catch (Exception e) {
throw new Exceptions.InstantiationError(className, e);
}
cacheInstance(instance, id);
return instance;
}
/** Check if a class specializer is more specific than another class specializer. */
public boolean subspecializer(long instanceId, String leftTag, String rightTag)
throws Exceptions.UnregisteredClassError, Exceptions.UnregisteredInstanceError {
Object instance = getInstance(instanceId);
Class cls, leftClass, rightClass;
cls = instance.getClass();
leftClass = getClass(leftTag);
rightClass = getClass(rightTag);
if (leftClass.isInstance(instance) || rightClass.isInstance(instance)) {
while (cls != null) {
if (cls.equals(leftClass)) {
return true;
} else if (cls.equals(rightClass)) {
return false;
}
cls = cls.getSuperclass();
}
assert false;
}
return false;
}
/** Check if a Java instance is an instance of a class. */
public boolean isa(JSONObject instance, String classTag)
throws Exceptions.UnregisteredClassError, Exceptions.UnregisteredInstanceError,
Exceptions.UnexpectedPolarTypeError, Exceptions.OsoException {
Class cls = getClass(classTag);
return cls.isInstance(toJava(instance));
}
/** Return true if left is a subclass (or the same class) as right. */
public boolean isSubclass(String leftTag, String rightTag) {
Class leftClass, rightClass;
leftClass = getClass(leftTag);
rightClass = getClass(rightTag);
return rightClass.isAssignableFrom(leftClass);
}
public boolean operator(String op, List args) throws Exceptions.OsoException {
Object left = args.get(0), right = args.get(1);
if (op.equals("Eq")) {
if (left == null) return left == right;
else return left.equals(right);
}
throw new Exceptions.UnimplementedOperation(op);
}
/** Convert Java Objects to Polar (JSON) terms. */
public JSONObject toPolarTerm(Object value) throws Exceptions.OsoException {
// Build Polar value
JSONObject jVal = new JSONObject();
if (value != null && value.getClass() == Boolean.class) {
jVal.put("Boolean", value);
} else if (value != null && value.getClass() == Integer.class) {
jVal.put("Number", Map.of("Integer", value));
} else if (value != null
&& (value.getClass() == Float.class || value.getClass() == Double.class)) {
if ((Double) value == Double.POSITIVE_INFINITY) {
jVal.put("Number", Map.of("Float", "Infinity"));
} else if ((Double) value == Double.NEGATIVE_INFINITY) {
jVal.put("Number", Map.of("Float", "-Infinity"));
} else if (Double.isNaN((Double) value)) {
jVal.put("Number", Map.of("Float", "NaN"));
} else {
jVal.put("Number", Map.of("Float", value));
}
} else if (value != null && value.getClass() == String.class) {
jVal.put("String", value);
} else if (value != null && value.getClass().isArray()) {
jVal.put("List", javaArrayToPolar(value));
} else if (value != null && value instanceof List) {
jVal.put("List", javaListToPolar((List) value));
} else if (value != null && value instanceof Map) {
Map valueMap = (Map) value;
HashMap stringMap = new HashMap();
// Polar only supports dictionaries with string keys. Convert a map to a map of
// string keys.
for (Object objectKey : valueMap.keySet()) {
if (!(objectKey instanceof String)) {
throw new Exceptions.UnexpectedPolarTypeError(
"Cannot convert map with non-string keys to Polar");
}
String key = (String) objectKey;
stringMap.put(key, valueMap.get(objectKey));
}
Map jMap = javaMaptoPolar(stringMap);
jVal.put("Dictionary", new JSONObject().put("fields", jMap));
} else if (value != null && value instanceof Predicate) {
Predicate pred = (Predicate) value;
if (pred.args == null) pred.args = new ArrayList();
jVal.put(
"Call", new JSONObject(Map.of("name", pred.name, "args", javaListToPolar(pred.args))));
} else if (value != null && value instanceof Variable) {
jVal.put("Variable", value);
} else if (value != null && value instanceof Expression) {
Expression expression = (Expression) value;
JSONObject expressionJSON = new JSONObject();
expressionJSON.put("operator", expression.getOperator().toString());
expressionJSON.put("args", javaListToPolar(expression.getArgs()));
jVal.put("Expression", expressionJSON);
} else if (value != null && value instanceof Pattern) {
Pattern pattern = (Pattern) value;
if (pattern.getTag() == null) {
jVal.put("Pattern", toPolarTerm(pattern.getFields()));
} else {
JSONObject fieldsJSON = new JSONObject();
fieldsJSON.put("fields", javaMaptoPolar(pattern.getFields()));
JSONObject instanceJSON = new JSONObject();
instanceJSON.put("tag", pattern.getTag());
instanceJSON.put("fields", fieldsJSON);
JSONObject patternJSON = new JSONObject();
patternJSON.put("Instance", instanceJSON);
jVal.put("Pattern", patternJSON);
}
} else {
JSONObject attrs = new JSONObject();
attrs.put("instance_id", cacheInstance(value, null));
attrs.put("repr", value == null ? "null" : value.toString());
jVal.put("ExternalInstance", attrs);
}
// Build Polar term
JSONObject term = new JSONObject();
term.put("id", 0);
term.put("offset", 0);
term.put("value", jVal);
return term;
}
/** Convert a Java List to a JSONified Polar list. */
private List javaListToPolar(List list) throws Exceptions.OsoException {
ArrayList polarList = new ArrayList();
for (Object el : (List) list) {
polarList.add(toPolarTerm(el));
}
return polarList;
}
/** Convert a Java Array to a JSONified Polar list. */
private List javaArrayToPolar(Object array) throws Exceptions.OsoException {
assert (array.getClass().isArray());
List l;
if (array instanceof int[]
|| array instanceof boolean[]
|| array instanceof char[]
|| array instanceof byte[]) {
l = IntStream.of((int[]) array).boxed().collect(Collectors.toList());
} else if (array instanceof float[] || array instanceof double[]) {
l = DoubleStream.of((double[]) array).boxed().collect(Collectors.toList());
} else if (array instanceof Object[]) {
l = Arrays.asList((Object[]) array);
} else {
throw new Exceptions.OsoException(
"Oso does not support arrays of type " + array.getClass().getComponentType().getName());
}
return javaListToPolar(l);
}
/** Convert a Java Map to a JSONified Polar dictionary. */
private Map javaMaptoPolar(Map map)
throws Exceptions.OsoException {
HashMap polarDict = new HashMap();
for (String key : map.keySet()) {
JSONObject val = toPolarTerm(map.get(key));
polarDict.put(key, val);
}
return polarDict;
}
/** Turn a Polar term passed across the FFI boundary into a Java Object. */
public Object toJava(JSONObject term)
throws Exceptions.UnregisteredInstanceError, Exceptions.UnexpectedPolarTypeError,
Exceptions.OsoException {
JSONObject value = term.getJSONObject("value");
String tag = value.keys().next();
switch (tag) {
case "String":
return value.getString(tag);
case "Boolean":
return value.getBoolean(tag);
case "Number":
JSONObject num = value.getJSONObject(tag);
switch (num.keys().next()) {
case "Integer":
return num.getInt("Integer");
case "Float":
Object f = num.get("Float");
if (f instanceof String) {
switch ((String) f) {
case "Infinity":
return Double.POSITIVE_INFINITY;
case "-Infinity":
return Double.NEGATIVE_INFINITY;
case "NaN":
return Double.NaN;
default:
throw new Exceptions.OsoException(
"Expected a floating point number, got \"" + f + "\"");
}
}
return (Double) f;
}
case "List":
return polarListToJava(value.getJSONArray(tag));
case "Dictionary":
return polarDictToJava(value.getJSONObject(tag).getJSONObject("fields"));
case "ExternalInstance":
return getInstance(value.getJSONObject(tag).getLong("instance_id"));
case "Call":
List args = polarListToJava(value.getJSONObject(tag).getJSONArray("args"));
return new Predicate(value.getJSONObject(tag).getString("name"), args);
case "Variable":
return new Variable(value.getString(tag));
case "Expression":
if (!this.acceptExpression) {
throw new Exceptions.UnexpectedPolarTypeError(Exceptions.UNEXPECTED_EXPRESSION_MESSAGE);
}
return new Expression(
value.getJSONObject(tag).getEnum(Operator.class, "operator"),
polarListToJava(value.getJSONObject(tag).getJSONArray("args")));
case "Pattern":
JSONObject pattern = value.getJSONObject("Pattern");
String patternTag = pattern.keys().next();
JSONObject patternValue = pattern.getJSONObject(patternTag);
switch (patternTag) {
case "Instance":
return new Pattern(
patternValue.getString("tag"),
polarDictToJava(patternValue.getJSONObject("fields").getJSONObject("fields")));
case "Dictionary":
return new Pattern(null, polarDictToJava(patternValue));
default:
throw new Exceptions.UnexpectedPolarTypeError("Pattern: " + patternTag);
}
default:
throw new Exceptions.UnexpectedPolarTypeError(tag);
}
}
/** Convert a JSONified Polar dictionary to a Java Map */
public HashMap polarDictToJava(JSONObject dict)
throws Exceptions.UnregisteredInstanceError, Exceptions.UnexpectedPolarTypeError,
Exceptions.OsoException {
HashMap resMap = new HashMap();
for (String key : dict.keySet()) {
resMap.put(key, toJava(dict.getJSONObject(key)));
}
return resMap;
}
/** Convert a JSONified Polar List to a Java List */
public List polarListToJava(JSONArray list)
throws Exceptions.UnregisteredInstanceError, Exceptions.UnexpectedPolarTypeError,
Exceptions.OsoException {
ArrayList resArray = new ArrayList();
for (int i = 0; i < list.length(); i++) {
resArray.add(toJava(list.getJSONObject(i)));
}
return resArray;
}
}