package net.ion.craken.script;
import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import net.ion.craken.node.ReadSession;
import net.ion.framework.db.Rows;
import net.ion.framework.util.Debug;
import net.ion.framework.util.FileUtil;
import net.ion.framework.util.ListUtil;
import net.ion.framework.util.MapUtil;
import net.ion.framework.util.StringUtil;
import org.apache.commons.io.DirectoryWalker;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.filefilter.FileFilterUtils;
import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;
import org.apache.commons.io.monitor.FileAlterationObserver;
public class CrakenScript {
private ScriptEngine sengine;
private Map<String, Object> packages = MapUtil.newCaseInsensitiveMap();
private FileAlterationMonitor monitor;
private ScheduledExecutorService ses;
public CrakenScript(ReadSession rsession, ScheduledExecutorService ses) {
ScriptEngineManager manager = new ScriptEngineManager();
this.ses = ses ;
this.sengine = manager.getEngineByName("JavaScript");
sengine.put("session", rsession);
sengine.put("jbuilder", JsonBuilder.instance()) ;
sengine.put("func", new DBFunction());
}
public static CrakenScript create(ReadSession rsession, ScheduledExecutorService ses) {
return new CrakenScript(rsession, ses);
}
public CrakenScript readDir(final File scriptDir) throws IOException {
return readDir(scriptDir, false) ;
}
public CrakenScript readDir(final File scriptDir, boolean reloadWhenDetected) throws IOException {
if (!scriptDir.exists() || !scriptDir.isDirectory())
throw new IllegalArgumentException(scriptDir + " is not directory");
try {
if (this.monitor != null)
this.monitor.stop();
} catch (Exception e) {
throw new IOException(e) ;
}
new DirectoryWalker<String>(FileFilterUtils.suffixFileFilter(".js"), 1) {
protected void handleFile(File file, int dept, Collection<String> results) throws IOException {
String packName = loadPackageScript(file);
results.add(packName);
}
protected boolean handleDirectory(File dir, int depth, Collection results) {
return true;
}
public List<String> loadScript(File scriptDir) throws IOException {
List<String> result = ListUtil.newList();
super.walk(scriptDir, result);
return result;
}
}.loadScript(scriptDir);
if (! reloadWhenDetected) return this ;
FileAlterationObserver observer = new FileAlterationObserver(scriptDir, FileFilterUtils.suffixFileFilter(".js")) ;
observer.addListener(new FileAlterationListenerAdaptor() {
@Override
public void onFileDelete(File file) {
Debug.line("Package Deleted", file);
packages.remove(FilenameUtils.getBaseName(file.getName())) ;
}
@Override
public void onFileCreate(File file) {
Debug.line("Package Created", file);
loadPackageScript(file) ;
}
@Override
public void onFileChange(File file) {
Debug.line("Package Changed", file);
loadPackageScript(file) ;
}
});
try {
observer.initialize();
this.monitor = new FileAlterationMonitor(1000, this.ses, observer) ;
monitor.start();
} catch (Exception e) {
throw new IOException(e) ;
}
return this;
}
private String loadPackageScript(File file) {
try {
String script = FileUtil.readFileToString(file);
String packName = FilenameUtils.getBaseName(file.getName());
packages.put(packName, sengine.eval(script));
return packName;
} catch (IOException e) {
throw new IllegalStateException(e) ;
} catch (ScriptException e) {
throw new IllegalStateException(e) ;
}
}
public Map<String, Object> packages() {
return Collections.unmodifiableMap(packages);
}
public Rows execQuery(String uptName, Object... params) throws SQLException {
Object result = callFn(uptName, params);
if (Rows.class.isInstance(result))
return (Rows) result;
throw new IllegalStateException("illegal return type");
}
public Object callFn(String uptName, Object... params) throws SQLException{
try {
String packName = StringUtil.substringBefore(uptName, "@");
String fnName = StringUtil.substringAfter(uptName, "@");
Object pack = packages.get(packName);
if (pack == null)
throw new SQLException("not found package");
Object result = ((Invocable) sengine).invokeMethod(pack, fnName, params);
return result;
} catch (ScriptException e) {
throw new SQLException(e);
} catch (NoSuchMethodException e) {
throw new SQLException(e);
}
}
public int execUpdate(String uptName, Object... params) throws SQLException{
Object result = callFn(uptName, params);
if (result == null) return 0 ;
if (Integer.class.isInstance(result)) return (Integer) result ;
if (Double.class.isInstance(result)) return ((Double)result).intValue() ;
throw new IllegalStateException("illegal return type");
}
}