Statistics
| Revision:

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
}