svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.library / org.gvsig.expressionevaluator / org.gvsig.expressionevaluator.lib / org.gvsig.expressionevaluator.lib.impl / src / main / java / org / gvsig / expressionevaluator / impl / function / programming / CreateFnFunction.java @ 45213
History | View | Annotate | Download (11.6 KB)
1 | 44138 | jjdelcerro | package org.gvsig.expressionevaluator.impl.function.programming; |
---|---|---|---|
2 | 43512 | jjdelcerro | |
3 | 44533 | jjdelcerro | import java.lang.reflect.Method; |
4 | 44389 | jjdelcerro | import java.util.ArrayList; |
5 | import java.util.Arrays; |
||
6 | 44138 | jjdelcerro | import java.util.List; |
7 | 43512 | jjdelcerro | import org.apache.commons.lang3.Range; |
8 | 44533 | jjdelcerro | import org.apache.commons.lang3.StringUtils; |
9 | 44138 | jjdelcerro | import org.gvsig.expressionevaluator.Code; |
10 | import org.gvsig.expressionevaluator.Codes; |
||
11 | 43939 | jjdelcerro | import org.gvsig.expressionevaluator.Function; |
12 | 43521 | jjdelcerro | import org.gvsig.expressionevaluator.Interpreter; |
13 | 43512 | jjdelcerro | import org.gvsig.expressionevaluator.spi.AbstractFunction; |
14 | 44138 | jjdelcerro | import org.gvsig.expressionevaluator.ExpressionEvaluatorLocator; |
15 | import org.gvsig.expressionevaluator.ExpressionEvaluatorManager; |
||
16 | import org.gvsig.expressionevaluator.ExpressionRuntimeException; |
||
17 | import org.gvsig.expressionevaluator.MutableSymbolTable; |
||
18 | import org.gvsig.expressionevaluator.SymbolTable; |
||
19 | 44533 | jjdelcerro | import org.gvsig.tools.ToolsLocator; |
20 | import org.gvsig.tools.resourcesstorage.ResourcesStorage; |
||
21 | import org.gvsig.tools.script.Script; |
||
22 | import org.gvsig.tools.script.ScriptManager; |
||
23 | 43512 | jjdelcerro | |
24 | 44750 | jjdelcerro | @SuppressWarnings("UseSpecificCatch") |
25 | 44138 | jjdelcerro | public class CreateFnFunction extends AbstractFunction { |
26 | |||
27 | public static final String NAME = "CREATE_FUNCTION"; |
||
28 | 43512 | jjdelcerro | |
29 | 44138 | jjdelcerro | public CreateFnFunction() {
|
30 | super(Function.GROUP_PROGRAMMING,
|
||
31 | NAME, |
||
32 | 44533 | jjdelcerro | Range.between(2, 6), |
33 | 44742 | jjdelcerro | "This function allows you to define functions within the expression evaluator.\n" +
|
34 | "We can define three types of functions:\n" +
|
||
35 | "\n<ul>" +
|
||
36 | "<li>Functions defined in the evaluator itself.</li>\n" +
|
||
37 | "<li>Functions implemented as a static method of a java class.</li>\n" +
|
||
38 | "<li>Functions defined in an external script.</li>\n" +
|
||
39 | "\n</ul>" +
|
||
40 | "<b> Functions defined in the evaluator itself. </b>\n" +
|
||
41 | "\n" +
|
||
42 | "They have the form:\n" +
|
||
43 | "\n" +
|
||
44 | "<pre>\n" +
|
||
45 | "CREATE PROCEDURE myfun param1 AS\n" +
|
||
46 | "BEGIN\n" +
|
||
47 | " RETURN 'Hello' || param1;\n" +
|
||
48 | "END PROCEDURE\n" +
|
||
49 | "</pre>\n" +
|
||
50 | "\n" +
|
||
51 | "<b> Functions implemented as a static method </b>\n" +
|
||
52 | "\n" +
|
||
53 | "They allow defining a function that will invoke a static method of a java class.\n" +
|
||
54 | "\n" +
|
||
55 | "They have the form:\n" +
|
||
56 | "\n" +
|
||
57 | "<pre>\n" +
|
||
58 | 44750 | jjdelcerro | "CREATE FUNCTION parseInt(value) AS 'java.lang.Integer', 'parseInt' LANGUAGE 'java'\n" +
|
59 | 44742 | jjdelcerro | "</pre>\n" +
|
60 | "\n" +
|
||
61 | 44750 | jjdelcerro | "Defines the \"parseInt\" function that receives a single parameter, and links it to the method\n" +
|
62 | "static 'parseInt' of the class 'java.lang.Integer',\n" +
|
||
63 | 44742 | jjdelcerro | "\n" +
|
64 | "<b> Functions defined in an external script. </b>\n" +
|
||
65 | "\n" +
|
||
66 | "It allows defining functions that are implemented in an external script module.\n" +
|
||
67 | "\n" +
|
||
68 | "They have the form:\n" +
|
||
69 | "\n" +
|
||
70 | "<pre>\n" +
|
||
71 | 44750 | jjdelcerro | "CREATE FUNCTION getCRS(crs) AS 'crs.py', 'getCRS' LANGUAGE 'script'\n" +
|
72 | 44742 | jjdelcerro | "</pre>\n" +
|
73 | "\n" +
|
||
74 | "What defines a \"getCRS\" function that is implemented in the python module\n" +
|
||
75 | "located in \"Users / crs\" with the name 'getCRS'.",
|
||
76 | 44924 | jjdelcerro | "CREATE FUNCTION {{name}}(param1, param2) AS\nBEGIN\n PASS\nEND FUNCTION\n",
|
77 | 44098 | jjdelcerro | null,
|
78 | "Object",
|
||
79 | false
|
||
80 | 43939 | jjdelcerro | ); |
81 | 43512 | jjdelcerro | } |
82 | |||
83 | @Override
|
||
84 | 44738 | jjdelcerro | public boolean isHidden() { |
85 | 44750 | jjdelcerro | return false; |
86 | 44738 | jjdelcerro | } |
87 | |||
88 | @Override
|
||
89 | 43939 | jjdelcerro | public boolean useArgumentsInsteadObjects() { |
90 | return true; |
||
91 | } |
||
92 | |||
93 | @Override
|
||
94 | 44138 | jjdelcerro | public boolean allowConstantFolding() { |
95 | return false; |
||
96 | } |
||
97 | 44738 | jjdelcerro | |
98 | @Override
|
||
99 | 43521 | jjdelcerro | public Object call(Interpreter interpreter, Object[] args) throws Exception { |
100 | 43939 | jjdelcerro | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. |
101 | } |
||
102 | |||
103 | 44750 | jjdelcerro | private static final int FUNCTION_NAME = 0; |
104 | private static final int PARAMETERS = 1; |
||
105 | private static final int BODY = 2; |
||
106 | private static final int SCRIPT_PATH = 3; |
||
107 | private static final int SCRIPT_FUNCTION = 4; |
||
108 | private static final int LANGUAGE = 5; |
||
109 | |||
110 | private static final int TYPE_USER_FUNCTION = 0; |
||
111 | private static final int TYPE_JAVA_FUNCTION = 1; |
||
112 | private static final int TYPE_SCRIPT_FUNCTION = 2; |
||
113 | |||
114 | 43939 | jjdelcerro | @Override
|
115 | 44138 | jjdelcerro | public Object call(Interpreter interpreter, Codes args) throws Exception { |
116 | 45025 | jjdelcerro | if( args.size()==2 ) { |
117 | List<String> argNames = (List<String>) getObject(interpreter, args, 0); |
||
118 | Code body = args.get(1);
|
||
119 | Function fn = new UserFunction("", argNames, body); |
||
120 | |||
121 | return fn;
|
||
122 | } |
||
123 | 44138 | jjdelcerro | if( !(interpreter.getSymbolTable() instanceof MutableSymbolTable) ) { |
124 | throw new ExpressionRuntimeException("The use of user functions require a mutable symbol table."); |
||
125 | 43512 | jjdelcerro | } |
126 | 44138 | jjdelcerro | MutableSymbolTable symbolTable = (MutableSymbolTable) interpreter.getSymbolTable(); |
127 | |||
128 | 44750 | jjdelcerro | String name = (String) getObject(interpreter, args, FUNCTION_NAME); |
129 | List<String> argNames = (List<String>) getObject(interpreter, args, PARAMETERS); |
||
130 | Code body = args.get(BODY); |
||
131 | String script_path = (String) getObject(interpreter, args, SCRIPT_PATH); |
||
132 | String script_function = (String) getObject(interpreter, args, SCRIPT_FUNCTION); |
||
133 | String language = (String) getObject(interpreter, args, LANGUAGE); |
||
134 | |||
135 | 44533 | jjdelcerro | if( StringUtils.isBlank(language) ) {
|
136 | language = "script";
|
||
137 | } |
||
138 | 44750 | jjdelcerro | |
139 | int type = TYPE_USER_FUNCTION;
|
||
140 | if( !StringUtils.isBlank(script_path) || !StringUtils.isBlank(script_function)) {
|
||
141 | switch(language.toLowerCase()) {
|
||
142 | case "script": |
||
143 | type = TYPE_SCRIPT_FUNCTION; |
||
144 | break;
|
||
145 | case "java": |
||
146 | type = TYPE_JAVA_FUNCTION; |
||
147 | break;
|
||
148 | default:
|
||
149 | throw new ExpressionRuntimeException("Unsupported language '"+language+"."); |
||
150 | } |
||
151 | 44533 | jjdelcerro | } |
152 | 44750 | jjdelcerro | Function fn = null;
|
153 | switch(type) {
|
||
154 | case TYPE_USER_FUNCTION:
|
||
155 | fn = new UserFunction(name, argNames, body);
|
||
156 | symbolTable.addFunction(fn); |
||
157 | break;
|
||
158 | case TYPE_JAVA_FUNCTION:
|
||
159 | if( StringUtils.isBlank(script_path) || StringUtils.isBlank(script_function)) {
|
||
160 | throw new ExpressionRuntimeException("Requiered classname and methodname."); |
||
161 | } |
||
162 | fn = new JavaFunction(name, script_path, script_function);
|
||
163 | symbolTable.addFunction(fn); |
||
164 | break;
|
||
165 | case TYPE_SCRIPT_FUNCTION:
|
||
166 | if( StringUtils.isBlank(script_path) || StringUtils.isBlank(script_function)) {
|
||
167 | throw new ExpressionRuntimeException("Requiered module and function name."); |
||
168 | } |
||
169 | fn = new ExternalFunction(name, script_path, script_function);
|
||
170 | symbolTable.addFunction(fn); |
||
171 | break;
|
||
172 | } |
||
173 | return fn;
|
||
174 | 43512 | jjdelcerro | } |
175 | |||
176 | 44138 | jjdelcerro | private static class UserFunction extends AbstractFunction { |
177 | |||
178 | private final Code body; |
||
179 | private final List<String> argNames; |
||
180 | |||
181 | public UserFunction(String name, List<String> argNames, Code body) { |
||
182 | super(GROUP_OTHER, name, Range.between(0, Integer.MAX_VALUE)); |
||
183 | this.argNames = argNames;
|
||
184 | this.body = body;
|
||
185 | } |
||
186 | 44738 | jjdelcerro | |
187 | 44138 | jjdelcerro | @Override
|
188 | public Object call(Interpreter interpreter, Object[] args) throws Exception { |
||
189 | Object value;
|
||
190 | ExpressionEvaluatorManager manager = ExpressionEvaluatorLocator.getManager(); |
||
191 | MutableSymbolTable localSymbolTable = manager.createSymbolTable(); |
||
192 | 44389 | jjdelcerro | |
193 | List $args = new ArrayList(); |
||
194 | if( args != null ) { |
||
195 | $args.addAll(Arrays.asList(args)); |
||
196 | } |
||
197 | localSymbolTable.setVar("$ARGS", $args); |
||
198 | |||
199 | 44138 | jjdelcerro | int max;
|
200 | if( this.argNames==null ) { |
||
201 | max = 0;
|
||
202 | } else {
|
||
203 | max = Math.min(this.argNames.size(), args.length); |
||
204 | } |
||
205 | for (int i = 0; i < max; i++) { |
||
206 | localSymbolTable.setVar(this.argNames.get(i), args[i]);
|
||
207 | } |
||
208 | SymbolTable savedSymbolTable = interpreter.getSymbolTable(); |
||
209 | localSymbolTable.addSymbolTable(savedSymbolTable); |
||
210 | try {
|
||
211 | interpreter.setSymbolTable(localSymbolTable); |
||
212 | value = interpreter.run(this.body);
|
||
213 | } finally {
|
||
214 | interpreter.setSymbolTable(savedSymbolTable); |
||
215 | } |
||
216 | return value;
|
||
217 | } |
||
218 | |||
219 | } |
||
220 | |||
221 | 44533 | jjdelcerro | private static class ExternalFunction extends AbstractFunction { |
222 | |||
223 | private final String script_path; |
||
224 | private final String script_function; |
||
225 | 44592 | jjdelcerro | private final Script script; |
226 | 44533 | jjdelcerro | |
227 | public ExternalFunction(String name, String script_path, String script_function) { |
||
228 | super(GROUP_OTHER, name, Range.between(0, Integer.MAX_VALUE)); |
||
229 | this.script_path = script_path;
|
||
230 | this.script_function = script_function;
|
||
231 | ScriptManager scriptManager = ToolsLocator.getScriptManager(); |
||
232 | ExpressionEvaluatorManager expressionManager = ExpressionEvaluatorLocator.getExpressionEvaluatorManager(); |
||
233 | ResourcesStorage resourcesStorage = expressionManager.getScriptsResourcesStorage(); |
||
234 | 44592 | jjdelcerro | this.script = scriptManager.loadScript(resourcesStorage, script_path);
|
235 | if( this.script == null ) { |
||
236 | 44533 | jjdelcerro | throw new ExpressionRuntimeException("Can't locate '"+this.script_path+"'."); |
237 | } |
||
238 | 44592 | jjdelcerro | } |
239 | |||
240 | @Override
|
||
241 | public Object call(Interpreter interpreter, Object[] args) throws Exception { |
||
242 | Object r = this.script.invokeFunction(this.script_function, args); |
||
243 | 44533 | jjdelcerro | return r;
|
244 | } |
||
245 | |||
246 | } |
||
247 | |||
248 | private static class JavaFunction extends AbstractFunction { |
||
249 | |||
250 | private final String fullClassName; |
||
251 | private final String methodName; |
||
252 | |||
253 | public JavaFunction(String name, String fullClassName, String methodName) { |
||
254 | super(GROUP_OTHER, name, Range.between(0, Integer.MAX_VALUE)); |
||
255 | this.fullClassName = fullClassName;
|
||
256 | this.methodName = methodName;
|
||
257 | } |
||
258 | |||
259 | @Override
|
||
260 | public Object call(Interpreter interpreter, Object[] args) throws Exception { |
||
261 | 44750 | jjdelcerro | List<ClassLoader> loaders = ExpressionEvaluatorLocator.getManager().getClassLoaders(); |
262 | Class<?> theClass = null; |
||
263 | for (ClassLoader loader : loaders) { |
||
264 | try {
|
||
265 | theClass = loader.loadClass(this.fullClassName);
|
||
266 | if( theClass!=null ) { |
||
267 | break;
|
||
268 | } |
||
269 | } catch(Throwable th) { |
||
270 | // Do nothing skip
|
||
271 | } |
||
272 | } |
||
273 | if( theClass == null ) { |
||
274 | throw new ExpressionRuntimeException("Can't localte the class '"+this.fullClassName+"'."); |
||
275 | } |
||
276 | 44533 | jjdelcerro | Class[] parameterTypes = new Class[args.length]; |
277 | for (int i = 0; i < args.length; i++) { |
||
278 | if( args[i]==null ) { |
||
279 | parameterTypes[i] = null;
|
||
280 | } else {
|
||
281 | parameterTypes[i] = args[i].getClass(); |
||
282 | } |
||
283 | } |
||
284 | Method method = theClass.getMethod(this.methodName, parameterTypes); |
||
285 | Object value = method.invoke(null, args); |
||
286 | return value;
|
||
287 | } |
||
288 | |||
289 | } |
||
290 | |||
291 | 43512 | jjdelcerro | } |