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

History | View | Annotate | Download (9.84 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
public class CreateFnFunction extends AbstractFunction {
25
    
26
    public static final String NAME = "CREATE_FUNCTION";
27

    
28
    public CreateFnFunction() {
29
        super(Function.GROUP_PROGRAMMING, 
30
                NAME, 
31
                Range.between(2, 6),
32
                "This function allows you to define functions within the expression evaluator.\n" +
33
                  "We can define three types of functions:\n" +
34
                  "\n<ul>" +
35
                  "<li>Functions defined in the evaluator itself.</li>\n" +
36
                  "<li>Functions implemented as a static method of a java class.</li>\n" +
37
                  "<li>Functions defined in an external script.</li>\n" +
38
                  "\n</ul>" +
39
                  "<b> Functions defined in the evaluator itself. </b>\n" +
40
                  "\n" +
41
                  "They have the form:\n" +
42
                  "\n" +
43
                  "<pre>\n" +
44
                  "CREATE PROCEDURE myfun param1 AS\n" +
45
                  "BEGIN\n" +
46
                  "  RETURN 'Hello' || param1;\n" +
47
                  "END PROCEDURE\n" +
48
                  "</pre>\n" +
49
                  "\n" +
50
                  "<b> Functions implemented as a static method </b>\n" +
51
                  "\n" +
52
                  "They allow defining a function that will invoke a static method of a java class.\n" +
53
                  "\n" +
54
                  "They have the form:\n" +
55
                  "\n" +
56
                  "<pre>\n" +
57
                  "CREATE FUNCTION getCRS (crs) AS 'org.gvsig.fmap.crs.CRSFactory', 'getCRS' LANGUAGE 'java'\n" +
58
                  "</pre>\n" +
59
                  "\n" +
60
                  "Defines the \"getCRS\" function that receives a single parameter, and links it to the method\n" +
61
                  "static 'getCRS' of class 'org.gvsig.fmap.crs.CRSFactory',\n" +
62
                  "\n" +
63
                  "<b> Functions defined in an external script. </b>\n" +
64
                  "\n" +
65
                  "It allows defining functions that are implemented in an external script module.\n" +
66
                  "\n" +
67
                  "They have the form:\n" +
68
                  "\n" +
69
                  "<pre>\n" +
70
                  "CREATE FUNCTION getCRS (crs) AS 'scripts / crs.py', 'getCRS' LANGUAGE 'python'\n" +
71
                  "</pre>\n" +
72
                  "\n" +
73
                  "What defines a \"getCRS\" function that is implemented in the python module\n" +
74
                  "located in \"Users / crs\" with the name 'getCRS'.",
75
                null,
76
                null,
77
                "Object",
78
                false
79
        );
80
    }
81

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

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

    
97
    @Override
98
    public boolean allowArgNames() {
99
      return true;
100
    }
101
    
102
    @Override
103
    public Object call(Interpreter interpreter, Object[] args) throws Exception {
104
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
105
    }
106
    
107
    @Override
108
    public Object call(Interpreter interpreter, Codes args) throws Exception {
109
        if( !(interpreter.getSymbolTable() instanceof MutableSymbolTable) ) {
110
            throw new ExpressionRuntimeException("The use of user functions require a mutable symbol table.");
111
        }
112
        MutableSymbolTable symbolTable = (MutableSymbolTable) interpreter.getSymbolTable();
113
        
114
        String name = (String) getObject(interpreter, args, "FUNCTION_NAME");
115
        List<String> argNames = (List<String>) getObject(interpreter, args, "PARAMETERS");
116
        Code body = args.get("BODY");
117
        String script_path = (String) getObject(interpreter, args, "SCRIPT_PATH");
118
        String script_function = (String) getObject(interpreter, args, "SCRIPT_FUNCTION");
119
        String language = (String) getObject(interpreter, args, "LANGUAGE");
120
        Function fn;
121
        if( body!=null ) {
122
            fn = new UserFunction(name, argNames, body);
123
            symbolTable.addFunction(fn);
124
            return fn;
125
        }
126
        if( StringUtils.isBlank(script_path) || StringUtils.isBlank(script_function) ) {
127
            throw new ExpressionRuntimeException("boydy and, script path or script function, are empty.");
128
        }
129
        if( StringUtils.isBlank(language) ) {
130
            language = "script";
131
        }
132
        switch(language.toLowerCase()) {
133
            case "script":
134
                fn = new ExternalFunction(name, script_path, script_function);
135
                symbolTable.addFunction(fn);
136
                return fn;
137
            case "java":
138
                fn = new JavaFunction(name, script_path, script_function);
139
                symbolTable.addFunction(fn);
140
                return fn;
141
        }
142
        throw new ExpressionRuntimeException("Unsupported language '"+language+".");
143
    }
144
    
145
    private static class UserFunction extends AbstractFunction {
146

    
147
        private final Code body;
148
        private final List<String> argNames;
149

    
150
        public UserFunction(String name, List<String> argNames, Code body) {
151
            super(GROUP_OTHER, name, Range.between(0, Integer.MAX_VALUE));
152
            this.argNames = argNames;
153
            this.body = body;
154
        }
155

    
156
        @Override
157
        public boolean allowArgNames() {
158
          return true;
159
        }
160

    
161
        @Override
162
        public Object call(Interpreter interpreter, Object[] args) throws Exception {
163
            Object value;
164
            ExpressionEvaluatorManager manager = ExpressionEvaluatorLocator.getManager();
165
            MutableSymbolTable localSymbolTable = manager.createSymbolTable();
166
            
167
            List $args = new ArrayList();
168
            if( args != null ) {
169
                $args.addAll(Arrays.asList(args));
170
            }
171
            localSymbolTable.setVar("$ARGS", $args);
172
            
173
            int max;
174
            if( this.argNames==null ) {
175
                max = 0;
176
            } else {
177
                max = Math.min(this.argNames.size(), args.length);
178
            }
179
            for (int i = 0; i < max; i++) {
180
                localSymbolTable.setVar(this.argNames.get(i), args[i]);
181
            }
182
            SymbolTable savedSymbolTable = interpreter.getSymbolTable();
183
            localSymbolTable.addSymbolTable(savedSymbolTable);
184
            try {
185
                interpreter.setSymbolTable(localSymbolTable);
186
                value = interpreter.run(this.body);
187
            } finally {
188
                interpreter.setSymbolTable(savedSymbolTable);
189
            }
190
            return value;
191
        }
192
        
193
    }
194
    
195
    private static class ExternalFunction extends AbstractFunction {
196

    
197
        private final String script_path;
198
        private final String script_function;
199
        private final Script script;
200

    
201
        public ExternalFunction(String name, String script_path, String script_function) {
202
            super(GROUP_OTHER, name, Range.between(0, Integer.MAX_VALUE));
203
            this.script_path = script_path;
204
            this.script_function = script_function;
205
            ScriptManager scriptManager = ToolsLocator.getScriptManager();
206
            ExpressionEvaluatorManager expressionManager = ExpressionEvaluatorLocator.getExpressionEvaluatorManager();
207
            ResourcesStorage resourcesStorage = expressionManager.getScriptsResourcesStorage();
208
            this.script = scriptManager.loadScript(resourcesStorage, script_path);
209
            if( this.script == null ) {
210
                throw new ExpressionRuntimeException("Can't locate '"+this.script_path+"'.");
211
            }
212
        }
213
        
214
        @Override
215
        public Object call(Interpreter interpreter, Object[] args) throws Exception {
216
            Object r = this.script.invokeFunction(this.script_function, args);
217
            return r;
218
        }
219
        
220
    }
221

    
222
    private static class JavaFunction extends AbstractFunction {
223

    
224
        private final String fullClassName;
225
        private final String methodName;
226

    
227
        public JavaFunction(String name, String fullClassName, String methodName) {
228
            super(GROUP_OTHER, name, Range.between(0, Integer.MAX_VALUE));
229
            this.fullClassName = fullClassName;
230
            this.methodName = methodName;
231
        }
232
        
233
        @Override
234
        public Object call(Interpreter interpreter, Object[] args) throws Exception {
235
            Class[] parameterTypes = new Class[args.length];
236
            for (int i = 0; i < args.length; i++) {
237
                if( args[i]==null ) {
238
                    parameterTypes[i] = null;
239
                } else {
240
                    parameterTypes[i] = args[i].getClass();
241
                }
242
            }
243
            Class<?> theClass = Class.forName(this.fullClassName);
244
            Method method = theClass.getMethod(this.methodName, parameterTypes);
245
            Object value = method.invoke(null, args);
246
            return value;
247
        }
248
        
249
    }
250

    
251
}