2018-09-02 13:36:49 +02:00
package it.cavallium.warppi.math.rules ;
2017-12-21 23:21:29 +01:00
import java.io.File ;
2018-06-11 22:41:11 +02:00
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-09-04 12:12:41 +02:00
import java.util.zip.ZipFile ;
2018-05-09 22:54:00 +02:00
2018-09-04 12:12:41 +02:00
import it.cavallium.warppi.Engine ;
2018-09-02 13:36:49 +02:00
import it.cavallium.warppi.Error ;
import it.cavallium.warppi.StaticVars ;
2018-09-04 12:12:41 +02:00
import it.cavallium.warppi.deps.Platform.ConsoleUtils ;
import it.cavallium.warppi.deps.Platform.URLClassLoader ;
2018-09-02 13:36:49 +02:00
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 ;
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-02 13:39:22 +02:00
@SuppressWarnings ( { " unchecked " , " unused " } )
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 " ) ;
2017-12-21 23:21:29 +01:00
rules = new ObjectArrayList [ RuleType . values ( ) . length ] ;
2018-05-12 21:18:29 +02:00
for ( final RuleType val : RuleType . values ( ) ) {
rules [ val . ordinal ( ) ] = new ObjectArrayList < > ( ) ;
2017-12-21 23:21:29 +01:00
}
try {
2018-03-26 09:01:26 +02:00
boolean compiledSomething = false ;
2018-06-11 22:41:11 +02:00
InputStream defaultRulesList ;
try {
2018-09-04 12:12:41 +02:00
defaultRulesList = Engine . getPlatform ( ) . getStorageUtils ( ) . getResourceStream ( " /default-rules.lst " ) ;
2018-06-11 22:41:11 +02:00
} catch ( 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-06-11 22:41:11 +02:00
if ( rulesPath . exists ( ) ) {
2018-09-04 12:12:41 +02:00
for ( File f : Engine . getPlatform ( ) . getStorageUtils ( ) . walk ( rulesPath ) ) {
2018-06-11 22:41:11 +02:00
if ( f . toString ( ) . endsWith ( " .java " ) ) {
2018-09-04 12:12:41 +02:00
String path = Engine . getPlatform ( ) . getStorageUtils ( ) . relativize ( rulesPath , f ) . toString ( ) ;
2018-06-11 22:41:11 +02:00
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-06-11 22:41:11 +02:00
}
2018-05-12 21:18:29 +02:00
}
2018-05-09 22:54:00 +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 " ) ;
2018-06-11 22:41:11 +02:00
// 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-04 12:12:41 +02:00
if ( Engine . getPlatform ( ) . isJavascript ( ) ) {
Engine . getPlatform ( ) . loadPlatformRules ( ) ;
2018-06-11 22:41:11 +02:00
} else {
if ( cacheFilePath . exists ( ) ) {
cacheFileExists = true ;
cacheFileStream = new FileInputStream ( cacheFilePath ) ;
} 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(
2018-06-11 22:41:11 +02:00
org . apache . commons . io . FileUtils . copyInputStreamToFile ( cacheFileStream , cacheFilePath ) ;
cacheFileExists = true ;
} catch ( IOException ex ) { //File does not exists.
2018-03-22 20:40:41 +01:00
}
}
2018-06-11 22:41:11 +02:00
boolean useCache = false ;
if ( cacheFileExists ) {
try {
if ( tDir . exists ( ) ) {
tDir . delete ( ) ;
}
2018-09-04 12:12:41 +02:00
Engine . getPlatform ( ) . unzip ( cacheFilePath . toString ( ) , tDir . getParent ( ) . toString ( ) , " " ) ;
2018-08-28 02:38:27 +02:00
useCache = ! StaticVars . startupArguments . isUncached ( ) ;
2018-06-11 22:41:11 +02:00
} catch ( final Exception ex ) {
ex . printStackTrace ( ) ;
}
}
2018-08-28 02:39:41 +02:00
2018-06-11 22:41:11 +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 " ) ;
2018-06-11 22:41:11 +02:00
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-06-11 22:41:11 +02:00
if ( resourcePath = = null ) {
System . err . println ( new FileNotFoundException ( " /rules/ " + ruleName + " .java not found! " ) ) ;
} else {
Rule r = null ;
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-06-11 22:41:11 +02:00
r = loadClassRuleFromSourceFile ( scriptFile , tDir ) ;
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-06-11 22:41:11 +02:00
}
} catch ( final Exception e ) {
e . printStackTrace ( ) ;
2018-09-11 01:12:54 +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-06-11 22:41:11 +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 " ) ;
2018-06-11 22:41:11 +02:00
try {
r = compileJavaRule ( scriptFile , tDir ) ;
compiledSomething = true ;
} catch ( InstantiationException | IllegalAccessException | ClassNotFoundException | IOException e ) {
e . printStackTrace ( ) ;
}
2018-08-28 02:39:41 +02:00
2018-06-11 22:41:11 +02:00
}
if ( r ! = null ) {
RulesManager . addRule ( r ) ;
2018-03-22 10:06:31 +01:00
}
2018-03-24 23:33:04 +01:00
}
2017-12-24 11:59:09 +01: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-06-11 22:41:11 +02:00
if ( cacheFileExists | | cacheFilePath . exists ( ) ) {
cacheFilePath . delete ( ) ;
2018-05-09 22:30:15 +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-06-11 22:41:11 +02:00
if ( cacheFileStream ! = null ) {
cacheFileStream . close ( ) ;
}
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-06-11 22:41:11 +02:00
public static Rule compileJavaRule ( String scriptFile , 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 ) ;
2018-06-11 22:41:11 +02:00
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 ( ) ) ;
2018-09-02 13:36:49 +02:00
final String javaClassNameAndPath = new StringBuilder ( " it.cavallium.warppi.math.rules. " ) . append ( javaClassDeclaration ) . toString ( ) ;
2018-06-11 22:41:11 +02:00
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-06-11 22:41:11 +02:00
if ( ! tDirPath . exists ( ) ) {
2018-09-04 12:12:41 +02:00
Engine . getPlatform ( ) . getStorageUtils ( ) . createDirectories ( tDirPath ) ;
2018-06-11 22:41:11 +02:00
}
if ( tFileJava . exists ( ) ) {
tFileJava . delete ( ) ;
}
2018-09-04 12:12:41 +02:00
Engine . getPlatform ( ) . getStorageUtils ( ) . write ( tFileJava , javaCode . getBytes ( " UTF-8 " ) , Engine . getPlatform ( ) . getStorageUtils ( ) . OpenOptionWrite , Engine . getPlatform ( ) . getStorageUtils ( ) . OpenOptionCreate ) ;
final boolean compiled = Engine . getPlatform ( ) . compile ( new String [ ] { " -nowarn " , " -1.8 " , tFileJava . toString ( ) } , new PrintWriter ( System . out ) , new PrintWriter ( System . err ) ) ;
2018-08-28 02:38:27 +02:00
if ( StaticVars . startupArguments . isUncached ( ) ) {
2018-06-11 22:41:11 +02:00
tFileJava . deleteOnExit ( ) ;
} else {
tFileJava . delete ( ) ;
}
if ( compiled ) {
tFileClass . deleteOnExit ( ) ;
return loadClassRuleDirectly ( javaClassNameAndPath , tDir ) ;
} else {
throw new IOException ( " Can't build script file ' " + scriptFile + " ' " ) ;
}
2018-03-22 20:40:41 +01:00
} else {
2018-06-11 22:41:11 +02:00
throw new IOException ( " Can't build script file ' " + scriptFile + " ', the header is missing or wrong. " ) ;
2018-03-22 20:40:41 +01:00
}
}
2018-05-12 21:18:29 +02:00
2018-06-11 22:41:11 +02:00
public static Rule loadClassRuleFromSourceFile ( String scriptFile , 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 ) ;
2018-06-11 22:41:11 +02:00
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 ) ;
2018-09-02 13:36:49 +02:00
final String javaClassNameAndPath = new StringBuilder ( " it.cavallium.warppi.math.rules. " ) . append ( javaClassName ) . toString ( ) ;
2018-06-11 22:41:11 +02:00
try {
return loadClassRuleDirectly ( javaClassNameAndPath , tDir ) ;
} catch ( final Exception ex ) {
ex . printStackTrace ( ) ;
return null ;
}
} else {
throw new IOException ( " Can't load script file ' " + scriptFile + " ', the header is missing or wrong. " ) ;
2018-03-22 20:40:41 +01:00
}
}
2018-05-12 21:18:29 +02:00
2018-06-11 22:41:11 +02:00
public static Rule loadClassRuleDirectly ( String javaClassNameAndPath , 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
2018-03-25 12:36:22 +02:00
public static void warmUp ( ) throws Error , InterruptedException {
2017-12-23 15:20:42 +01:00
ObjectArrayList < Function > uselessResult = null ;
2018-02-05 00:05:31 +01:00
boolean uselessVariable = false ;
2018-05-12 21:18:29 +02:00
for ( final RuleType val : RuleType . values ( ) ) {
2017-12-23 15:20:42 +01:00
final ObjectArrayList < Rule > ruleList = rules [ val . ordinal ( ) ] ;
for ( final Rule rule : ruleList ) {
2018-02-05 00:05:31 +01:00
String ruleName = " <null> " ;
try {
ruleName = rule . getRuleName ( ) ;
2018-05-12 21:18:29 +02:00
final ObjectArrayList < Function > uselessResult2 = rule . execute ( generateUselessExpression ( ) ) ;
2018-02-05 00:05:31 +01:00
uselessVariable = ( uselessResult = = null ? new ObjectArrayList < > ( ) : uselessResult ) . equals ( uselessResult2 ) ;
uselessResult = uselessResult2 ;
2018-05-12 21:18:29 +02:00
} catch ( final Exception e ) {
2018-02-05 00:05:31 +01:00
if ( uselessVariable | | true ) {
System . err . println ( " Exception thrown by rule ' " + ruleName + " '! " ) ;
e . printStackTrace ( ) ;
}
}
2017-12-23 15:20:42 +01:00
}
}
try {
new MathSolver ( generateUselessExpression ( ) ) . solveAllSteps ( ) ;
} 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
2017-12-21 23:21:29 +01:00
public static void addRule ( Rule rule ) {
2017-12-22 22:39:58 +01:00
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
}
}