package com.smtscript.run; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.PrintStream; import java.io.PrintWriter; import java.io.StringWriter; import java.lang.reflect.Field; import java.util.Date; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import java.util.Scanner; import java.util.regex.Pattern; import org.mozilla.javascript.Context; import org.mozilla.javascript.ImporterTopLevel; import org.mozilla.javascript.NativeArray; import org.mozilla.javascript.NativeObject; import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.ScriptableObject; import org.mozilla.javascript.Undefined; import org.mozilla.javascript.Wrapper; import com.smtscript.lib.JSComment; import com.smtscript.lib.JSStaticCSV; import com.smtscript.lib.JSStaticCounter; import com.smtscript.lib.JSStaticDate; import com.smtscript.lib.JSStaticExcel; import com.smtscript.lib.JSStaticFile; import com.smtscript.lib.JSStaticHttp; import com.smtscript.lib.JSStaticJDBC; import com.smtscript.lib.JSStaticKCSV; import com.smtscript.lib.JSStaticKettle; import com.smtscript.lib.JSStaticLineFile; import com.smtscript.lib.JSStaticProperties; import com.smtscript.lib.JSStaticRegex; import com.smtscript.lib.JSStaticRobot; import com.smtscript.lib.JSStaticSQLFile; import com.smtscript.lib.JSStaticShell; import com.smtscript.lib.JSStaticSocket; import com.smtscript.lib.JSStaticString; import com.smtscript.lib.JSStaticSystem; import com.smtscript.lib.JSStaticThreadPool; import com.smtscript.lib.JSStaticXml; import com.smtscript.lib.JSStaticYML; import com.smtscript.lib.JSStaticZip; import com.smtscript.lib.ScriptRunLibInf; import com.smtscript.utils.Json; import com.smtscript.utils.SMTStatic; public class ScriptRunScope extends ImporterTopLevel { public abstract static class FileInfo { public abstract String getShortName(); public abstract String getName(); public abstract InputStream open() throws Exception; public abstract void close() throws Exception; public abstract String getPath() throws Exception; public abstract FileInfo findSbilingFileInfo(String fileName, boolean throwErr) throws Exception; @Override public String toString(){ return getName(); } } public static class FileInfoRes extends FileInfo { protected String _resName; protected InputStream _resStream; public FileInfoRes(String resName, InputStream resStream) { _resName = resName; _resStream = resStream; } @Override public String getName() { return "*" + _resName; } @Override public InputStream open() throws Exception { if(_resStream == null) _resStream = ClassLoader.getSystemResourceAsStream(_resName); return _resStream; } @Override public void close() throws Exception { if(_resStream != null) { _resStream.close(); _resStream = null; } } @Override public FileInfo findSbilingFileInfo(String fileName, boolean throwErr) throws Exception { String resPath; int pos = _resName.lastIndexOf("/"); if(pos >= 0) resPath = _resName.substring(0, pos + 1); else resPath = ""; InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream(resPath + fileName); if(is == null) { if(throwErr) throw new Exception("can't find res : " + fileName); return null; } return new FileInfoRes(resPath + fileName, is); } @Override public String getShortName() { int pos = _resName.lastIndexOf("/"); if(pos >= 0) return _resName.substring(pos + 1); else return _resName; } @Override public String getPath() throws Exception { int pos = _resName.lastIndexOf("/"); if(pos >= 0) return "*" + _resName.substring(0, pos); else return "*"; } } public static class FileInfoFile extends FileInfo { protected File _file; protected InputStream _stream; public FileInfoFile(File file) { _file = file; } public File getFileName() { return _file; } @Override public InputStream open() throws Exception { if(_stream == null) _stream = new FileInputStream(_file); return _stream; } @Override public void close() throws Exception { if(_stream != null) { _stream.close(); _stream = null; } } @Override public String getName() { return _file.getAbsolutePath(); } @Override public FileInfo findSbilingFileInfo(String fileName, boolean throwErr) throws Exception { File fileNew = new File(SMTStatic.getFilePath(_file), fileName); if(!fileNew.exists()) { if(throwErr) throw new Exception("can't find sbling file " + fileName + " at " + this.getName()); return null; } return new FileInfoFile(fileNew); } @Override public String getShortName() { return _file.getName(); } @Override public String getPath() throws Exception { return SMTStatic.getFilePath(_file).getCanonicalPath() + "/"; } } protected static class StaticVarb { public ScriptRunScope _scope; public Object[] _args; public Class _clzDef; public ScriptRunLibInf _instance; public StaticVarb(ScriptRunScope scope, Class clzDef, Object[] args) { _clzDef = clzDef; _args = args; _instance = null; _scope = scope; } public Object getInstance() throws Exception { if(_instance == null) { _instance = (ScriptRunLibInf) _clzDef. newInstance(); _instance.__init__(_scope, _args); } return _instance; } public void exitInstance() throws Exception { if(_instance != null) { _instance.__exit__(); _instance = null; } } } public JSStaticString Str; public JSStaticFile File; public JSStaticExcel Excel; public JSStaticRegex Regex; public JSStaticHttp Http; public JSStaticZip Zip; public JSStaticThreadPool ThreadPool; public JSStaticProperties PropModify; public JSStaticDate DateTime; public JSStaticRobot Robot; public JSStaticSocket Socket; public JSStaticXml Xml; public JSStaticShell Shell; public JSStaticKCSV KCSV; public JSStaticJDBC JDBC; public JSStaticSystem Sys; public JSStaticCSV CSV; public JSStaticYML YmlModify; public JSStaticCounter Counter; public JSStaticKettle Kettle; public JSStaticLineFile LineFile; public JSStaticSQLFile SQLFile; protected ScriptRuntime _runtime; protected File _libPath; protected LinkedList _srcFileStack = new LinkedList(); protected Map _mapId2StaticVarb = new HashMap(); public ScriptRunScope Global; public NativeArray GlobalArgs; protected void initialStaticVarbs() throws Exception { for(Field field : this.getClass().getFields()) { if(!ScriptRunLibInf.class.isAssignableFrom(field.getType())) continue; newStaticVarb(field.getName(), field.getType(), null); } } protected void newStaticVarb(String id, Class clzObj, Object[] args) throws Exception { _mapId2StaticVarb.put(id, new StaticVarb(this, clzObj, args)); } public void pushSrcFileName(FileInfo file) { _srcFileStack.push(file); } public void popSrcFileName() { _srcFileStack.pop(); } @Override public Object get(String name, Scriptable start) { StaticVarb varb; if((varb = _mapId2StaticVarb.get(name)) != null && !this.has(name, start)) { try { defineProperty(name, varb.getInstance(), ScriptableObject.READONLY); } catch(Exception ex) { throw new RuntimeException(ex); } } return super.get(name, start); } public Object getStaticVarb(String varbName) throws Exception { StaticVarb varb = _mapId2StaticVarb.get(varbName); if(varb == null) throw new Exception("can't get static varb : " + varbName); return varb.getInstance(); } public void __exit__() throws Exception { for(StaticVarb varb : _mapId2StaticVarb.values()) { varb.exitInstance(); } } public File __libPath__() { return this._libPath; } public void __arguments__(String[] args) { GlobalArgs = new NativeArray(args); } public void __init__(ScriptRuntime runtime, Context cx) throws Exception { _runtime = runtime; ClassLoader sysClzLoader = ClassLoader.getSystemClassLoader(); Class clz = null; try { clz = Class.forName("com.smtscript.run.ScriptRuntime", false, sysClzLoader); } catch(ClassNotFoundException ex) { try { clz = Class.forName("org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader", false, sysClzLoader); } catch(ClassNotFoundException ex1) { clz = null; } } if(clz != null) { File file = new File(clz.getProtectionDomain().getCodeSource().getLocation().getPath()); String name = file.getName(); String sFile = file.getCanonicalPath(); _libPath = new File(sFile.substring(0, sFile.length() - name.length())); } // Define some global functions particular to the shell. Note // that these functions are not part of ECMA. initStandardObjects(cx, false); initialStaticVarbs(); String[] funcListArr = new String[]{ "print", "println", "evalString", "evalFile", "convString", "initLog4jConfig", "importGlobal", "toInt", "toDate", "createUUID", "createStringBuilder", "getTopCodeFile", "getCurCodeFile", "sleep", "currentTimeMillis", "getCurCodePath", "getTopCodePath", "findExistFile", "typeOf", "evalNamedString", "toJson", "setCurrentPath", "getCurrentPath", "throwException", }; defineRunFunctions(ScriptRunScope.class, funcListArr); defineProperty("GlobalArgs", GlobalArgs, ScriptableObject.READONLY); defineProperty("Global", this, ScriptableObject.READONLY); } public String readConsole() { @SuppressWarnings("resource") Scanner scaner = new Scanner(System.in); return scaner.nextLine(); } public ScriptRuntime __runtime__() { return _runtime; } protected void defineRunFunctions(Class clz, String[] names) { defineFunctionProperties(names, clz, ScriptableObject.DONTENUM); } public void setCurrentPath(String filePath) throws Exception { File path = new File(filePath); if(!path.exists() || !path.isDirectory()) throw new Exception("file path is not exist or file : " + path.getAbsolutePath()); System.setProperty("user.dir", path.getAbsolutePath()); } public String getCurrentPath() { return System.getProperty("user.dir"); } public String findExistFile(String fileName, boolean throwErr) throws Exception { FileInfo fileInfo = __findExistFile__(fileName, throwErr); if(fileInfo == null) return null; return fileInfo.getName(); } public FileInfo __findExistFile__(String fileName, boolean throwErr) throws Exception { if(fileName.length() == 0) { if(throwErr) throw new Exception("file name is empty"); return null; } // 如果当前文件名是资源,则直接作为资源打开 if(fileName.charAt(0) == '*') { fileName = fileName.substring(1); InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream(fileName.substring(1)); if(is == null) { if(throwErr) throw new Exception("can't find resource : " + fileName); return null; } return new FileInfoRes(fileName, is); } File file = new File(fileName); // 如果当前目录存在指定文件,则直接返回 if(file.exists()) return new FileInfoFile(file); // 如果文件不存在,且指定了绝对路径,则返回null if(file.isAbsolute()) { if(throwErr) throw new Exception("can't find file : " + fileName); return null; } // 如果当前文件属于嵌套文件,则以嵌套的文件为根目录检索 FileInfo fileInfo; if(_srcFileStack.size() > 1) { fileInfo = _srcFileStack.peekLast(); fileInfo = fileInfo.findSbilingFileInfo(fileName, false); if(fileInfo != null) return fileInfo; } // 将根脚本路径作为根目录检索 fileInfo = _srcFileStack.peekFirst(); fileInfo = fileInfo.findSbilingFileInfo(fileName, false); if(fileInfo != null) return fileInfo; // 将jar包路径作为根目录检索 file = new File(_libPath, fileName); if(file.exists()) return new FileInfoFile(file); if(throwErr) throw new Exception("can't find file : " + fileName); return null; } public String typeOf(Object obj) { if(obj == null) return "NULL"; return obj.getClass().getSimpleName(); } protected void outputString(String out) { System.out.print(out); } public void print(Object out) throws Exception { if(!(out instanceof String)) out = convString(out); outputString(out.toString()); } public void println(Object out) throws Exception { if(!(out instanceof String)) out = convString(out); outputString(out.toString() + "\n"); } public String convString(Object value) throws Exception { return SMTStatic.convJSString(value); } public Object evalString(String code) { return _runtime.evalString("#eval", code, 1); } public Object evalNamedString(String code, String name, boolean catchFull) throws Exception { try { return _runtime.evalString(name, code, 1); } catch(Exception ex) { ByteArrayOutputStream byteOS = new ByteArrayOutputStream(); PrintStream ps = new PrintStream(byteOS); ex.printStackTrace(ps); String errMsg = new String(byteOS.toByteArray()); throw new Exception(errMsg); } } public Object evalFile(String fileName) throws Exception { FileInfo file = __findExistFile__(fileName, true); String code = SMTStatic.readTextStream(file.open(), "UTF-8"); return _runtime.evalFile(file, code, 1); } public Pattern createRegex(String regex, String option) { return Pattern.compile(regex); } @JSComment( "
\n" +
    	"   propFile == null : no any log\n" +
    	"   propFile       : String: prop file name\n" + 
    	"   propFile       : {}=>\n" +
    	"       level      : log level\n" +
    	"       stdout     : output stdout\n" +
    	"       file       : {}=>\n" +
    	"          pattern : pattern(default)" +
    	"          name    : log file name\n" +
    	"
" ) public void initLog4jConfig(Object propFile) throws Exception { if(propFile != null && propFile instanceof Wrapper) { propFile = ((Wrapper)propFile).unwrap(); } if(propFile == null || propFile instanceof Undefined) { Properties prop = new Properties(); InputStream is = ScriptRunScope.class.getResourceAsStream("/script/log4j_off.properties"); prop.load(is); initLog4jConfig(prop); } else if(propFile instanceof NativeObject) { NativeObject propObj = (NativeObject)propFile; Properties prop = new Properties(); String level = (String) SMTStatic.getJSValue(propObj, "level", "all"); String pattern = (String) SMTStatic.getJSValue(propObj, "pattern", "%p %d{yyyy-MM-dd HH:mm:ss} %-50.50c(%L) - %m%n"); if(propObj.has("stdout", propObj)) { level += ", stdout"; prop.setProperty("log4j.appender.stdout", "org.apache.log4j.ConsoleAppender"); prop.setProperty("log4j.appender.stdout.Target", "System.out"); prop.setProperty("log4j.appender.stdout.layout", "org.apache.log4j.PatternLayout"); prop.setProperty("log4j.appender.stdout.layout.ConversionPattern", "%d{ABSOLUTE} %5p %c{1}:%L - %m%n"); } if(propObj.has("file", propObj)) { NativeObject nvLogFile = (NativeObject) propObj.get("file"); level += ", DAILY_ALL"; prop.setProperty("log4j.appender.DAILY_ALL", "org.apache.log4j.DailyRollingFileAppender"); prop.setProperty("log4j.appender.DAILY_ALL.Encoding", "UTF-8"); prop.setProperty("log4j.appender.DAILY_ALL.layout", "org.apache.log4j.PatternLayout"); prop.setProperty("log4j.appender.DAILY_ALL.layout.ConversionPattern", pattern); prop.setProperty("log4j.appender.DAILY_ALL.File", (String)SMTStatic.getJSValue(nvLogFile, "name")); } prop.setProperty("log4j.rootLogger", level); doInitLog4jConfig(prop); } else if(propFile instanceof String) { doInitLog4jConfig((String)propFile); } else { throw new Exception("unsupport type : " + propFile.getClass().getName()); } } protected void doInitLog4jConfig(Object prop) throws Exception { Class cls = Class.forName("org.apache.log4j.PropertyConfigurator"); cls.getDeclaredMethod("configure", prop.getClass()).invoke(null, new Object[]{prop}); } public NativeObject mergeObject(NativeArray arr) { NativeObject ret = new NativeObject(); int size = arr.size(); for(int i = 0; i < size; i ++) { NativeObject src = (NativeObject) arr.get(i); for(Entry entry : src.entrySet()) { ret.put((String)entry.getKey(), ret, entry.getValue()); } } return ret; } public int toInt(Object value) { return SMTStatic.toInt(value); } public Date toDate(Object value) { return SMTStatic.toDate(value); } public String createUUID() { return SMTStatic.newUUID(); } public String createSequence() { return SMTStatic.newSequence(); } public StringBuilder createStringBuilder() { return new StringBuilder(); } public void sleep(int time) throws Exception { Thread.sleep(time); } public long currentTimeMillis() { return System.currentTimeMillis(); } public void importGlobal(String global) { } public String getCurCodePath() throws Exception { if(_srcFileStack.size() == 0) return null; return _srcFileStack.peek().getPath(); } public String getTopCodePath() throws Exception { if(_srcFileStack.size() == 0) return null; return _srcFileStack.peekFirst().getPath(); } public String getCurCodeFile() { if(_srcFileStack.size() == 0) return null; return _srcFileStack.peek().getName(); } public String getTopCodeFile() { if(_srcFileStack.size() == 0) return null; return _srcFileStack.peekFirst().getName(); } public Object toJson(String jsonStr) throws Exception { Json json = Json.read(jsonStr); Object ret = SMTStatic.convJsonToJS(json); return ret; } public void execJSFile(String fileName, NativeObject nvObject, NativeArray nvMapProp) throws Exception { try { fileName = this.getCurCodePath() + fileName; // 如果不存在映射表,则直接设置 if(nvMapProp == null) { for(Entry entry : nvObject.entrySet()) { String key = (String) SMTStatic.unwrapObject(entry.getKey()); String value = (String) SMTStatic.unwrapObject(entry.getValue()); System.setProperty(key, value); } } // 如果存在映射表,则根据映射表获取数据 else { for(int i = 0; i < nvMapProp.size(); i ++) { Object oMap = SMTStatic.unwrapObject(nvMapProp.get(i)); if(oMap instanceof String) { String key = (String)oMap; String value = SMTStatic.getJSValue(nvObject, key).toString();; System.setProperty(key, value); } else if(oMap instanceof NativeObject) { String inkey = (String) SMTStatic.getJSValue((NativeObject)oMap, "inkey"); String outkey = (String) SMTStatic.getJSValue((NativeObject)oMap, "outkey", inkey); boolean need = (Boolean) SMTStatic.getJSValue((NativeObject)oMap, "need", true); //boolean hide = (Boolean) SMTStatic.getJSValue((NativeObject)oMap, "hide", false); String value = (String)SMTStatic.getJSValue(nvObject, inkey, null); if(value == null) { if(need) throw new Exception("can't find key : " + inkey); else System.setProperty(outkey, null); } else { System.setProperty(outkey, value); } } } } File file = new File(fileName); ScriptRuntime runtime = newScriptRuntime(); runtime.getGlobalScope().pushSrcFileName(new ScriptRunScope.FileInfoFile(file)); runtime.evalScriptFile(file); runtime.callScriptFunction("main", new Object[0]); runtime.getGlobalScope().popSrcFileName(); } finally { } } protected ScriptRuntime newScriptRuntime() throws Exception { ScriptRuntime runtime = ScriptRuntime.newScriptRuntime(null, newScriptRunScope(), null); return runtime; } protected ScriptRunScope newScriptRunScope() { return new ScriptRunScope(); } public void throwException(Object value) throws Throwable { if(value == null) return; if("org.mozilla.javascript.NativeError".equals(value.getClass().getName())) { Field field = value.getClass().getDeclaredField("stackProvider"); field.setAccessible(true); Object oo = field.get(value); if(oo != null && oo instanceof Throwable) { StringWriter sr = new StringWriter(); PrintWriter out = new PrintWriter(sr); ((Throwable)oo).printStackTrace(out); throw new Exception(sr.toString()); } } else if(value instanceof Throwable) { throw (Throwable)value; } else { throw new Exception(value.toString()); } } }