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

History | View | Annotate | Download (21.1 KB)

1
package org.gvsig.expressionevaluator.spi;
2

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

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

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

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

    
72
    protected AbstractFunction(String group, String name, Range argc) {
73
        this(group, name, argc, null, null, null, null);
74
    }
75

    
76
    @Override
77
    public String name() {
78
        return this.name;
79
    }
80

    
81
    @Override
82
    public String returnType() {
83
        return this.returnType;
84
    }
85

    
86
    @Override
87
    public String group() {
88
        return this.group;
89
    }
90

    
91
    @Override
92
    public Range argc() {
93
        return argc;
94
    }
95

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

    
104
    @Override
105
    public String[] descriptionArgs() {
106
        return descriptionArgs;
107
    }
108

    
109
    public String getFullDescription() {
110
        I18nManager i18n = ToolsLocator.getI18nManager();
111

    
112
        StringBuilder html = new StringBuilder();
113
        html.append("<html>\n");
114

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

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

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

    
149
        html.append("</html>\n");
150
        return html.toString();
151
    }
152

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

    
167
    @Override
168
    public List<String> aliases() {
169
        return this.alias;
170
    }
171

    
172
    @Override
173
    public String template() {
174
        return this.template;
175
    }
176

    
177
    @Override
178
    public boolean isOperator() {
179
        return false;
180
    }
181

    
182
    @Override
183
    public boolean isHidden() {
184
      return false;
185
    }
186
    
187
    @Override
188
    public boolean useArgumentsInsteadObjects() {
189
        return false;
190
    }
191

    
192
    @Override
193
    public boolean isSQLCompatible() {
194
        return sqlCompatible;
195
    }
196

    
197
    @Override
198
    public boolean allowConstantFolding() {
199
        return false;
200
    }
201

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

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

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

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

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

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

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

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

    
423
    public URL getURL(Object[] args, int index) throws MalformedURLException {
424
        Object obj = getObject(args, index);
425
        if( obj == null ) {
426
            return null;
427
        }  
428
        URL url;
429
        if( obj instanceof URL ) {
430
            url = (URL) obj;        } else if( obj instanceof CharSequence ) {
431
            url = new URL(((CharSequence)obj).toString());
432
        } else if( obj instanceof File ) {
433
            url = ((File)obj).toURI().toURL();
434
        } else if( obj instanceof URI ) {
435
            url = ((URI)obj).toURL();
436
        } else {
437
            throw new ExpressionRuntimeException("The "+this.name()+" function require a File, URI or a String and a received a '"+obj.getClass().getSimpleName()+"'.");
438
        }  
439
        return url;
440
    }
441
    
442
    protected boolean getBoolean(Object args[], int n, Double accuracy) {
443
        if( args.length < n  ) {
444
            throw new IllegalArgumentException(I18N.Required_argument_XargnX_and_only_found_XargcX_in_call_to_XIdentifierX(name(), args.length, n));
445
        }
446
        return getBoolean(args[n], n, accuracy);
447
    }
448

    
449
    protected boolean getBoolean(Object value, int n) {
450
        return getBoolean(value, n, MathUtils.EPSILON);
451
    }
452

    
453
    protected boolean getBoolean(Object value, int n, Double accuracy) {
454
        return toBoolean(value, accuracy);
455
    }
456

    
457
    protected boolean getBoolean(Interpreter interpreter, Codes args, int n) {
458
        Object value = getObject(interpreter, args, n);
459
        return toBoolean(value, interpreter.getAccuracy());
460
    }
461

    
462
    protected boolean toBoolean(Object value, Double accuracy) {
463
        if( value == null ) {
464
            return false;
465
        }
466
        if( value instanceof Boolean ) {
467
            return (Boolean)value;
468
        }        
469
        if( value instanceof Number ) {
470
            return MathUtils.compareTo(
471
                ((Number) value).doubleValue(), 
472
                0,
473
                accuracy==null? MathUtils.EPSILON:accuracy
474
            ) == 0;
475
        }
476
        return BooleanUtils.toBoolean(value.toString());
477
    } 
478

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

    
592
    @Override
593
    public String toString(Codes args, Formatter<Code> formatter) {
594
        return null;
595
    }
596

    
597
}