WarpPI/core/src/main/java/it/cavallium/warppi/math/rules/RulesManager.java

265 lines
12 KiB
Java
Raw Normal View History

package it.cavallium.warppi.math.rules;
2017-12-21 23:21:29 +01:00
import java.io.File;
import java.io.FileInputStream;
2017-12-21 23:21:29 +01:00
import java.io.FileNotFoundException;
import java.io.IOException;
2017-12-23 01:14:38 +01:00
import java.io.InputStream;
2018-03-22 20:40:41 +01:00
import java.io.PrintWriter;
2017-12-21 23:21:29 +01:00
import java.net.URISyntaxException;
import java.net.URL;
2018-05-09 22:54:00 +02:00
import java.util.ArrayList;
2017-12-21 23:21:29 +01:00
import java.util.List;
2018-05-09 22:54:00 +02:00
2018-09-04 12:12:41 +02:00
import it.cavallium.warppi.Engine;
import it.cavallium.warppi.Platform.ConsoleUtils;
2018-09-22 11:17:30 +02:00
import it.cavallium.warppi.Platform.StorageUtils;
import it.cavallium.warppi.Platform.URLClassLoader;
import it.cavallium.warppi.StaticVars;
import it.cavallium.warppi.math.Function;
import it.cavallium.warppi.math.MathContext;
import it.cavallium.warppi.math.functions.Expression;
import it.cavallium.warppi.math.functions.Variable;
import it.cavallium.warppi.math.functions.Variable.V_TYPE;
import it.cavallium.warppi.math.solver.MathSolver;
import it.cavallium.warppi.util.Error;
2017-12-21 23:21:29 +01:00
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
public class RulesManager {
2018-05-12 21:18:29 +02:00
2017-12-21 23:21:29 +01:00
public static ObjectArrayList<Rule>[] rules;
2018-05-12 21:18:29 +02:00
private RulesManager() {}
2017-12-21 23:21:29 +01:00
2018-09-22 11:17:30 +02:00
@SuppressWarnings({ "unchecked" })
2017-12-21 23:21:29 +01:00
public static void initialize() {
2018-09-04 12:12:41 +02:00
Engine.getPlatform().getConsoleUtils().out().println(ConsoleUtils.OUTPUTLEVEL_NODEBUG, "RulesManager", "Loading the rules");
2018-09-22 11:17:30 +02:00
RulesManager.rules = new ObjectArrayList[RuleType.values().length];
2018-09-28 11:39:28 +02:00
for (final RuleType val : RuleType.values()) {
2018-09-22 11:17:30 +02:00
RulesManager.rules[val.ordinal()] = new ObjectArrayList<>();
2018-09-28 11:39:28 +02:00
}
2017-12-21 23:21:29 +01:00
try {
2018-03-26 09:01:26 +02:00
boolean compiledSomething = false;
InputStream defaultRulesList;
try {
2018-09-04 12:12:41 +02:00
defaultRulesList = Engine.getPlatform().getStorageUtils().getResourceStream("/default-rules.lst");
2018-09-22 11:17:30 +02:00
} catch (final IOException ex) {
2018-05-09 22:54:00 +02:00
throw new FileNotFoundException("default-rules.lst not found!");
2017-12-21 23:21:29 +01:00
}
2018-05-12 21:18:29 +02:00
final List<String> ruleLines = new ArrayList<>();
2018-09-04 12:12:41 +02:00
final File rulesPath = Engine.getPlatform().getStorageUtils().get("rules/");
2018-09-28 11:39:28 +02:00
if (rulesPath.exists()) {
for (final File f : Engine.getPlatform().getStorageUtils().walk(rulesPath)) {
if (f.toString().endsWith(".java")) {
2018-09-04 12:12:41 +02:00
String path = Engine.getPlatform().getStorageUtils().relativize(rulesPath, f).toString();
path = path.substring(0, path.length() - ".java".length());
ruleLines.add(path);
2018-09-04 12:12:41 +02:00
Engine.getPlatform().getConsoleUtils().out().println(ConsoleUtils.OUTPUTLEVEL_NODEBUG, "RulesManager", "Found external rule: " + f.getAbsolutePath());
}
2018-09-28 11:39:28 +02:00
}
}
2018-09-04 12:12:41 +02:00
ruleLines.addAll(Engine.getPlatform().getStorageUtils().readAllLines(defaultRulesList));
2018-05-12 21:18:29 +02:00
2018-09-04 12:12:41 +02:00
final File tDir = Engine.getPlatform().getStorageUtils().resolve(Engine.getPlatform().getStorageUtils().get(System.getProperty("java.io.tmpdir"), "WarpPi-Calculator"), "rules-rt");
// try {
// final Path defaultResource = Utils.getResource("/math-rules-cache.zip");
// }
InputStream cacheFileStream = null;
File cacheFilePath = null;
cacheFilePath = new File("math-rules-cache.zip");
boolean cacheFileExists = false;
2018-09-28 11:39:28 +02:00
if (Engine.getPlatform().isJavascript()) {
2018-09-04 12:12:41 +02:00
Engine.getPlatform().loadPlatformRules();
2018-09-28 11:39:28 +02:00
} else {
if (cacheFilePath.exists()) {
cacheFileExists = true;
cacheFileStream = new FileInputStream(cacheFilePath);
2018-09-28 11:39:28 +02:00
} else {
try {
2018-09-04 12:12:41 +02:00
cacheFileStream = Engine.getPlatform().getStorageUtils().getResourceStream("/math-rules-cache.zip");//Paths.get(Utils.getJarDirectory().toString()).resolve("math-rules-cache.zip").toAbsolutePath(
org.apache.commons.io.FileUtils.copyInputStreamToFile(cacheFileStream, cacheFilePath);
cacheFileExists = true;
2018-09-22 11:17:30 +02:00
} catch (final IOException ex) { //File does not exists.
2018-03-22 20:40:41 +01:00
}
2018-09-28 11:39:28 +02:00
}
boolean useCache = false;
2018-09-28 11:39:28 +02:00
if (cacheFileExists) {
try {
2018-09-28 11:39:28 +02:00
if (tDir.exists()) {
tDir.delete();
2018-09-28 11:39:28 +02:00
}
2018-09-04 12:12:41 +02:00
Engine.getPlatform().unzip(cacheFilePath.toString(), tDir.getParent().toString(), "");
useCache = !StaticVars.startupArguments.isUncached();
} catch (final Exception ex) {
ex.printStackTrace();
}
2018-09-28 11:39:28 +02:00
}
2018-08-28 02:39:41 +02:00
2018-09-28 11:39:28 +02:00
for (final String rulesLine : ruleLines) {
if (rulesLine.length() > 0) {
final String[] ruleDetails = rulesLine.split(",", 1);
final String ruleName = ruleDetails[0];
final String ruleNameEscaped = ruleName.replace(".", "_");
2018-09-11 01:12:54 +02:00
Engine.getPlatform().getConsoleUtils().out().println(ConsoleUtils.OUTPUTLEVEL_DEBUG_MIN, "RulesManager", "Evaluating /rules/" + ruleNameEscaped + ".java");
final String pathWithoutExtension = "/rules/" + ruleNameEscaped;
final String scriptFile = pathWithoutExtension + ".java";
2018-09-04 12:12:41 +02:00
final InputStream resourcePath = Engine.getPlatform().getStorageUtils().getResourceStream(scriptFile);
2018-09-28 11:39:28 +02:00
if (resourcePath == null) {
System.err.println(new FileNotFoundException("/rules/" + ruleName + ".java not found!"));
2018-09-28 11:39:28 +02:00
} else {
Rule r = null;
2018-09-28 11:39:28 +02:00
if (useCache) {
try {
2018-09-04 12:12:41 +02:00
Engine.getPlatform().getConsoleUtils().out().println(ConsoleUtils.OUTPUTLEVEL_DEBUG_MIN, "RulesManager", ruleName, "Trying to load cached rule");
2018-09-22 11:17:30 +02:00
r = RulesManager.loadClassRuleFromSourceFile(scriptFile, tDir);
2018-09-28 11:39:28 +02:00
if (r != null) {
2018-09-04 12:12:41 +02:00
Engine.getPlatform().getConsoleUtils().out().println(ConsoleUtils.OUTPUTLEVEL_DEBUG_MIN, "RulesManager", ruleName, "Loaded cached rule");
2018-09-28 11:39:28 +02:00
}
} catch (final Exception e) {
e.printStackTrace();
2018-09-22 11:17:30 +02:00
Engine.getPlatform().getConsoleUtils().out().println(ConsoleUtils.OUTPUTLEVEL_NODEBUG, "RulesManager", ruleName, "Can't load the rule " + ruleNameEscaped + "!");
2018-03-22 10:06:31 +01:00
}
2018-09-28 11:39:28 +02:00
}
if (r == null || !useCache) {
2018-09-04 12:12:41 +02:00
Engine.getPlatform().getConsoleUtils().out().println(ConsoleUtils.OUTPUTLEVEL_DEBUG_MIN, "RulesManager", ruleName, "This rule is not cached. Compiling");
try {
2018-09-22 11:17:30 +02:00
r = RulesManager.compileJavaRule(scriptFile, tDir);
compiledSomething = true;
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException | IOException e) {
e.printStackTrace();
}
2018-08-28 02:39:41 +02:00
}
2018-09-28 11:39:28 +02:00
if (r != null) {
RulesManager.addRule(r);
2018-09-28 11:39:28 +02:00
}
}
2017-12-24 11:59:09 +01:00
}
2018-09-28 11:39:28 +02:00
}
2017-12-21 23:21:29 +01:00
}
2018-09-04 12:12:41 +02:00
Engine.getPlatform().getConsoleUtils().out().println(ConsoleUtils.OUTPUTLEVEL_NODEBUG, "RulesManager", "Loaded all the rules successfully");
if (!Engine.getPlatform().isJavascript() && compiledSomething) {
2018-09-28 11:39:28 +02:00
if (cacheFileExists || cacheFilePath.exists()) {
cacheFilePath.delete();
2018-09-28 11:39:28 +02:00
}
2018-09-04 12:12:41 +02:00
Engine.getPlatform().zip(tDir.toString(), cacheFilePath.toString(), "");
Engine.getPlatform().getConsoleUtils().out().println(ConsoleUtils.OUTPUTLEVEL_NODEBUG, "RulesManager", "Cached the compiled rules");
2018-03-26 09:01:26 +02:00
}
2018-09-28 11:39:28 +02:00
if (cacheFileStream != null) {
cacheFileStream.close();
2018-09-28 11:39:28 +02:00
}
2017-12-21 23:21:29 +01:00
} catch (URISyntaxException | IOException e) {
e.printStackTrace();
2018-09-04 12:12:41 +02:00
Engine.getPlatform().exit(1);
2017-12-21 23:21:29 +01:00
}
}
2018-05-12 21:18:29 +02:00
2018-09-22 11:17:30 +02:00
public static Rule compileJavaRule(final String scriptFile, final File tDir) throws IOException, URISyntaxException,
2018-05-12 21:18:29 +02:00
InstantiationException, IllegalAccessException, ClassNotFoundException {
2018-09-04 12:12:41 +02:00
final InputStream resource = Engine.getPlatform().getStorageUtils().getResourceStream(scriptFile);
final String text = Engine.getPlatform().getStorageUtils().read(resource);
final String[] textArray = text.split("\\n", 6);
if (textArray[3].contains("PATH=")) {
final String javaClassDeclaration = textArray[3].substring(6);
int extIndex = javaClassDeclaration.lastIndexOf('.');
final String javaClassNameOnly = javaClassDeclaration.substring(extIndex + 1, javaClassDeclaration.length());
final String javaClassNameAndPath = new StringBuilder("it.cavallium.warppi.math.rules.").append(javaClassDeclaration).toString();
extIndex = javaClassNameAndPath.lastIndexOf('.');
final String javaCode = new StringBuilder("package ").append(javaClassNameAndPath.substring(0, extIndex >= 0 ? extIndex : javaClassNameAndPath.length())).append(";\n").append(textArray[5]).toString();
2018-09-04 12:12:41 +02:00
final File tDirPath = Engine.getPlatform().getStorageUtils().getParent(Engine.getPlatform().getStorageUtils().resolve(tDir, javaClassNameAndPath.replace('.', File.separatorChar)));
final File tFileJava = Engine.getPlatform().getStorageUtils().resolve(tDirPath, javaClassNameOnly + ".java");
final File tFileClass = Engine.getPlatform().getStorageUtils().resolve(tDirPath, javaClassNameOnly + ".class");
2018-09-28 11:39:28 +02:00
if (!tDirPath.exists()) {
2018-09-04 12:12:41 +02:00
Engine.getPlatform().getStorageUtils().createDirectories(tDirPath);
2018-09-28 11:39:28 +02:00
}
if (tFileJava.exists()) {
tFileJava.delete();
2018-09-28 11:39:28 +02:00
}
2018-09-22 11:17:30 +02:00
Engine.getPlatform().getStorageUtils();
Engine.getPlatform().getStorageUtils();
Engine.getPlatform().getStorageUtils().write(tFileJava, javaCode.getBytes("UTF-8"), StorageUtils.OpenOptionWrite, StorageUtils.OpenOptionCreate);
2018-09-04 12:12:41 +02:00
final boolean compiled = Engine.getPlatform().compile(new String[] { "-nowarn", "-1.8", tFileJava.toString() }, new PrintWriter(System.out), new PrintWriter(System.err));
2018-09-28 11:39:28 +02:00
if (StaticVars.startupArguments.isUncached()) {
tFileJava.deleteOnExit();
2018-09-28 11:39:28 +02:00
} else {
tFileJava.delete();
2018-09-28 11:39:28 +02:00
}
if (compiled) {
tFileClass.deleteOnExit();
2018-09-22 11:17:30 +02:00
return RulesManager.loadClassRuleDirectly(javaClassNameAndPath, tDir);
2018-09-28 11:39:28 +02:00
} else {
throw new IOException("Can't build script file '" + scriptFile + "'");
2018-09-28 11:39:28 +02:00
}
} else {
throw new IOException("Can't build script file '" + scriptFile + "', the header is missing or wrong.");
2018-09-28 11:39:28 +02:00
}
2018-03-22 20:40:41 +01:00
}
2018-05-12 21:18:29 +02:00
2018-09-22 11:17:30 +02:00
public static Rule loadClassRuleFromSourceFile(final String scriptFile, final File tDir) throws IOException,
URISyntaxException, InstantiationException, IllegalAccessException, ClassNotFoundException {
2018-09-04 12:12:41 +02:00
final InputStream resource = Engine.getPlatform().getStorageUtils().getResourceStream(scriptFile);
final String text = Engine.getPlatform().getStorageUtils().read(resource);
final String[] textArray = text.split("\\n", 6);
if (textArray[3].contains("PATH=")) {
final String javaClassName = textArray[3].substring(6);
2018-09-11 01:12:54 +02:00
Engine.getPlatform().getConsoleUtils().out().println(ConsoleUtils.OUTPUTLEVEL_DEBUG_VERBOSE, "RulesManager", "Rule java class name: " + javaClassName);
final String javaClassNameAndPath = new StringBuilder("it.cavallium.warppi.math.rules.").append(javaClassName).toString();
try {
2018-09-22 11:17:30 +02:00
return RulesManager.loadClassRuleDirectly(javaClassNameAndPath, tDir);
} catch (final Exception ex) {
ex.printStackTrace();
return null;
}
2018-09-28 11:39:28 +02:00
} else {
throw new IOException("Can't load script file '" + scriptFile + "', the header is missing or wrong.");
2018-09-28 11:39:28 +02:00
}
2018-03-22 20:40:41 +01:00
}
2018-05-12 21:18:29 +02:00
2018-09-22 11:17:30 +02:00
public static Rule loadClassRuleDirectly(final String javaClassNameAndPath, final File tDir) throws IOException,
2018-05-12 21:18:29 +02:00
URISyntaxException, InstantiationException, IllegalAccessException, ClassNotFoundException {
2018-09-04 12:12:41 +02:00
final URLClassLoader cl = Engine.getPlatform().newURLClassLoader(new URL[] { tDir.toURI().toURL() });
2018-05-12 21:18:29 +02:00
final Class<?> aClass = cl.loadClass(javaClassNameAndPath);
2018-03-22 20:40:41 +01:00
cl.close();
return (Rule) aClass.newInstance();
2018-03-22 10:06:31 +01:00
}
2018-05-12 21:18:29 +02:00
public static void warmUp() throws Error, InterruptedException {
2017-12-23 15:20:42 +01:00
ObjectArrayList<Function> uselessResult = null;
boolean uselessVariable = false;
2018-05-12 21:18:29 +02:00
for (final RuleType val : RuleType.values()) {
2018-09-22 11:17:30 +02:00
final ObjectArrayList<Rule> ruleList = RulesManager.rules[val.ordinal()];
2017-12-23 15:20:42 +01:00
for (final Rule rule : ruleList) {
String ruleName = "<null>";
try {
ruleName = rule.getRuleName();
2018-09-22 11:17:30 +02:00
final ObjectArrayList<Function> uselessResult2 = rule.execute(RulesManager.generateUselessExpression());
uselessVariable = (uselessResult == null ? new ObjectArrayList<>() : uselessResult).equals(uselessResult2);
uselessResult = uselessResult2;
2018-05-12 21:18:29 +02:00
} catch (final Exception e) {
if (uselessVariable || true) {
System.err.println("Exception thrown by rule '" + ruleName + "'!");
e.printStackTrace();
}
}
2017-12-23 15:20:42 +01:00
}
}
try {
2018-09-22 11:17:30 +02:00
new MathSolver(RulesManager.generateUselessExpression()).solveAllSteps();
2017-12-23 15:20:42 +01:00
} catch (InterruptedException | Error e) {
e.printStackTrace();
}
}
2018-05-12 21:18:29 +02:00
2017-12-24 11:59:09 +01:00
private static Function generateUselessExpression() {
2018-05-12 21:18:29 +02:00
final MathContext mc = new MathContext();
2017-12-24 11:59:09 +01:00
Function expr = new Expression(mc);
expr = expr.setParameter(0, new Variable(mc, 'x', V_TYPE.VARIABLE));
2017-12-23 15:20:42 +01:00
return expr;
}
2018-05-12 21:18:29 +02:00
2018-09-22 11:17:30 +02:00
public static void addRule(final Rule rule) {
RulesManager.rules[rule.getRuleType().ordinal()].add(rule);
2018-09-11 01:12:54 +02:00
Engine.getPlatform().getConsoleUtils().out().println(ConsoleUtils.OUTPUTLEVEL_DEBUG_MIN, "RulesManager", rule.getRuleName(), "Loaded as " + rule.getRuleType() + " rule");
2017-12-21 23:21:29 +01:00
}
}