参数返回值
9 | * @param 参数类型
10 | */
11 | public interface Callable {
12 |
13 | R call(P... arg);
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/com/greenpineyu/fel/common/Null.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.common;
2 |
3 | /**
4 | * 用于表示Null值
5 | * @author yuqingsong
6 | *
7 | */
8 | public class Null {
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/src/com/greenpineyu/fel/common/ObjectUtils.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.common;
2 |
3 |
4 | public class ObjectUtils {
5 | /**
6 | * Compares two objects for equality, where either one or both
7 | * objects may be {@code null}.
8 | *
9 | *
10 | * ObjectUtils.equals(null, null) = true
11 | * ObjectUtils.equals(null, "") = false
12 | * ObjectUtils.equals("", null) = false
13 | * ObjectUtils.equals("", "") = true
14 | * ObjectUtils.equals(Boolean.TRUE, null) = false
15 | * ObjectUtils.equals(Boolean.TRUE, "true") = false
16 | * ObjectUtils.equals(Boolean.TRUE, Boolean.TRUE) = true
17 | * ObjectUtils.equals(Boolean.TRUE, Boolean.FALSE) = false
18 | *
19 | *
20 | * @param object1 the first object, may be {@code null}
21 | * @param object2 the second object, may be {@code null}
22 | * @return {@code true} if the values of both objects are the same
23 | */
24 | public static boolean equals(Object object1, Object object2) {
25 | if (object1 == object2) {
26 | return true;
27 | }
28 | if ((object1 == null) || (object2 == null)) {
29 | return false;
30 | }
31 | return object1.equals(object2);
32 | }
33 |
34 | /**
35 | * Gets the {@code toString} of an {@code Object} returning
36 | * an empty string ("") if {@code null} input.
37 | *
38 | *
39 | * ObjectUtils.toString(null) = ""
40 | * ObjectUtils.toString("") = ""
41 | * ObjectUtils.toString("bat") = "bat"
42 | * ObjectUtils.toString(Boolean.TRUE) = "true"
43 | *
44 | *
45 | * @see StringUtils#defaultString(String)
46 | * @see String#valueOf(Object)
47 | * @param obj the Object to {@code toString}, may be null
48 | * @return the passed in Object's toString, or nullStr if {@code null} input
49 | * @since 2.0
50 | */
51 | public static String toString(Object obj) {
52 | return obj == null ? "" : obj.toString();
53 | }
54 |
55 | /**
56 | * Compares two objects for inequality, where either one or both
57 | * objects may be {@code null}.
58 | *
59 | *
60 | * ObjectUtils.notEqual(null, null) = false
61 | * ObjectUtils.notEqual(null, "") = true
62 | * ObjectUtils.notEqual("", null) = true
63 | * ObjectUtils.notEqual("", "") = false
64 | * ObjectUtils.notEqual(Boolean.TRUE, null) = true
65 | * ObjectUtils.notEqual(Boolean.TRUE, "true") = true
66 | * ObjectUtils.notEqual(Boolean.TRUE, Boolean.TRUE) = false
67 | * ObjectUtils.notEqual(Boolean.TRUE, Boolean.FALSE) = true
68 | *
69 | *
70 | * @param object1 the first object, may be {@code null}
71 | * @param object2 the second object, may be {@code null}
72 | * @return {@code false} if the values of both objects are the same
73 | */
74 | public static boolean notEqual(Object object1, Object object2) {
75 | return ObjectUtils.equals(object1, object2) == false;
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/com/greenpineyu/fel/common/ReflectUtil.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.common;
2 |
3 | import java.lang.reflect.Method;
4 | import java.util.HashMap;
5 | import java.util.Map;
6 |
7 | public class ReflectUtil {
8 |
9 | /**
10 | * key为基本类型及其包装类型,value为包装类型
11 | */
12 | static final Map,Class>> wrapperCls;
13 | /**
14 | * key为基本类型及其包装类型,value为基本类型
15 | */
16 | static final Map,Class>> primitiveCls;
17 |
18 | static final Map,Class>> numberClassMap;
19 | static{
20 | numberClassMap = wrapperNumberCls();
21 | primitiveCls = new HashMap, Class>>(primitiveNumberCls());
22 | primitiveCls.put(boolean.class, boolean.class);
23 | primitiveCls.put(Boolean.class, boolean.class);
24 |
25 | wrapperCls = new HashMap, Class>>(wrapperNumberCls());
26 | wrapperCls.put(boolean.class, Boolean.class);
27 | wrapperCls.put(Boolean.class, Boolean.class);
28 | }
29 |
30 | private static Map,Class>> primitiveNumberCls() {
31 | Map,Class>> map = new HashMap, Class>>();
32 | map.put(byte.class, byte.class);
33 | map.put(Byte.class, byte.class);
34 |
35 | map.put(short.class, short.class);
36 | map.put(Short.class, short.class);
37 |
38 | map.put(int.class, int.class);
39 | map.put(Integer.class, int.class);
40 |
41 | map.put(long.class, long.class);
42 | map.put(Long.class, long.class);
43 |
44 | map.put(float.class, float.class);
45 | map.put(Float.class, float.class);
46 |
47 | map.put(double.class, double.class);
48 | map.put(Double.class, double.class);
49 |
50 | map.put(char.class, char.class);
51 | map.put(Character.class, char.class);
52 | return map;
53 | }
54 |
55 | private static Map,Class>> wrapperNumberCls() {
56 | Map,Class>> map = new HashMap, Class>>();
57 | map.put(byte.class, Byte.class);
58 | map.put(Byte.class, Byte.class);
59 |
60 | map.put(short.class, Short.class);
61 | map.put(Short.class, Short.class);
62 |
63 | map.put(int.class, Integer.class);
64 | map.put(Integer.class, Integer.class);
65 |
66 | map.put(long.class, Long.class);
67 | map.put(Long.class, Long.class);
68 |
69 | map.put(float.class, Float.class);
70 | map.put(Float.class, Float.class);
71 |
72 | map.put(double.class, Double.class);
73 | map.put(Double.class, Double.class);
74 |
75 | map.put(char.class, Character.class);
76 | map.put(Character.class, Character.class);
77 | return map;
78 | }
79 |
80 | /**
81 | * 是基本类型中的数值类型(包含包装类型)
82 | * @return
83 | */
84 | public static boolean isPrimitiveOrWrapNumber(Class> c){
85 | return numberClassMap.containsKey(c);
86 | }
87 | public static boolean isPrimitiveNumber(Class> c){
88 | if(c == null){
89 | return false;
90 | }
91 | return c.isPrimitive()&&(c!=boolean.class);
92 | // return numberClassMap.containsKey(c);
93 | }
94 |
95 | public static Class> toWrapperClass(Class> c){
96 | return wrapperCls.get(c);
97 | }
98 | public static Class> toPrimitiveClass(Class> c){
99 | return primitiveCls.get(c);
100 | }
101 |
102 | /*
103 | public static void main(String[] args) {
104 | System.out.println((1+"2"+3));
105 | int[] a = new int[]{5,4,3,2,10,100,1};
106 | sort(a);
107 | System.out.println(Arrays.toString(a));
108 | }*/
109 |
110 | public static void sort(int[] array){
111 | for (int i = 1; i < array.length; i++) {
112 | int j = i-1;
113 | int current = array[i];
114 | for(;j>-1&¤t cls,String attr,Class>[] paramTypes){
130 | if(attr == null || "".equals(attr)){
131 | return null;
132 | }
133 | String firstUpper = String.valueOf(attr.charAt(0)).toUpperCase()+attr.substring(1);
134 | Method[] methods = cls.getMethods();
135 |
136 | Method finalMethod = null;
137 | String[] methodNames = new String[]{attr,"get"+firstUpper,"is"+firstUpper};
138 | for (String methodName : methodNames) {
139 | finalMethod = match(methodName, paramTypes, methods);
140 | if(finalMethod!=null){
141 | break;
142 | }
143 | }
144 | return finalMethod;
145 |
146 | /*
147 | String get = "get";
148 | finalMethod = match(get, paramTypes, methods, finalMethod);
149 | if(finalMethod!=null){
150 | return finalMethod;
151 | }*/
152 | }
153 |
154 | public static Method getMethod(Class> cls,String methodName,Class>[] paramTypes){
155 | Method[] methods = cls.getMethods();
156 | return match(methodName,paramTypes,methods);
157 |
158 | }
159 | private static Method match(String methodName, Class>[] paramValueTypes,
160 | Method[] methods) {
161 | Method finalMethod = null;
162 | //方法名称和参数长度核匹配的方法,当不能精确匹配时,返回此方法
163 | Method nameParamLengthEqualsMethod = null;
164 | out:for (Method m : methods) {
165 | String name = m.getName();
166 | if(name.equals(methodName) ){
167 | Class>[] methodParamTypes = m.getParameterTypes();
168 | if(methodParamTypes!=null&& paramValueTypes != null){
169 | if(methodParamTypes.length== paramValueTypes.length){
170 | if(nameParamLengthEqualsMethod == null){
171 | nameParamLengthEqualsMethod = m;
172 | }
173 |
174 | //比较参数是否匹配
175 | for (int i = 0; i < methodParamTypes.length; i++) {
176 | Class> c1 = methodParamTypes[i];
177 | Class> c2 = paramValueTypes[i];
178 | if(!isTypeMatch(c1, c2)){
179 | //如果不匹配,找下一个方法
180 | continue out;
181 | }
182 | }
183 | finalMethod = m;
184 | break;
185 | }
186 | }else if(ArrayUtils.isEmpty(methodParamTypes)&&ArrayUtils.isEmpty(paramValueTypes)){
187 | //如果参数都为null,认为是方法是匹配的
188 | finalMethod = m;
189 | break;
190 | }
191 | }
192 | }
193 | return finalMethod == null?nameParamLengthEqualsMethod:finalMethod;
194 | }
195 |
196 | public static boolean isTypeMatch(Class> c1,Class> c2){
197 | if(c1 == c2||c2==Null.class){
198 | //当c2为Null.class时,表示参数值是null,null值可以与任何类型匹配类型
199 | return true;
200 | }
201 | Class> w1 = ReflectUtil.toWrapperClass(c1);
202 | Class> w2 = ReflectUtil.toWrapperClass(c2);
203 | if(w1!=null){
204 | //可能转换成包装类型
205 | if(w1==w2){
206 | //查看包装类型是否相等
207 | return true;
208 | }
209 | }
210 | //判断c2是不是c1的子类,如果是,返回true
211 | return c1.isAssignableFrom(c2);
212 | }
213 |
214 | static public String getClassName(Class> cls){
215 | if(cls == null){
216 | return "null";
217 | }
218 | return cls.getCanonicalName();
219 | }
220 |
221 |
222 | }
223 |
--------------------------------------------------------------------------------
/src/com/greenpineyu/fel/common/StringUtils.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.common;
2 |
3 | public class StringUtils {
4 |
5 | /**
6 | * Represents a failed index search.
7 | * @since 2.1
8 | */
9 | public static final int INDEX_NOT_FOUND = -1;
10 |
11 | public static boolean isEmpty(CharSequence cs) {
12 | return cs == null || cs.length() == 0;
13 | }
14 |
15 | /**
16 | * Checks if a CharSequence is not empty ("") and not null.
17 | *
18 | *
19 | * StringUtils.isNotEmpty(null) = false
20 | * StringUtils.isNotEmpty("") = false
21 | * StringUtils.isNotEmpty(" ") = true
22 | * StringUtils.isNotEmpty("bob") = true
23 | * StringUtils.isNotEmpty(" bob ") = true
24 | *
25 | *
26 | * @param cs the CharSequence to check, may be null
27 | * @return {@code true} if the CharSequence is not empty and not null
28 | * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence)
29 | */
30 | public static boolean isNotEmpty(CharSequence cs) {
31 | return !StringUtils.isEmpty(cs);
32 | }
33 |
34 |
35 | /**
36 | * Replaces all occurrences of a String within another String.
37 | *
38 | * A {@code null} reference passed to this method is a no-op.
39 | *
40 | *
41 | * StringUtils.replace(null, *, *) = null
42 | * StringUtils.replace("", *, *) = ""
43 | * StringUtils.replace("any", null, *) = "any"
44 | * StringUtils.replace("any", *, null) = "any"
45 | * StringUtils.replace("any", "", *) = "any"
46 | * StringUtils.replace("aba", "a", null) = "aba"
47 | * StringUtils.replace("aba", "a", "") = "b"
48 | * StringUtils.replace("aba", "a", "z") = "zbz"
49 | *
50 | *
51 | * @see #replace(String text, String searchString, String replacement, int max)
52 | * @param text text to search and replace in, may be null
53 | * @param searchString the String to search for, may be null
54 | * @param replacement the String to replace it with, may be null
55 | * @return the text with any replacements processed,
56 | * {@code null} if null String input
57 | */
58 | public static String replace(String text, String searchString, String replacement) {
59 | return replace(text, searchString, replacement, -1);
60 | }
61 |
62 |
63 | /**
64 | * Replaces a String with another String inside a larger String,
65 | * for the first {@code max} values of the search String.
66 | *
67 | * A {@code null} reference passed to this method is a no-op.
68 | *
69 | *
70 | * StringUtils.replace(null, *, *, *) = null
71 | * StringUtils.replace("", *, *, *) = ""
72 | * StringUtils.replace("any", null, *, *) = "any"
73 | * StringUtils.replace("any", *, null, *) = "any"
74 | * StringUtils.replace("any", "", *, *) = "any"
75 | * StringUtils.replace("any", *, *, 0) = "any"
76 | * StringUtils.replace("abaa", "a", null, -1) = "abaa"
77 | * StringUtils.replace("abaa", "a", "", -1) = "b"
78 | * StringUtils.replace("abaa", "a", "z", 0) = "abaa"
79 | * StringUtils.replace("abaa", "a", "z", 1) = "zbaa"
80 | * StringUtils.replace("abaa", "a", "z", 2) = "zbza"
81 | * StringUtils.replace("abaa", "a", "z", -1) = "zbzz"
82 | *
83 | *
84 | * @param text text to search and replace in, may be null
85 | * @param searchString the String to search for, may be null
86 | * @param replacement the String to replace it with, may be null
87 | * @param max maximum number of values to replace, or {@code -1} if no maximum
88 | * @return the text with any replacements processed,
89 | * {@code null} if null String input
90 | */
91 | public static String replace(String text, String searchString, String replacement, int max) {
92 | if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) {
93 | return text;
94 | }
95 | int start = 0;
96 | int end = text.indexOf(searchString, start);
97 | if (end == INDEX_NOT_FOUND) {
98 | return text;
99 | }
100 | int replLength = searchString.length();
101 | int increase = replacement.length() - replLength;
102 | increase = (increase < 0 ? 0 : increase);
103 | increase *= (max < 0 ? 16 : (max > 64 ? 64 : max));
104 | StringBuilder buf = new StringBuilder(text.length() + increase);
105 | while (end != INDEX_NOT_FOUND) {
106 | buf.append(text.substring(start, end)).append(replacement);
107 | start = end + replLength;
108 | if (--max == 0) {
109 | break;
110 | }
111 | end = text.indexOf(searchString, start);
112 | }
113 | buf.append(text.substring(start));
114 | return buf.toString();
115 | }
116 |
117 |
118 | /**
119 | * Removes all occurrences of a character from within the source string.
120 | *
121 | * A {@code null} source string will return {@code null}.
122 | * An empty ("") source string will return the empty string.
123 | *
124 | *
125 | * StringUtils.remove(null, *) = null
126 | * StringUtils.remove("", *) = ""
127 | * StringUtils.remove("queued", 'u') = "qeed"
128 | * StringUtils.remove("queued", 'z') = "queued"
129 | *
130 | *
131 | * @param str the source String to search, may be null
132 | * @param remove the char to search for and remove, may be null
133 | * @return the substring with the char removed if found,
134 | * {@code null} if null String input
135 | * @since 2.1
136 | */
137 | public static String remove(String str, char remove) {
138 | if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) {
139 | return str;
140 | }
141 | char[] chars = str.toCharArray();
142 | int pos = 0;
143 | for (int i = 0; i < chars.length; i++) {
144 | if (chars[i] != remove) {
145 | chars[pos++] = chars[i];
146 | }
147 | }
148 | return new String(chars, 0, pos);
149 | }
150 |
151 | //-----------------------------------------------------------------------
152 | /**
153 | * Compares two CharSequences, returning {@code true} if they are equal.
154 | *
155 | * {@code null}s are handled without exceptions. Two {@code null}
156 | * references are considered to be equal. The comparison is case sensitive.
157 | *
158 | *
159 | * StringUtils.equals(null, null) = true
160 | * StringUtils.equals(null, "abc") = false
161 | * StringUtils.equals("abc", null) = false
162 | * StringUtils.equals("abc", "abc") = true
163 | * StringUtils.equals("abc", "ABC") = false
164 | *
165 | *
166 | * @see java.lang.String#equals(Object)
167 | * @param cs1 the first CharSequence, may be null
168 | * @param cs2 the second CharSequence, may be null
169 | * @return {@code true} if the CharSequences are equal, case sensitive, or
170 | * both {@code null}
171 | * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence)
172 | */
173 | public static boolean equals(CharSequence cs1, CharSequence cs2) {
174 | return cs1 == null ? cs2 == null : cs1.equals(cs2);
175 | }
176 |
177 | }
178 |
--------------------------------------------------------------------------------
/src/com/greenpineyu/fel/compile/AbstCompiler.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.compile;
2 |
3 | import java.io.File;
4 | import java.io.FilenameFilter;
5 | import java.io.UnsupportedEncodingException;
6 | import java.net.URL;
7 | import java.net.URLDecoder;
8 | import java.util.ArrayList;
9 | import java.util.Arrays;
10 | import java.util.HashSet;
11 | import java.util.List;
12 | import java.util.Set;
13 | import java.util.concurrent.ExecutorService;
14 | import java.util.concurrent.LinkedBlockingQueue;
15 | import java.util.concurrent.ThreadPoolExecutor;
16 | import java.util.concurrent.TimeUnit;
17 |
18 | import com.greenpineyu.fel.Expression;
19 | import com.greenpineyu.fel.common.StringUtils;
20 |
21 | public abstract class AbstCompiler implements FelCompiler {
22 | /*
23 | * 用户编译的classpath
24 | */
25 | public static final String CLASSPATH;
26 |
27 | /**
28 | * class文件夹
29 | */
30 | static final String CLASS_DIR;
31 |
32 | private static final String BASE_DIR;
33 | static ClassLoader loader;
34 | static {
35 | CLASSPATH = getClassPath();
36 | String userDir = System.getProperty("user.dir");
37 | BASE_DIR = userDir + File.separator + "fel" + File.separator;
38 | CLASS_DIR = BASE_DIR + "classes" + File.separator;
39 | loader = new FileClassLoader(AbstCompiler.class.getClassLoader(),
40 | CLASS_DIR);
41 | createClassDir();
42 | }
43 |
44 | /**
45 | * Class文件所在文件夹,包含包名
46 | */
47 | static String getClassPackageDir(String pack) {
48 | return CLASS_DIR + packageToPath(pack) + File.separator;
49 | }
50 |
51 | static String getSrcPackageDir(String pack) {
52 | return BASE_DIR + "src" + File.separator + packageToPath(pack)
53 | + File.separator;
54 | }
55 |
56 | private static String getPath(Class> cls) {
57 | String path = "";
58 | try {
59 | URL location = cls.getProtectionDomain().getCodeSource()
60 | .getLocation();
61 | path = URLDecoder.decode(location.getFile(), "UTF-8");
62 | } catch (UnsupportedEncodingException e) {
63 | }
64 | return path;
65 | }
66 |
67 | private static String getClassPath() {
68 | /*
69 | * 将三项添加到classpath 1:lib中的所有jar 2:class目录 3:系统属性:"java.class.path"
70 | */
71 | Class> cls = AbstCompiler.class;
72 | String path = getPath(cls);
73 | boolean isJar = path.endsWith(".jar");
74 | Set cpSet = new HashSet();
75 | if (isJar) {
76 | File jarFile = new File(path);
77 | File lib = jarFile.getParentFile();
78 | if (lib != null) {
79 | cpSet.addAll(getLibJars(jarFile.getParent()));
80 | String web_inf = lib.getParent();
81 | String classDir = web_inf + File.separator + "classes";
82 | File classDirfile = new File(classDir);
83 | if (classDirfile != null && classDirfile.exists()) {
84 | cpSet.add(classDir);
85 | }
86 | }
87 | } else {
88 | String classFullName = cls.getName().replaceAll("\\.", "/");
89 | int index = path.lastIndexOf(classFullName + ".class");
90 | if (index != -1) {
91 | String classDir = path.substring(0, index);
92 | cpSet.add(classDir);
93 | File classDirFile = new File(classDir);
94 | File web_inf = classDirFile.getParentFile();
95 | String libDir = web_inf + File.separator + "lib";
96 | cpSet.addAll(getLibJars(libDir));
97 | }
98 | }
99 | String systemCp = System.getProperty("java.class.path");
100 | if (systemCp != null) {
101 | String[] cps = systemCp.split(File.pathSeparator);
102 | if (cps != null) {
103 | cpSet.addAll(Arrays.asList(cps));
104 | }
105 | }
106 | String cpStr = "";
107 | for (String c : cpSet) {
108 | cpStr += c + File.pathSeparator;
109 | }
110 | return cpStr;
111 | }
112 |
113 | private static Set getLibJars(String libDir) {
114 | Set jarPathSet = new HashSet();
115 | File dir = new File(libDir);
116 | if (dir != null && dir.isDirectory()) {
117 | File[] files = dir.listFiles(new FilenameFilter() {
118 | public boolean accept(File dir, String name) {
119 | return name.endsWith(".jar");
120 | }
121 | });
122 | for (int i = 0; i < files.length; i++) {
123 | File file = files[i];
124 | String absolutePath = file.getAbsolutePath();
125 | jarPathSet.add(absolutePath);
126 | }
127 | }
128 | return jarPathSet;
129 | }
130 |
131 | public Expression compile(JavaSource src) {
132 | Class compile;
133 | try {
134 | compile = this.compileToClass(src);
135 | return compile.newInstance();
136 | } catch (ClassNotFoundException e1) {
137 | e1.printStackTrace();
138 | } catch (InstantiationException e) {
139 | e.printStackTrace();
140 | } catch (IllegalAccessException e) {
141 | e.printStackTrace();
142 | }finally{
143 | String className = src.getName();
144 | String pack = src.getPackageName();
145 | String srcPackageDir = getSrcPackageDir(pack);
146 | clean(srcPackageDir,getClassPackageDir(pack),className);
147 | }
148 | return null;
149 | }
150 |
151 |
152 | abstract Class compileToClass(JavaSource expr)
153 | throws ClassNotFoundException;
154 |
155 | static void createClassDir() {
156 | new File(CLASS_DIR).mkdirs();
157 | }
158 |
159 | private static ExecutorService exeService = initThreadPool();
160 |
161 | private static ExecutorService initThreadPool() {
162 | return new ThreadPoolExecutor(0, 10, 5L, TimeUnit.SECONDS,
163 | new LinkedBlockingQueue());
164 | }
165 |
166 | void clean(final String srcPackageDir,
167 | final String classPackageDir, final String fileName) {
168 | if (exeService.isShutdown()) {
169 | exeService = initThreadPool();
170 | }
171 | exeService.execute(new Runnable() {
172 | public void run() {
173 | // 优先级设置成最低
174 | Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
175 | delFile(srcPackageDir, classPackageDir, fileName);
176 | }
177 | });
178 | // exeService.shutdown();
179 | }
180 |
181 | void delFile(final String srcPackageDir, final String classPackageDir,
182 | final String fileName) {
183 | String src = srcPackageDir + fileName + ".java";
184 | deleteFile(src);
185 | String cls = classPackageDir + fileName + ".class";
186 | deleteFile(cls);
187 | }
188 |
189 | void deleteFile(String src) {
190 | File file = new File(src);
191 | // System.out.println("delete file:"+src);
192 | if (file.exists()) {
193 | file.delete();
194 | }
195 | }
196 |
197 |
198 | List getCompileOption() {
199 | List options = new ArrayList();
200 | options.add("-encoding");
201 | options.add("UTF-8");
202 | options.add("-d");
203 | options.add(CLASS_DIR);
204 |
205 | if (StringUtils.isNotEmpty(CLASSPATH)) {
206 | options.add("-classpath");
207 | options.add(CLASSPATH);
208 | }
209 | return options;
210 | }
211 |
212 | /**
213 | * 将包名转换成包路径
214 | *
215 | * @param packageName
216 | * @return
217 | */
218 | private static String packageToPath(String packageName) {
219 | String sep = File.separator;
220 | // if (sep.equals("\\")) {
221 | // sep = "\\\\";
222 | // }
223 | return StringUtils.replace(packageName, ".", sep);
224 | // return packageName.replaceAll("\\.", sep);
225 | }
226 |
227 | }
228 |
--------------------------------------------------------------------------------
/src/com/greenpineyu/fel/compile/CompileService.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.compile;
2 |
3 | import com.greenpineyu.fel.Expression;
4 | import com.greenpineyu.fel.context.FelContext;
5 | import com.greenpineyu.fel.parser.FelNode;
6 |
7 | public class CompileService {
8 |
9 | private SourceGenerator srcGen;
10 | private FelCompiler complier;
11 |
12 | public SourceGenerator getSrcGen() {
13 | return srcGen;
14 | }
15 |
16 | public void setSrcGen(SourceGenerator srcGen) {
17 | this.srcGen = srcGen;
18 | }
19 |
20 | public FelCompiler getComplier() {
21 | return complier;
22 | }
23 |
24 | public void setComplier(FelCompiler complier) {
25 | this.complier = complier;
26 | }
27 |
28 | {
29 | srcGen = new SourceGeneratorImpl();
30 | String name = getCompilerClassName();
31 | FelCompiler comp = newCompiler(name);
32 | complier = comp;
33 | }
34 |
35 | private FelCompiler newCompiler(String name) {
36 | FelCompiler comp = null;
37 | try {
38 | @SuppressWarnings("unchecked")
39 | Class cls = (Class) Class.forName(name);
40 | comp = cls.newInstance();
41 | } catch (ClassNotFoundException e) {
42 | e.printStackTrace();
43 | } catch (InstantiationException e) {
44 | e.printStackTrace();
45 | } catch (IllegalAccessException e) {
46 | e.printStackTrace();
47 | } finally {
48 | }
49 | return comp;
50 | }
51 |
52 | private String getCompilerClassName() {
53 | String version = System.getProperty("java.version");
54 | String compileClassName = FelCompiler.class.getName();
55 | if (version != null && version.startsWith("1.5")) {
56 | compileClassName += "15";
57 | } else {
58 | compileClassName += "16";
59 | }
60 | return compileClassName;
61 | }
62 |
63 | public Expression compile(FelContext ctx, FelNode node, String originalExp) {
64 | try {
65 | JavaSource src = srcGen.getSource(ctx, node);
66 | if (src instanceof ConstExpSrc) {
67 | ConstExpSrc s = (ConstExpSrc) src;
68 | return s.getValue();
69 | }
70 | src.setSource("// 表达式:" + originalExp + "\n" + src.getSource());
71 | // System.out.println("****************\n" + src.getSource());
72 | return complier.compile(src);
73 | } catch (Exception e) {
74 | e.printStackTrace();
75 | }
76 | return null;
77 | }
78 |
79 | public static void main(String[] args) {
80 | System.getProperties().list(System.out);
81 | }
82 |
83 | }
84 |
--------------------------------------------------------------------------------
/src/com/greenpineyu/fel/compile/ConstExp.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.compile;
2 |
3 | import com.greenpineyu.fel.Expression;
4 | import com.greenpineyu.fel.context.FelContext;
5 |
6 | public final class ConstExp implements Expression {
7 | public ConstExp(Object o) {
8 | this.value = o;
9 | }
10 |
11 | private final Object value;
12 |
13 | @Override
14 | public final Object eval(FelContext context) {
15 | return value;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/com/greenpineyu/fel/compile/ConstExpSrc.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.compile;
2 |
3 | /**
4 | * @author yuqingsong
5 | *
6 | */
7 | public class ConstExpSrc extends JavaSource {
8 |
9 | public ConstExpSrc(Object o) {
10 | this.value = new ConstExp(o);
11 | }
12 |
13 | private final ConstExp value;
14 |
15 | public ConstExp getValue() {
16 | return value;
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/com/greenpineyu/fel/compile/FelCompiler.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.compile;
2 |
3 | import com.greenpineyu.fel.Expression;
4 |
5 | public interface FelCompiler {
6 |
7 | /**
8 | *
9 | * 编译代码,并创建Expression
10 | * @param expr
11 | * @return
12 | */
13 | public Expression compile(JavaSource src);
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/com/greenpineyu/fel/compile/FelCompiler15.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.compile;
2 |
3 | import java.io.BufferedOutputStream;
4 | import java.io.File;
5 | import java.io.FileNotFoundException;
6 | import java.io.FileOutputStream;
7 | import java.io.IOException;
8 | import java.io.OutputStreamWriter;
9 | import java.io.UnsupportedEncodingException;
10 | import java.util.List;
11 |
12 | import com.greenpineyu.fel.Expression;
13 | import com.sun.tools.javac.Main;
14 |
15 | /**
16 | * jdk1.5环境的编译器实现类
17 | *
18 | * @author yuqingsong
19 | *
20 | */
21 | public class FelCompiler15 extends AbstCompiler {
22 |
23 |
24 | @Override
25 | Class compileToClass(JavaSource src) throws ClassNotFoundException {
26 | String className = src.getSimpleName();
27 | String pack = src.getPackageName();
28 | String srcPackageDir = getSrcPackageDir(pack);
29 | String file = srcPackageDir + className + ".java";
30 | new File(srcPackageDir).mkdirs();
31 | String source =src.getSource();
32 | writeJavaFile(file, source);
33 |
34 | List opt = getCompileOption();
35 | opt.add(file);
36 | String[] arg = opt.toArray(new String[0]);
37 |
38 | int compile = Main.compile(arg);
39 | if (compile != 0) {
40 | return null;
41 | }
42 | @SuppressWarnings("unchecked")
43 | Class c = (Class) loader.loadClass(src.getName());
44 | return c;
45 | }
46 |
47 | void writeJavaFile(String file, String source) {
48 | OutputStreamWriter write = null;
49 | try {
50 | BufferedOutputStream os;
51 | os = new BufferedOutputStream(new FileOutputStream(file), 500);
52 | write = new OutputStreamWriter(os, "utf-8");
53 | write.write(source);
54 | } catch (FileNotFoundException e) {
55 | e.printStackTrace();
56 | } catch (UnsupportedEncodingException e) {
57 | e.printStackTrace();
58 | } catch (IOException e) {
59 | e.printStackTrace();
60 | } finally {
61 | if (write != null) {
62 | try {
63 | write.close();
64 | } catch (IOException e) {
65 | e.printStackTrace();
66 | }
67 | }
68 | }
69 | }
70 |
71 |
72 |
73 |
74 |
75 | public static void main(String[] args) throws InstantiationException,
76 | IllegalAccessException {
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/com/greenpineyu/fel/compile/FelCompiler16.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.compile;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 | import java.net.URI;
6 | import java.net.URISyntaxException;
7 | import java.net.URL;
8 | import java.net.URLClassLoader;
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 | import javax.tools.DiagnosticCollector;
13 | import javax.tools.FileObject;
14 | import javax.tools.ForwardingJavaFileManager;
15 | import javax.tools.JavaCompiler;
16 | import javax.tools.JavaCompiler.CompilationTask;
17 | import javax.tools.JavaFileManager;
18 | import javax.tools.JavaFileObject;
19 | import javax.tools.JavaFileObject.Kind;
20 | import javax.tools.StandardJavaFileManager;
21 | import javax.tools.StandardLocation;
22 | import javax.tools.ToolProvider;
23 |
24 | import com.greenpineyu.fel.Expression;
25 | import com.greenpineyu.fel.exception.CompileException;
26 |
27 | public class FelCompiler16 implements FelCompiler {
28 | private final FelCompilerClassloader classLoader;
29 |
30 | private final JavaCompiler compiler;
31 |
32 | private final List options;
33 |
34 | private DiagnosticCollector diagnostics;
35 |
36 | private final JavaFileManager javaFileManager;
37 |
38 | public FelCompiler16() {
39 | compiler = ToolProvider.getSystemJavaCompiler();
40 |
41 | if (compiler == null) {
42 | throw new IllegalStateException(
43 | "Cannot find the system Java compiler. "
44 | + "Check that your class path includes tools.jar");
45 | }
46 |
47 | this.classLoader = new FelCompilerClassloader(this.getClass()
48 | .getClassLoader());
49 | diagnostics = new DiagnosticCollector();
50 | final StandardJavaFileManager fileManager = compiler
51 | .getStandardFileManager(diagnostics, null, null);
52 |
53 | ClassLoader loader = this.classLoader.getParent();
54 | if (loader instanceof URLClassLoader
55 | && (!loader.getClass().getName()
56 | .equals("sun.misc.Launcher$AppClassLoader"))) {
57 | try {
58 | URLClassLoader urlClassLoader = (URLClassLoader) loader;
59 | List path = new ArrayList();
60 | for (URL url : urlClassLoader.getURLs()) {
61 | File file = new File(url.getFile());
62 | path.add(file);
63 | }
64 | fileManager.setLocation(StandardLocation.CLASS_PATH, path);
65 | } catch (IOException e) {
66 | e.printStackTrace();
67 | }
68 | }
69 |
70 | javaFileManager = new ForwardingJavaFileManager(
71 | fileManager) {
72 | @Override
73 | public JavaFileObject getJavaFileForOutput(Location location,
74 | String qualifiedName, Kind kind, FileObject outputFile)
75 | throws IOException {
76 | // 由于编译成功后的bytecode需要放到file中,所以需要将file放到classloader中,以便读取bytecode生成Class对象.
77 | classLoader.add(qualifiedName, outputFile);
78 | return (JavaFileObject) outputFile;
79 | }
80 | };
81 | this.options = new ArrayList();
82 | // this.options.add("-O");
83 | }
84 |
85 | @Override
86 | public Expression compile(JavaSource src) {
87 |
88 | Class compile = compileToClass(src);
89 | try {
90 | return (Expression) compile.newInstance();
91 | } catch (InstantiationException e) {
92 | e.printStackTrace();
93 | } catch (IllegalAccessException e) {
94 | e.printStackTrace();
95 | }
96 | return null;
97 | }
98 |
99 |
100 | public synchronized Class compileToClass(final JavaSource src) {
101 | List compileSrcs = new ArrayList();
102 | String className = src.getSimpleName();
103 | final FelJavaFileObject compileSrc = new FelJavaFileObject(className,
104 | src.getSource());
105 | compileSrcs.add(compileSrc);
106 | final CompilationTask task = compiler.getTask(null, javaFileManager,
107 | diagnostics, options, null, compileSrcs);
108 | final Boolean result = task.call();
109 | if (result == null || !result.booleanValue()) {
110 | // diagnostics.
111 | // 编译失败
112 | // diagnostics.getDiagnostics()
113 | throw new CompileException(src.getSource() + "\n"
114 | + diagnostics.getDiagnostics().toString());
115 | }
116 | try {
117 | return loadClass(src.getName());
118 | } catch (ClassNotFoundException e) {
119 | e.printStackTrace();
120 | }
121 | return null;
122 | }
123 |
124 | @SuppressWarnings("unchecked")
125 | public Class loadClass(final String qualifiedClassName)
126 | throws ClassNotFoundException {
127 | return (Class) classLoader.loadClass(qualifiedClassName);
128 | }
129 |
130 | static URI toUri(String name) {
131 | try {
132 | return new URI(name);
133 | } catch (URISyntaxException e) {
134 | throw new RuntimeException(e);
135 | }
136 | }
137 |
138 | }
139 |
140 |
--------------------------------------------------------------------------------
/src/com/greenpineyu/fel/compile/FelCompilerClassloader.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.compile;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | import javax.tools.FileObject;
7 |
8 | public final class FelCompilerClassloader extends ClassLoader {
9 | private final Map compileFileMap = new HashMap();
10 |
11 | public FelCompilerClassloader(ClassLoader parentClassLoader) {
12 | super(parentClassLoader);
13 | }
14 |
15 |
16 | @Override
17 | protected synchronized Class> findClass(String qualifiedClassName) throws ClassNotFoundException {
18 | FileObject file = compileFileMap.remove(qualifiedClassName);
19 | if (file != null) {
20 | byte[] bytes = ((FelJavaFileObject) file).getByteCode();
21 | return defineClass(qualifiedClassName, bytes, 0, bytes.length);
22 | }
23 | return super.findClass(qualifiedClassName);
24 | }
25 |
26 | public void add(String qualifiedClassName, final FileObject javaFile) {
27 | compileFileMap.put(qualifiedClassName, javaFile);
28 | }
29 |
30 | }
--------------------------------------------------------------------------------
/src/com/greenpineyu/fel/compile/FelJavaFileObject.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.compile;
2 |
3 | import java.io.ByteArrayInputStream;
4 | import java.io.ByteArrayOutputStream;
5 | import java.io.InputStream;
6 | import java.io.OutputStream;
7 | import java.net.URI;
8 |
9 | import javax.tools.SimpleJavaFileObject;
10 |
11 | /**
12 | * 编译时,用于提供类源码和保存类的字节码
13 | *
14 | * @author yuqingsong
15 | *
16 | */
17 | public class FelJavaFileObject extends SimpleJavaFileObject {
18 |
19 | // If kind == CLASS, this stores byte code from openOutputStream
20 | private final ByteArrayOutputStream byteCodeOs = new ByteArrayOutputStream();
21 |
22 | // if kind == SOURCE, this contains the source text
23 | private final CharSequence src;
24 |
25 | public FelJavaFileObject(final String baseName, final CharSequence source) {
26 | super(FelCompiler16.toUri(baseName + ".java"),
27 | Kind.SOURCE);
28 | this.src = source;
29 | }
30 |
31 | FelJavaFileObject(final String name, final Kind kind) {
32 | super(FelCompiler16.toUri(name), kind);
33 | src = null;
34 | }
35 |
36 | public FelJavaFileObject(URI uri, Kind kind) {
37 | super (uri, kind);
38 | src = null;
39 | }
40 |
41 | @Override
42 | public CharSequence getCharContent(final boolean ignoreEncodingErrors) throws UnsupportedOperationException {
43 | if (src == null) {
44 | throw new UnsupportedOperationException();
45 | }
46 |
47 | return src;
48 | }
49 |
50 | @Override
51 | public InputStream openInputStream() {
52 | return new ByteArrayInputStream(getByteCode());
53 | }
54 |
55 | @Override
56 | public OutputStream openOutputStream() {
57 | return byteCodeOs;
58 | }
59 |
60 | byte[] getByteCode() {
61 | return byteCodeOs.toByteArray();
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/src/com/greenpineyu/fel/compile/FelMethod.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.compile;
2 |
3 | import com.greenpineyu.fel.context.FelContext;
4 | import com.greenpineyu.fel.parser.FelNode;
5 |
6 | /**
7 | *
8 | */
9 | public class FelMethod implements SourceBuilder {
10 |
11 | private Class> returnType;
12 |
13 | private String code;
14 |
15 |
16 | public FelMethod(Class> returnType,String code){
17 | this.returnType = returnType;
18 | this.code = code;
19 | }
20 |
21 |
22 | public Class> returnType(FelContext ctx, FelNode node) {
23 | return returnType;
24 | }
25 |
26 |
27 | public void setReturnType(Class> returnType) {
28 | this.returnType = returnType;
29 | }
30 |
31 |
32 | public String source(FelContext ctx, FelNode node) {
33 | return code;
34 | }
35 |
36 |
37 | public void setCode(String code) {
38 | this.code = code;
39 | }
40 |
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/com/greenpineyu/fel/compile/FileClassLoader.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.compile;
2 |
3 | import java.io.ByteArrayOutputStream;
4 | import java.io.File;
5 | import java.io.FileInputStream;
6 | import java.io.IOException;
7 |
8 | public class FileClassLoader extends ClassLoader {
9 | private String dir;
10 | public static final String fileType = ".class";
11 |
12 | public FileClassLoader(ClassLoader arg0, String dir) {
13 | super(arg0);
14 | this.dir = dir;
15 | }
16 |
17 | public Class> findClass(String name) {
18 | byte[] data = loadClassData(name);
19 | return defineClass(name, data, 0, data.length);
20 | }
21 |
22 | public byte[] loadClassData(String name) {
23 | name = name.replaceAll("\\.", "/");
24 | FileInputStream fis = null;
25 | byte[] data = null;
26 | try {
27 | fis = new FileInputStream(new File(dir + name + fileType));
28 | ByteArrayOutputStream baos = new ByteArrayOutputStream();
29 | int ch = 0;
30 | while ((ch = fis.read()) != -1) {
31 | baos.write(ch);
32 | }
33 | data = baos.toByteArray();
34 | } catch (IOException e) {
35 | e.printStackTrace();
36 | }finally{
37 | if(fis!= null){
38 | try {
39 | fis.close();
40 | } catch (IOException e) {
41 | e.printStackTrace();
42 | }
43 | }
44 | }
45 | return data;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/com/greenpineyu/fel/compile/InterpreterSourceBuilder.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.compile;
2 |
3 | import com.greenpineyu.fel.context.AbstractContext;
4 | import com.greenpineyu.fel.context.FelContext;
5 | import com.greenpineyu.fel.interpreter.Interpreter;
6 | import com.greenpineyu.fel.parser.FelNode;
7 |
8 | public class InterpreterSourceBuilder implements SourceBuilder {
9 |
10 |
11 |
12 |
13 | private static final SourceBuilder instance;
14 |
15 | public static SourceBuilder getInstance() {
16 | return instance;
17 | }
18 |
19 | static{
20 | instance = new InterpreterSourceBuilder();
21 | }
22 |
23 |
24 |
25 | @Override
26 | public Class> returnType(FelContext ctx, FelNode node) {
27 | return AbstractContext.getVarType(node.getInterpreter().interpret(ctx, node));
28 | }
29 |
30 | /**
31 | * 用户自定义解析器生成的java代码
32 | *
33 | * @param ctx
34 | * @param node
35 | * @return
36 | */
37 | @Override
38 | public String source(FelContext ctx, FelNode node) {
39 | // 用户设置了解释器
40 | // Interpreter inte = new ProxyInterpreter(node.getInterpreter(), node);
41 | Interpreter inte = node.getInterpreter();
42 | SourceBuilder nodeBuilder = node.toMethod(ctx);
43 | Class> type =nodeBuilder.returnType(ctx, node);
44 | String code = "("+type.getName()+")";
45 | String varName = VarBuffer.push(inte,Interpreter.class);
46 | String nodeVarName = VarBuffer.push(node, FelNode.class);
47 | code += varName + ".interpret(context," + nodeVarName + ")";
48 | boolean isNumber = Number.class.isAssignableFrom(type);
49 | if(isNumber){
50 | code="("+code+").doubleValue()";
51 | }
52 | return code;
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/src/com/greenpineyu/fel/compile/JavaSource.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.compile;
2 |
3 | public class JavaSource {
4 |
5 | /**
6 | * 类名,不包含包名
7 | */
8 | private String simpleName;
9 |
10 | /**
11 | * java源码
12 | */
13 | private String source;
14 |
15 | /**
16 | * 包名
17 | */
18 | private String packageName;
19 |
20 | public String getPackageName() {
21 | return packageName;
22 | }
23 |
24 | public void setPackageName(String packageName) {
25 | this.packageName = packageName;
26 | }
27 |
28 | public String getSimpleName() {
29 | return simpleName;
30 | }
31 |
32 | public void setSimpleName(String name) {
33 | this.simpleName = name;
34 | }
35 |
36 | public String getName(){
37 | return packageName + "." + simpleName;
38 | }
39 |
40 | public String getSource() {
41 | return source;
42 | }
43 |
44 | public void setSource(String source) {
45 | this.source = source;
46 | }
47 |
48 |
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/com/greenpineyu/fel/compile/SourceBuilder.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.compile;
2 |
3 | import com.greenpineyu.fel.context.FelContext;
4 | import com.greenpineyu.fel.parser.FelNode;
5 |
6 | /**
7 | * 创建java源码接口,此接口和SourceGenerator的区别在于,后者负责创建整个java类的源码。前者只用了创建表达式的代码片断。
8 | * @author yuqingsong
9 | *
10 | */
11 | public interface SourceBuilder {
12 |
13 | /**
14 | * 类型
15 | * @param ctx TODO
16 | * @param node TODO
17 | * @return
18 | */
19 | Class> returnType(FelContext ctx, FelNode node);
20 | /**
21 | * 构建源码
22 | * @param node TODO
23 | * @return
24 | */
25 | String source(FelContext ctx, FelNode node);
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/com/greenpineyu/fel/compile/SourceGenerator.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.compile;
2 |
3 | import com.greenpineyu.fel.context.FelContext;
4 | import com.greenpineyu.fel.optimizer.Optimizer;
5 | import com.greenpineyu.fel.parser.FelNode;
6 |
7 | public interface SourceGenerator {
8 |
9 | /**
10 | * 获取表达式JAVA源代码
11 | * @param node TODO
12 | * @return
13 | */
14 | JavaSource getSource(FelContext ctx, FelNode node);
15 |
16 | void addOpti(Optimizer opti);
17 |
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/com/greenpineyu/fel/compile/VarBuffer.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.compile;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 | import java.util.Stack;
6 | import java.util.UUID;
7 | import java.util.concurrent.ExecutorService;
8 | import java.util.concurrent.Executors;
9 |
10 |
11 | public class VarBuffer {
12 | static private ThreadLocal> varCodes;
13 | static private ThreadLocal