package study.java.hanyx.el.simpleImpl;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
/**
* 简单的表达式引擎
* @author 韩元旭
*/
public class InvokeEL {
/** 编译器 */
private static com.sun.tools.javac.Main JAVAC = new com.sun.tools.javac.Main();
private Map<String, Object> CONTEXT;
/** Debug模式,开启后可以看到每个过程的时间 */
private static boolean isDebug = false;
public static InvokeEL instance = new InvokeEL();
public InvokeEL() {
CONTEXT = new HashMap<String, Object>();
}
public InvokeEL(Map<String, Object> context) {
if (context != null) {
CONTEXT = context;
} else {
CONTEXT = new HashMap<String, Object>();
}
}
/**
* 编译JavaCode,返回临时文件对象
* @param code
* @return 编译失败返回null
* @throws IOException
* @throws Exception
*/
private synchronized static File compile(String code,Map<String, Object> context) throws Exception {
long ioStart = System.currentTimeMillis();
// 在用户当前文件目录创建一个临时代码文件
File file = File.createTempFile("Iel", ".java", new File(System.getProperty("user.dir")));
// 当虚拟机退出时,删除此临时java源文件
file.deleteOnExit();
// 获得文件名和类名字
String fileName = file.getName();
String className = getClassName(fileName);
// 将代码输出到文件
PrintWriter out = new PrintWriter(new FileOutputStream(file));
out.println("public class " + className + " {");
out.println(" public static Object main(String[] args) throws Exception {");
if (context != null && context.size() > 0) {
for (Entry<String, Object> entry: context.entrySet()) {
Object value = entry.getValue();
String key = entry.getKey();
if (value instanceof Double) {
out.println("double " + key + " = " + value + "D;");
} else if (value instanceof Long) {
out.println("long " + key + " = " + value + "L;");
} else if (value instanceof Float) {
out.println("float " + key + " = " + value + "F;");
} else if (value instanceof Integer) {
out.println("int " + key + " = " + value + ";");
} else if (value instanceof Short) {
out.println("short " + key + " = " + value + ";");
} else if (value instanceof Byte) {
out.println("byte " + key + " = " + value + ";");
} else if (value instanceof String) {
out.println("String " + key + " = \"" + value + "\";");
} else if (value instanceof Character) {
out.println("char " + key + " = '" + value + "';");
} else if (value instanceof Boolean) {
out.println("boolean " + key + " = " + value + ";");
}
}
}
out.println(" return (" + code + ");");
out.println(" }");
out.println("}");
// 关闭文件流
out.flush();
out.close();
long ioEnd = System.currentTimeMillis();
if(isDebug) {
System.out.println("生成文件用时:" + (ioEnd-ioStart) + "ms");
}
// 编译代码文件
String[] args = new String[]{"-d", System.getProperty("user.dir"),fileName};
// 返回编译的状态代码
@SuppressWarnings("static-access")
int status = JAVAC.compile(args);
long cEnd = System.currentTimeMillis();
if(isDebug) {
System.out.println("编译文件用时:" + (cEnd-ioEnd) + "ms");
}
// 处理编译状态
return status==0?file:null;
}
/**
* 根据一个java源文件名获得类名
* @param filename
* @return
*/
private static String getClassName(String filename) {
return filename.substring(0, filename.length() - 5);
}
/**
* 执行JavaClass
* @param file
* @return
* @throws Exception
*/
private static synchronized Object run(File file) throws Exception{
long runStart = System.currentTimeMillis();
if (file == null) {
return "Expression Compile Exception";
}
String className = getClassName(file.getName());
// 当虚拟机退出时,删除此临时编译的类文件
File clsFile = new File(file.getParent(), className + ".class");
moveFile(clsFile, className).deleteOnExit();
// 访问这个类
Class<?> cls = Class.forName(className);
// 映射main方法
Method main = cls.getMethod("main", new Class[] { String[].class });
// 执行main方法
Object result = main.invoke(null, new Object[] { new String[0] });
long runEnd = System.currentTimeMillis();
if(isDebug) {
System.out.println("运行文件用时:" + (runEnd-runStart) + "ms");
}
return result;
}
/**
* 移动文件 如果不移动到bin目录下,就会报ClassNotFoundException
* @param file
* @param className
* @return
*/
private static File moveFile(File oldFile, String className) {
String newPath = System.getProperty("user.dir") + "\\bin\\";
//new一个新文件夹
File fnewpath = new File(newPath);
//判断文件夹是否存在
if(!fnewpath.exists()) {
fnewpath.mkdirs();
}
//将文件移到新文件里
File fnew = new File(newPath +oldFile.getName());
oldFile.renameTo(fnew);
return fnew;
}
/**
* 表达式计算
* @param code
* @return
*/
public Object eval(String code) {
try {
return run(compile(code,this.CONTEXT));
} catch (Exception e) {
return e;
}
}
/**
* 上下文存入值
* @param key
* @param value
*/
public InvokeEL push (String key, Object value) {
if (value != null) {
this.CONTEXT.put(key, value);
}
return this;
}
/**
* 清空上下文
*/
public Map<String, Object> clearContext() {
Map<String, Object> map = this.CONTEXT;
this.CONTEXT.clear();
return map;
}
public static void main(String[] args) {
InvokeEL.instance.eval("1000+100.0*99-(600-3*15)/(((68-9)-3)*2-100)+10000%7*71");
}
//File clsFile = new File(file.getParent(), className + ".class");
//com.sun.org.apache.bcel.internal.util.ClassLoader classLoader
// = new com.sun.org.apache.bcel.internal.util.ClassLoader(
// new String[] {file.getParent()});//类根路径
//Class<?> cls = classLoader.loadClass(className);//类名
}