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 @ 44750

History | View | Annotate | Download (11.2 KB)

1
package org.gvsig.expressionevaluator.impl.function.programming;
2

    
3
import java.lang.reflect.Method;
4
import java.util.ArrayList;
5
import java.util.Arrays;
6
import java.util.List;
7
import org.apache.commons.lang3.Range;
8
import org.apache.commons.lang3.StringUtils;
9
import org.gvsig.expressionevaluator.Code;
10
import org.gvsig.expressionevaluator.Codes;
11
import org.gvsig.expressionevaluator.Function;
12
import org.gvsig.expressionevaluator.Interpreter;
13
import org.gvsig.expressionevaluator.spi.AbstractFunction;
14
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
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

    
24
@SuppressWarnings("UseSpecificCatch")
25
public class CreateFnFunction extends AbstractFunction {
26
    
27
    public static final String NAME = "CREATE_FUNCTION";
28

    
29
    public CreateFnFunction() {
30
        super(Function.GROUP_PROGRAMMING, 
31
                NAME, 
32
                Range.between(2, 6),
33
                "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
                  "CREATE FUNCTION parseInt(value) AS 'java.lang.Integer', 'parseInt' LANGUAGE 'java'\n" +
59
                  "</pre>\n" +
60
                  "\n" +
61
                  "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
                  "\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
                  "CREATE FUNCTION getCRS(crs) AS 'crs.py', 'getCRS' LANGUAGE 'script'\n" +
72
                  "</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
                null,
77
                null,
78
                "Object",
79
                false
80
        );
81
    }
82

    
83
    @Override
84
    public boolean isHidden() {
85
      return false; 
86
    }
87
    
88
    @Override
89
    public boolean useArgumentsInsteadObjects() {
90
        return true;
91
    }
92

    
93
    @Override
94
    public boolean allowConstantFolding() {
95
        return false;
96
    }
97

    
98
    @Override
99
    public Object call(Interpreter interpreter, Object[] args) throws Exception {
100
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
101
    }
102
    
103
    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
    @Override
115
    public Object call(Interpreter interpreter, Codes args) throws Exception {
116
        if( !(interpreter.getSymbolTable() instanceof MutableSymbolTable) ) {
117
            throw new ExpressionRuntimeException("The use of user functions require a mutable symbol table.");
118
        }
119
        MutableSymbolTable symbolTable = (MutableSymbolTable) interpreter.getSymbolTable();
120
        
121
        String name = (String) getObject(interpreter, args, FUNCTION_NAME);
122
        List<String> argNames = (List<String>) getObject(interpreter, args, PARAMETERS);
123
        Code body = args.get(BODY);
124
        String script_path = (String) getObject(interpreter, args, SCRIPT_PATH);
125
        String script_function = (String) getObject(interpreter, args, SCRIPT_FUNCTION);
126
        String language = (String) getObject(interpreter, args, LANGUAGE);
127
        
128
        if( StringUtils.isBlank(language) ) {
129
            language = "script";
130
        }
131

    
132
        int type = TYPE_USER_FUNCTION;
133
        if( !StringUtils.isBlank(script_path) || !StringUtils.isBlank(script_function))  {
134
          switch(language.toLowerCase()) {
135
              case "script":
136
                type = TYPE_SCRIPT_FUNCTION;
137
                break;
138
              case "java":
139
                type = TYPE_JAVA_FUNCTION;
140
                break;
141
              default:
142
                throw new ExpressionRuntimeException("Unsupported language '"+language+".");
143
          }
144
        }
145
        Function fn = null;
146
        switch(type) {
147
          case TYPE_USER_FUNCTION:
148
            fn = new UserFunction(name, argNames, body);
149
            symbolTable.addFunction(fn);
150
            break;
151
          case TYPE_JAVA_FUNCTION:
152
            if( StringUtils.isBlank(script_path) || StringUtils.isBlank(script_function))  {
153
                throw new ExpressionRuntimeException("Requiered classname and methodname.");
154
            }
155
            fn = new JavaFunction(name, script_path, script_function);
156
            symbolTable.addFunction(fn);
157
            break;
158
          case TYPE_SCRIPT_FUNCTION:
159
            if( StringUtils.isBlank(script_path) || StringUtils.isBlank(script_function))  {
160
                throw new ExpressionRuntimeException("Requiered module and function name.");
161
            }
162
            fn = new ExternalFunction(name, script_path, script_function);
163
            symbolTable.addFunction(fn);
164
            break;
165
        }
166
        return fn;
167
    }
168
    
169
    private static class UserFunction extends AbstractFunction {
170

    
171
        private final Code body;
172
        private final List<String> argNames;
173

    
174
        public UserFunction(String name, List<String> argNames, Code body) {
175
            super(GROUP_OTHER, name, Range.between(0, Integer.MAX_VALUE));
176
            this.argNames = argNames;
177
            this.body = body;
178
        }
179

    
180
        @Override
181
        public Object call(Interpreter interpreter, Object[] args) throws Exception {
182
            Object value;
183
            ExpressionEvaluatorManager manager = ExpressionEvaluatorLocator.getManager();
184
            MutableSymbolTable localSymbolTable = manager.createSymbolTable();
185
            
186
            List $args = new ArrayList();
187
            if( args != null ) {
188
                $args.addAll(Arrays.asList(args));
189
            }
190
            localSymbolTable.setVar("$ARGS", $args);
191
            
192
            int max;
193
            if( this.argNames==null ) {
194
                max = 0;
195
            } else {
196
                max = Math.min(this.argNames.size(), args.length);
197
            }
198
            for (int i = 0; i < max; i++) {
199
                localSymbolTable.setVar(this.argNames.get(i), args[i]);
200
            }
201
            SymbolTable savedSymbolTable = interpreter.getSymbolTable();
202
            localSymbolTable.addSymbolTable(savedSymbolTable);
203
            try {
204
                interpreter.setSymbolTable(localSymbolTable);
205
                value = interpreter.run(this.body);
206
            } finally {
207
                interpreter.setSymbolTable(savedSymbolTable);
208
            }
209
            return value;
210
        }
211
        
212
    }
213
    
214
    private static class ExternalFunction extends AbstractFunction {
215

    
216
        private final String script_path;
217
        private final String script_function;
218
        private final Script script;
219

    
220
        public ExternalFunction(String name, String script_path, String script_function) {
221
            super(GROUP_OTHER, name, Range.between(0, Integer.MAX_VALUE));
222
            this.script_path = script_path;
223
            this.script_function = script_function;
224
            ScriptManager scriptManager = ToolsLocator.getScriptManager();
225
            ExpressionEvaluatorManager expressionManager = ExpressionEvaluatorLocator.getExpressionEvaluatorManager();
226
            ResourcesStorage resourcesStorage = expressionManager.getScriptsResourcesStorage();
227
            this.script = scriptManager.loadScript(resourcesStorage, script_path);
228
            if( this.script == null ) {
229
                throw new ExpressionRuntimeException("Can't locate '"+this.script_path+"'.");
230
            }
231
        }
232
        
233
        @Override
234
        public Object call(Interpreter interpreter, Object[] args) throws Exception {
235
            Object r = this.script.invokeFunction(this.script_function, args);
236
            return r;
237
        }
238
        
239
    }
240

    
241
    private static class JavaFunction extends AbstractFunction {
242

    
243
        private final String fullClassName;
244
        private final String methodName;
245

    
246
        public JavaFunction(String name, String fullClassName, String methodName) {
247
            super(GROUP_OTHER, name, Range.between(0, Integer.MAX_VALUE));
248
            this.fullClassName = fullClassName;
249
            this.methodName = methodName;
250
        }
251
        
252
        @Override
253
        public Object call(Interpreter interpreter, Object[] args) throws Exception {
254
            List<ClassLoader> loaders = ExpressionEvaluatorLocator.getManager().getClassLoaders();
255
            Class<?> theClass = null;
256
            for (ClassLoader loader : loaders) {
257
              try {
258
                theClass = loader.loadClass(this.fullClassName);
259
                if( theClass!=null ) {
260
                  break;
261
                }
262
              } catch(Throwable th) {
263
                // Do nothing skip
264
              }
265
            }
266
            if( theClass == null ) {
267
              throw new ExpressionRuntimeException("Can't localte the class '"+this.fullClassName+"'.");
268
            }
269
            Class[] parameterTypes = new Class[args.length];
270
            for (int i = 0; i < args.length; i++) {
271
                if( args[i]==null ) {
272
                    parameterTypes[i] = null;
273
                } else {
274
                    parameterTypes[i] = args[i].getClass();
275
                }
276
            }
277
            Method method = theClass.getMethod(this.methodName, parameterTypes);
278
            Object value = method.invoke(null, args);
279
            return value;
280
        }
281
        
282
    }
283

    
284
}