Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.library / org.gvsig.expressionevaluator / org.gvsig.expressionevaluator.lib / org.gvsig.expressionevaluator.lib.api / src / main / java / org / gvsig / expressionevaluator / spi / AbstractFunction.java @ 44924

History | View | Annotate | Download (20 KB)

1
package org.gvsig.expressionevaluator.spi;
2

    
3
import java.io.File;
4
import java.io.InputStream;
5
import java.net.URI;
6
import java.net.URISyntaxException;
7
import java.net.URL;
8
import java.time.LocalDateTime;
9
import java.time.ZoneId;
10
import java.time.temporal.TemporalAccessor;
11
import java.util.ArrayList;
12
import java.util.Date;
13
import java.util.List;
14
import java.util.Locale;
15
import java.util.Objects;
16
import org.apache.commons.io.IOUtils;
17
import org.apache.commons.lang3.BooleanUtils;
18
import org.apache.commons.lang3.Range;
19
import org.apache.commons.lang3.StringUtils;
20
import org.apache.commons.math.util.MathUtils;
21
import org.gvsig.expressionevaluator.Code;
22
import org.gvsig.expressionevaluator.Codes;
23
import org.gvsig.expressionevaluator.Function;
24
import org.gvsig.expressionevaluator.I18N;
25
import org.gvsig.expressionevaluator.Interpreter;
26
import org.gvsig.tools.ToolsLocator;
27
import org.gvsig.tools.i18n.I18nManager;
28
//import org.gvsig.fmap.geom.Geometry;
29
//import org.gvsig.fmap.geom.primitive.Point;
30
import org.json.JSONArray;
31
import org.json.JSONObject;
32

    
33
@SuppressWarnings("UseSpecificCatch")
34
public abstract class AbstractFunction implements Function {
35
 
36
    private final String name;
37
    private String group;
38
    private Range argc;
39
    private String description;
40
    private String[] descriptionArgs;
41
    private List<String> alias;
42
    private String template;
43
    private String returnType;
44
    private boolean sqlCompatible;
45

    
46
    protected AbstractFunction(String group, String name, Range argc, String description, String template, String[] descriptionArgs, String returnType, boolean sqlCompatible) {
47
        this.name = name;
48
        this.group = group;
49
        this.argc = argc;
50
        this.description = description;
51
        this.template = template;
52
        this.descriptionArgs = descriptionArgs;
53
        this.returnType = returnType;
54
        this.sqlCompatible = sqlCompatible;
55
        load_from_resource();
56
    }
57
    protected AbstractFunction(String group, String name, Range argc, String description, String template, String[] descriptionArgs, String returnType) {
58
        this(group, name, argc, description, template, descriptionArgs, returnType, false);
59
    }
60
    
61
    protected AbstractFunction(String group, String name, Range argc, String description, String template, String[] descriptionArgs) {
62
        this(group, name, argc, description, template, null, null);
63
    }
64

    
65
    protected AbstractFunction(String group, String name, Range argc, String description, String template) {
66
        this(group, name, argc, description, template, null, null);
67
    }
68

    
69
    protected AbstractFunction(String group, String name, Range argc) {
70
        this(group, name, argc, null, null, null, null);
71
    }
72

    
73
    @Override
74
    public String name() {
75
        return this.name;
76
    }
77

    
78
    @Override
79
    public String returnType() {
80
        return this.returnType;
81
    }
82

    
83
    @Override
84
    public String group() {
85
        return this.group;
86
    }
87

    
88
    @Override
89
    public Range argc() {
90
        return argc;
91
    }
92

    
93
    @Override
94
    public String description() {
95
        if( StringUtils.equalsIgnoreCase(System.getProperty("ExpressionEvaluatorReloadFunctionResources"), "true")) {
96
            load_from_resource();
97
        }
98
        return description;
99
    }
100

    
101
    @Override
102
    public String[] descriptionArgs() {
103
        return descriptionArgs;
104
    }
105

    
106
    public String getFullDescription() {
107
        I18nManager i18n = ToolsLocator.getI18nManager();
108

    
109
        StringBuilder html = new StringBuilder();
110
        html.append("<html>\n");
111

    
112
        // Lo primero llamamos a description() para forzar la recarga de los
113
        // recursos si fuese necesaria.
114
        String functionDescription = this.description();
115

    
116
        html.append("<b>").append(i18n.getTranslation("_Function")).append("</b> ").append(this.name()).append("<br>\n<br>\n");
117
        List<String> aliases = this.aliases();
118
        if( aliases!=null && !aliases.isEmpty() ) {
119
            html.append("<b>").append(i18n.getTranslation("_Aliases")).append(":</b> ").append("<ul>\n");
120
            for (String theAlias : aliases) {
121
                html.append("<li>").append(theAlias).append("</li>\n");
122
            }
123
            html.append("</ul>\n");
124
        }
125
        html.append("<b>").append(i18n.getTranslation("_Return")).append("</b> ");
126
        html.append(StringUtils.isEmpty(this.returnType()) ? "Objec" : this.returnType());
127
        html.append("<br>\n");
128
        html.append("<b>").append(i18n.getTranslation("_Template")).append("</b> ");
129
        html.append(StringUtils.isEmpty(this.template()) ? this.name() + "()" : this.template());
130
        html.append("<br>\n");
131

    
132
        String[] args = this.descriptionArgs();
133
        if (args != null) {
134
            html.append("<b>").append(i18n.getTranslation("_Arguments")).append(":</b> ").append("<ul>\n");
135
            for (String arg : args) {
136
                html.append("<li>").append(arg).append("</li>\n");
137
            }
138
            html.append("</ul>\n");
139
            html.append("<br>\n");
140
        }
141
        if( !StringUtils.isBlank(functionDescription) ) {
142
            html.append("<b>").append(i18n.getTranslation("_Description")).append("</b><br>\n");
143
            html.append(functionDescription.replace("\n", "<br>")).append("<br>\n");
144
        }            
145

    
146
        html.append("</html>\n");
147
        return html.toString();
148
    }
149

    
150
    @Override
151
    public void addAlias(String name) {
152
        if( StringUtils.isBlank(name) ) {
153
            return;
154
        }
155
        if( this.alias == null ) {
156
            this.alias = new ArrayList<>();
157
        }
158
        if( this.alias.contains(name) ) {
159
            return;
160
        }
161
        this.alias.add(name);
162
    }
163

    
164
    @Override
165
    public List<String> aliases() {
166
        return this.alias;
167
    }
168

    
169
    @Override
170
    public String template() {
171
        return this.template;
172
    }
173

    
174
    @Override
175
    public boolean isOperator() {
176
        return false;
177
    }
178

    
179
    @Override
180
    public boolean isHidden() {
181
      return false;
182
    }
183
    
184
    @Override
185
    public boolean useArgumentsInsteadObjects() {
186
        return false;
187
    }
188

    
189
    @Override
190
    public boolean isSQLCompatible() {
191
        return sqlCompatible;
192
    }
193

    
194
    @Override
195
    public boolean allowConstantFolding() {
196
        return false;
197
    }
198

    
199
    @Override
200
    public Object call(Interpreter interpreter, Codes args) throws Exception {
201
        return null;
202
    }
203
    
204
    protected int getInt(Object args[], int n) {
205
        if( args.length < n  ) {
206
            throw new IllegalArgumentException(I18N.Required_argument_XargnX_and_only_found_XargcX_in_call_to_XIdentifierX(name(), args.length, n));
207
        }
208
        return getInt(args[n],n);
209
    }
210

    
211
    protected int getInt(Object value, int n) {
212
        if( value == null ) {
213
            throw new IllegalArgumentException(I18N.Illegal_null_value_for_argument_XargnX_of_XIdentifierX_function(name(), n));
214
        }
215
        if( !(value instanceof Number) ) {
216
            String type = value.getClass().getCanonicalName();
217
            throw new IllegalArgumentException(
218
                    I18N.The_type_of_the_argument_XargnX_for_the_XIdentifierX_function_is_incorrect(name(), n) + " " +
219
                    I18N.Expected_XexpectedX_and_found_XfoundX("Number",type)
220
            );
221
        }
222
        return ((Number)value).intValue();
223
    }
224

    
225
    protected long getLong(Object args[], int n) {
226
        if( args.length < n  ) {
227
            throw new IllegalArgumentException(I18N.Required_argument_XargnX_and_only_found_XargcX_in_call_to_XIdentifierX(name(), args.length, n));
228
        }
229
        return getLong(args[n],n);
230
    }
231

    
232
    protected long getLong(Object value, int n) {
233
        if( value == null ) {
234
            throw new IllegalArgumentException(I18N.Illegal_null_value_for_argument_XargnX_of_XIdentifierX_function(name(), n));
235
        }
236
        if( !(value instanceof Number) ) {
237
            String type = value.getClass().getCanonicalName();
238
            throw new IllegalArgumentException(
239
                    I18N.The_type_of_the_argument_XargnX_for_the_XIdentifierX_function_is_incorrect(name(), n) + " " +
240
                    I18N.Expected_XexpectedX_and_found_XfoundX("Number",type)
241
            );
242
        }
243
        return ((Number)value).longValue();
244
    }
245

    
246
    protected double getDouble(Object args[], int n) {
247
        if( args.length < n  ) {
248
            throw new IllegalArgumentException(I18N.Required_argument_XargnX_and_only_found_XargcX_in_call_to_XIdentifierX(name(), args.length, n));
249
        }
250
        return getDouble(args[n],n);
251
    }
252

    
253
    protected double getDouble(Object value, int arg) {
254
        if( value == null ) {
255
            throw new IllegalArgumentException(I18N.Illegal_null_value_for_argument_XargnX_of_XIdentifierX_function(name(), arg));
256
        }
257
        if( !(value instanceof Number) ) {
258
            String type = value.getClass().getCanonicalName();
259
            throw new IllegalArgumentException(
260
                    I18N.The_type_of_the_argument_XargnX_for_the_XIdentifierX_function_is_incorrect(name(), arg) + " " +
261
                    I18N.Expected_XexpectedX_and_found_XfoundX("Number",type)
262
            );
263
        }
264
        return ((Number)value).doubleValue();
265
    }
266
    
267
    protected float getFloat(Object args[], int n) {
268
        if( args.length < n  ) {
269
            throw new IllegalArgumentException(I18N.Required_argument_XargnX_and_only_found_XargcX_in_call_to_XIdentifierX(name(), args.length, n));
270
        }
271
        return getFloat(args[n],n);
272
    }
273

    
274
    protected float getFloat(Object value, int arg) {
275
        if( value == null ) {
276
            throw new IllegalArgumentException(I18N.Illegal_null_value_for_argument_XargnX_of_XIdentifierX_function(name(), arg));
277
        }
278
        if( !(value instanceof Number) ) {
279
            String type = value.getClass().getCanonicalName();
280
            throw new IllegalArgumentException(
281
                    I18N.The_type_of_the_argument_XargnX_for_the_XIdentifierX_function_is_incorrect(name(), arg) + " " +
282
                    I18N.Expected_XexpectedX_and_found_XfoundX("Number",type)
283
            );
284
        }
285
        return ((Number)value).floatValue();
286
    }
287
    
288
    protected String getStr(Object args[], int n) {
289
        if( args.length < n  ) {
290
            throw new IllegalArgumentException(I18N.Required_argument_XargnX_and_only_found_XargcX_in_call_to_XIdentifierX(name(), args.length, n));
291
        }
292
        return getStr(args[n],n);
293
    }
294
    
295
    protected String getStr(Object value, int n) {
296
        return Objects.toString(value, "");
297
    }
298
    
299
    protected File getFile(Object args[], int n) {
300
        if( args.length < n  ) {
301
            throw new IllegalArgumentException(I18N.Required_argument_XargnX_and_only_found_XargcX_in_call_to_XIdentifierX(name(), args.length, n));
302
        }
303
        return getFile(args[n],n);
304
    }
305
    
306
    protected File getFile(Object value, int n) {
307
        if( value == null ) {
308
            return null;
309
        }
310
        if( value instanceof File ) {
311
            return (File)value;
312
        }
313
        if( value instanceof URL ) {
314
            try {
315
                return new File(((URL)value).toURI());
316
            } catch (URISyntaxException ex) {
317
                return null;
318
            }
319
        }
320
        if( value instanceof URI ) {
321
            return new File(((URI)value));
322
        }
323
        String s = Objects.toString(value, null);
324
        if( s == null ) {
325
            return null;
326
        }
327
        File f = new File(s);
328
        return f;
329
    }
330
    
331
    protected Object getObject(Object args[], int n) {
332
        if( args.length < n  ) {
333
            throw new IllegalArgumentException(I18N.Required_argument_XargnX_and_only_found_XargcX_in_call_to_XIdentifierX(name(), args.length, n));
334
        }
335
        return args[n];
336
    }
337
    
338
    protected Object getObject(Interpreter interpreter, Codes args, int n) {
339
        if( args.size() < n  ) {
340
            throw new IllegalArgumentException(I18N.Required_argument_XargnX_and_only_found_XargcX_in_call_to_XIdentifierX(name(), args.size(), n));
341
        }
342
        Code arg = args.get(n);
343
        if( arg==null ) {
344
            return null;
345
        }
346
        Object value = interpreter.run(arg);
347
        return value;
348
    }
349
    
350
    protected Comparable getComparable(Object[] args, int n) {
351
        if( args.length < n  ) {
352
            throw new IllegalArgumentException(I18N.Required_argument_XargnX_and_only_found_XargcX_in_call_to_XIdentifierX(name(), args.length, n));
353
        }
354
        return getComparable(args[n],n);
355
    }
356
    
357
    protected Comparable getComparable(Object value, int n) {
358
        if( value == null ) {
359
            return null;
360
        }
361
        if( !(value instanceof Comparable) ) {
362
            String type = value.getClass().getCanonicalName();
363
            throw new IllegalArgumentException(
364
                    I18N.The_type_of_the_argument_XargnX_for_the_XIdentifierX_function_is_incorrect(name(), n) + " " +
365
                    I18N.Expected_XexpectedX_and_found_XfoundX("Comparable",type)
366
            );
367
        }
368
        return (Comparable)value;
369
    }
370

    
371
    protected Comparable getDate(Object[] args, int n) {
372
        if( args.length < n  ) {
373
            throw new IllegalArgumentException(I18N.Required_argument_XargnX_and_only_found_XargcX_in_call_to_XIdentifierX(name(), args.length, n));
374
        }
375
        return getDate(args[n],n);
376
    }
377
    
378
    protected Date getDate(Object value, int n) {
379
        if( value == null ) {
380
            return null;
381
        }
382
        if( !(value instanceof Date) ) {
383
            String type = value.getClass().getCanonicalName();
384
            throw new IllegalArgumentException(
385
                    I18N.The_type_of_the_argument_XargnX_for_the_XIdentifierX_function_is_incorrect(name(), n) + " " +
386
                    I18N.Expected_XexpectedX_and_found_XfoundX("Date",type)
387
            );
388
        }
389
        return (Date)value;
390
    }
391
    
392
    protected LocalDateTime getLocalDateTime(Object[] args, int n) {
393
        if( args.length < n  ) {
394
            throw new IllegalArgumentException(I18N.Required_argument_XargnX_and_only_found_XargcX_in_call_to_XIdentifierX(name(), args.length, n));
395
        }
396
        return getLocalDateTime(args[n],n);
397
    }
398
    
399
    protected LocalDateTime getLocalDateTime(Object value, int n) {
400
        if( value == null ) {
401
            return null;
402
        }
403
        if( value instanceof Date ) {
404
            Date date = ((Date)value);
405
            return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
406
        }
407
        if( value instanceof LocalDateTime ) {
408
            return (LocalDateTime) value;
409
        }
410
        if( value instanceof TemporalAccessor ) {
411
            return LocalDateTime.from(((TemporalAccessor)value));
412
        }
413
        String type = value.getClass().getCanonicalName();
414
        throw new IllegalArgumentException(
415
                I18N.The_type_of_the_argument_XargnX_for_the_XIdentifierX_function_is_incorrect(name(), n) + " " +
416
                I18N.Expected_XexpectedX_and_found_XfoundX("Temporal/Date",type)
417
        );
418
    }
419
    
420
    protected boolean getBoolean(Object args[], int n, Double accuracy) {
421
        if( args.length < n  ) {
422
            throw new IllegalArgumentException(I18N.Required_argument_XargnX_and_only_found_XargcX_in_call_to_XIdentifierX(name(), args.length, n));
423
        }
424
        return getBoolean(args[n], n, accuracy);
425
    }
426

    
427
    protected boolean getBoolean(Object value, int n) {
428
        return getBoolean(value, n, MathUtils.EPSILON);
429
    }
430

    
431
    protected boolean getBoolean(Object value, int n, Double accuracy) {
432
        return toBoolean(value, accuracy);
433
    }
434

    
435
    protected boolean getBoolean(Interpreter interpreter, Codes args, int n) {
436
        Object value = getObject(interpreter, args, n);
437
        return toBoolean(value, interpreter.getAccuracy());
438
    }
439

    
440
    protected boolean toBoolean(Object value, Double accuracy) {
441
        if( value == null ) {
442
            return false;
443
        }
444
        if( value instanceof Boolean ) {
445
            return (Boolean)value;
446
        }        
447
        if( value instanceof Number ) {
448
            return MathUtils.compareTo(
449
                ((Number) value).doubleValue(), 
450
                0,
451
                accuracy==null? MathUtils.EPSILON:accuracy
452
            ) == 0;
453
        }
454
        return BooleanUtils.toBoolean(value.toString());
455
    } 
456

    
457
    private void load_from_resource() {
458
        String lang = Locale.getDefault().getLanguage();
459
        URL url = this.getClass().getResource("/org/gvsig/expressionevaluator/functions/"+lang+"/"+this.name()+".json");
460
        if( url == null ) {
461
            url = this.getClass().getResource("/org/gvsig/expressionevaluator/functions/en/"+this.name()+".json");
462
            if( url == null ) {
463
                return;
464
            }
465
        }
466
        InputStream is = null;
467
        JSONObject json;
468
        try {
469
            is = url.openStream();
470
            List<String> lines = IOUtils.readLines(is);
471
            json = new JSONObject(StringUtils.join(lines,  "\n"));
472
        } catch (Exception ex) {
473
            return;
474
        } finally {
475
            IOUtils.closeQuietly(is);
476
        }
477
        
478
        if( json.has("group") ) {
479
            this.group = json.getString("group");
480
        }
481
        if( json.has("description") ) {
482
            Object x = json.get("description");
483
            if( x instanceof String ) {
484
                this.description = (String) x;
485
            } else if( x instanceof JSONArray ) {
486
                StringBuilder builder = new StringBuilder();
487
                for (int i = 0; i < ((JSONArray)x).length(); i++) {
488
                    if( i>0 ) {
489
                        builder.append(" ");
490
                    }
491
                    builder.append(((JSONArray)x).getString(i));
492
                }
493
                this.description = builder.toString();
494
            } else {
495
                this.description = Objects.toString(x, null);
496
            }
497
            this.description = StringUtils.replace(
498
                    this.description, 
499
                    "@@@", 
500
                    url.toString()
501
            );
502
        }
503
        if( json.has("template") ) {
504
            this.template = json.getString("template");
505
        }
506
        if( json.has("returnType") ) {
507
            this.returnType = json.getString("returnType");
508
        }
509
        if( json.has("sqlCompatible") ) {
510
            this.sqlCompatible = json.getBoolean("sqlCompatible");
511
        }
512
        if( json.has("args") ) {
513
            JSONArray x = json.getJSONArray("args");
514
            String[] args = new String[x.length()];
515
            for (int i = 0; i < x.length(); i++) {
516
                args[i] = x.getString(i);
517
            }
518
            this.descriptionArgs = args;
519
        }
520
        if( json.has("alias") ) {
521
            JSONArray x = json.getJSONArray("alias");
522
            for (int i = 0; i < x.length(); i++) {
523
                this.addAlias(x.getString(i));
524
            }
525
        }
526
    }
527
    protected static final int TYPE_INT =     0b0000001;
528
    protected static final int TYPE_LONG =    0b0000010;
529
    protected static final int TYPE_FLOAT =   0b0000100;
530
    protected static final int TYPE_DOUBLE =  0b0001000;
531
    protected static final int TYPE_BOOLEAN = 0b0010000;
532
    protected static final int TYPE_STRING =  0b0100000;
533
    protected static final int TYPE_DATE =    0b1000000;
534
    
535
    protected int getType(Object op1, Object op2) {
536
        int r = 0;
537
        if( op1 instanceof Double ) {
538
            r |= TYPE_DOUBLE;
539
        } else if( op1 instanceof Float ) {
540
            r |= TYPE_FLOAT;
541
        } else if( op1 instanceof Long ) {
542
            r |= TYPE_LONG;
543
        } else if( op1 instanceof Integer ) {
544
            r |= TYPE_INT;
545
        } else if( op1 instanceof Boolean ) {
546
            r |= TYPE_BOOLEAN;
547
        } else if( op1 instanceof String ) {
548
            r |= TYPE_STRING;
549
        } else if( op1 instanceof Date ) {
550
            r |= TYPE_DATE;
551
        }
552
        if( op2 instanceof Double ) {
553
            r |= TYPE_DOUBLE;
554
        } else if( op2 instanceof Float ) {
555
            r |= TYPE_FLOAT;
556
        } else if( op2 instanceof Long ) {
557
            r |= TYPE_LONG;
558
        } else if( op2 instanceof Integer ) {
559
            r |= TYPE_INT;
560
        } else if( op2 instanceof Boolean ) {
561
            r |= TYPE_BOOLEAN;
562
        } else if( op2 instanceof String ) {
563
            r |= TYPE_STRING;
564
        } else if( op2 instanceof Date ) {
565
            r |= TYPE_DATE;
566
        }
567
        return r;
568
    }
569
    
570
}