Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.plugin / org.gvsig.app / org.gvsig.app.mainplugin / src / main / java / org / gvsig / app / project / symboltables / ProjectSymbolTable.java @ 44207

History | View | Annotate | Download (26 KB)

1
package org.gvsig.app.project.symboltables;
2

    
3
import java.io.File;
4
import java.io.FileInputStream;
5
import java.util.HashMap;
6
import java.util.Iterator;
7
import java.util.List;
8
import java.util.Map;
9
import java.util.Properties;
10
import org.apache.commons.io.IOUtils;
11
import org.apache.commons.lang3.Range;
12
import org.cresques.cts.IProjection;
13
import org.gvsig.app.ApplicationLocator;
14
import org.gvsig.app.ApplicationManager;
15
import org.gvsig.app.project.Project;
16
import org.gvsig.app.project.ProjectManager;
17
import org.gvsig.app.project.documents.Document;
18
import org.gvsig.app.project.documents.view.ViewDocument;
19
import org.gvsig.app.project.documents.view.ViewManager;
20
import org.gvsig.expressionevaluator.Expression;
21
import org.gvsig.expressionevaluator.ExpressionEvaluatorLocator;
22
import org.gvsig.expressionevaluator.ExpressionEvaluatorManager;
23
import org.gvsig.expressionevaluator.ExpressionRuntimeException;
24
import org.gvsig.expressionevaluator.Interpreter;
25
import org.gvsig.expressionevaluator.spi.AbstractFunction;
26
import org.gvsig.expressionevaluator.spi.AbstractSymbolTable;
27
import org.gvsig.fmap.crs.CRSFactory;
28
import org.gvsig.fmap.dal.DALLocator;
29
import org.gvsig.fmap.dal.DataManager;
30
import org.gvsig.fmap.dal.HasDataStore;
31
import org.gvsig.fmap.dal.expressionevaluator.FeatureSymbolTable;
32
import org.gvsig.fmap.dal.feature.Feature;
33
import org.gvsig.fmap.dal.feature.FeatureQuery;
34
import org.gvsig.fmap.dal.feature.FeatureSet;
35
import org.gvsig.fmap.dal.feature.FeatureStore;
36
import org.gvsig.fmap.geom.Geometry;
37
import org.gvsig.fmap.geom.primitive.Point;
38
import org.gvsig.fmap.mapcontext.MapContext;
39
import org.gvsig.fmap.mapcontext.layers.FLayer;
40
import org.gvsig.fmap.mapcontext.layers.vectorial.FLyrVect;
41
import org.gvsig.fmap.mapcontrol.AreaAndPerimeterCalculator;
42
import org.gvsig.temporarystorage.TemporaryStorageGroup;
43
import org.gvsig.temporarystorage.TemporaryStorageLocator;
44
import org.gvsig.temporarystorage.TemporaryStorageManager;
45
import org.gvsig.tools.util.UnmodifiableBasicList;
46

    
47
/**
48
 *
49
 * @author jjdelcerro
50
 */
51
@SuppressWarnings("UseSpecificCatch")
52
public class ProjectSymbolTable extends AbstractSymbolTable {
53

    
54
    public static final String AREA_NAME = "AREA";        
55
    public static final String PERIMETER_NAME = "PERIMETER";
56
    public static final String STORE_NAME = "STORE";
57
    public static final String FETCH_FIRST_NAME = "FETCH_FIRST";
58
    public static final String FETCH_FIRST_SELECTED_NAME = "FETCH_FIRST_SELECTED";
59
    public static final String FETCH_NAME = "FETCH";
60
        
61
    static final String NAME = "Project";
62
    
63
    private static final String TABLE_DOCUMENT_TYPENAME = "project.document.table";
64
    
65
    private abstract class CachedValue<T> {
66

    
67
        T value = null;
68
        long lastAccess = 0;
69

    
70
        protected abstract void reload();
71

    
72
        public boolean isExpired() {
73
            long now = System.currentTimeMillis();
74
            return now - lastAccess > 3000;
75
        }
76

    
77
        public T get() {
78
            if (isExpired()) {
79
                reload();
80
            }
81
            lastAccess = System.currentTimeMillis();
82
            return value;
83
        }
84
    }
85

    
86
    private class ProjectValue extends CachedValue<Project> {
87

    
88
        @Override
89
        protected void reload() {
90
            value = ProjectManager.getInstance().getCurrentProject();
91
        }
92

    
93
    }
94

    
95
    private class CurrentViewValue extends CachedValue<ViewDocument> {
96

    
97
        @Override
98
        protected void reload() {
99
            ApplicationManager application = ApplicationLocator.getManager();
100
            ViewDocument viewdoc = (ViewDocument) application.getActiveDocument(ViewManager.TYPENAME);
101
            value = viewdoc;
102
        }
103

    
104
    }
105

    
106
    private class CurrentViewEnvelopeValue extends CachedValue<Geometry> {
107

    
108
        @Override
109
        protected void reload() {
110
            ApplicationManager application = ApplicationLocator.getManager();
111
            ViewDocument viewdoc = (ViewDocument) application.getActiveDocument(ViewManager.TYPENAME);
112
            if( viewdoc == null ) {
113
                value = null;
114
                return;
115
            }
116
            value = viewdoc.getMapContext().getViewPort().getEnvelope().getGeometry();
117
        }
118

    
119
    }
120

    
121
    private class PropertiesValue extends CachedValue<Map<File, Properties>> {
122

    
123
        @Override
124
        protected void reload() {
125
            value = new HashMap<>();
126
        }
127
    }
128

    
129
    private class CurrentProjectFunction extends AbstractFunction {
130

    
131
        public CurrentProjectFunction() {
132
            super(
133
                    "Project",
134
                    "project",
135
                    Range.is(0),
136
                    "Access to the current project loaded in gvSIG desktop.\n",
137
                    "project()",
138
                    null,
139
                    "Project"
140
            );
141
        }
142

    
143
        @Override
144
        public Object call(Interpreter interpreter, Object[] args) throws Exception {
145
            return currentProject.get();
146
        }
147

    
148
    }
149

    
150
    private class StoreFunction extends AbstractFunction {
151

    
152
        public StoreFunction() {
153
            super(
154
                    "Project",
155
                    STORE_NAME,
156
                    Range.is(2), // Range.between(1, 2),
157
                    "Return the data store associated with a layer.", // or a table.\n" +
158
//                       "If receive a single parameter, it will correspond to " + 
159
//                       "the name of a table-type document, and it will return " + 
160
//                       "your data store. If you receive two parameters, you expect " +
161
//                       "to be the name of a view and a layer of it, returning the " +
162
//                       "data store of the layer.",
163
                    STORE_NAME+"({{view}}, layer)",
164
                    new String[]{
165
                        "view - String value with the name of a view",
166
                        "layer - String value with the name of a layer in the indicated view"
167
//                        "table - String value with the name of document table"
168
                    },
169
                    "DataStore"
170
            );
171
        }
172

    
173
        @Override
174
        public Object call(Interpreter interpreter, Object[] args) throws Exception {
175
            Project project = currentProject.get();
176
            switch (args.length) {
177
                case 1:
178
                    String tableName = getStr(args, 0);
179
                    Document document = project.getDocument(tableName, TABLE_DOCUMENT_TYPENAME);
180
                    if (document == null) {
181
                        return null;
182
                    }
183
                    if( document instanceof HasDataStore ) {
184
                        return ((HasDataStore) document).getDataStore();
185
                    }
186
                    return null;
187

    
188
                case 2:
189
                    String viewName = getStr(args, 0);
190
                    String layerName = getStr(args, 1);
191
                    ViewDocument view = (ViewDocument) project.getDocument(viewName, ViewManager.TYPENAME);
192
                    if (view == null) {
193
                        return null;
194
                    }
195
                    FLayer layer = view.getLayer(layerName);
196
                    if( layer instanceof HasDataStore ) {
197
                        return ((HasDataStore)layer).getDataStore();
198
                    }
199
                    return null;
200
            }
201
            return null;
202
        }
203
        
204
    }
205
    
206
    private class FetchFunction extends AbstractFunction {
207

    
208
        public FetchFunction() {
209
            super(
210
                    "Project",
211
                    FETCH_NAME,
212
                    Range.between(2, 4),
213
                    "Access to the features of a table and retuen a list with the values.",
214
                    FETCH_NAME+"({{value}}, store, where, order)",
215
                    new String[]{
216
                        "value - value to retrieve from the store, usually an expression in the columns of this are involved.",
217
                        "store - data store from which values will be collected",
218
                        "where - Optional. String value with a filter expression",
219
                        "order - Optional. String value with the order. must be a string with the names of separate fields with commas"
220
                    },
221
                    "Object"
222
            );
223
        }
224

    
225
        @Override
226
        public Object call(Interpreter interpreter, Object[] args) throws Exception {
227
            Object value;
228
            String where = null;
229
            String order = null;
230
            String expression_s = getStr(args, 0);
231
            FeatureStore store = (FeatureStore) getObject(args, 1);
232
            switch (args.length) {
233
                case 3:
234
                    where = getStr(args, 2);
235
                    break;
236
                case 4:
237
                    where = getStr(args, 2);
238
                    order = getStr(args, 3);
239
                    break;
240
            }
241
            try {
242
                List<Feature> features;
243
                if (where == null && order == null) {
244
                    features = store.getFeatures();
245
                } else {
246
                    FeatureQuery query = store.createFeatureQuery();
247
                    if (where != null) {
248
                        query.addFilter(where);
249
                    }
250
                    if (order != null) {
251
                        query.getOrder().add(order);
252
                    }
253
                    query.retrievesAllAttributes();
254
                    features = store.getFeatures(query);
255
                }
256
                UnmodifiableBasicList<Object> list = new ListOfFeaturesWrapper(
257
                        features,
258
                        interpreter.getSymbolTable(), 
259
                        expression_s
260
                );
261
                return list;
262
            } catch (Exception ex) {
263
                throw new ExpressionRuntimeException("Problems calling '"+FETCH_NAME+"' function", ex);
264
            }
265
        }
266
    }
267

    
268
    private class FetchFirstFunction extends AbstractFunction {
269

    
270
        public FetchFirstFunction() {
271
            super(
272
                    "Project",
273
                    FETCH_FIRST_NAME,
274
                    Range.between(2, 4),
275
                    "Access to the first feature of the layer, and "
276
                    + "return the value of the attribute.",
277
                    FETCH_FIRST_NAME+"({{value}}, store, where, order)",
278
                    new String[]{
279
                        "value - value to retrieve from the store, usually an expression in the columns of this are involved.",
280
                        "store - data store from which values will be collected",
281
                        "where - Optional. String value with a filter expression",
282
                        "order - Optional. String value with the order. must be a string with the names of separate fields with commas"
283
                    },
284
                    "Object"
285
            );
286
        }
287

    
288
        @Override
289
        public Object call(Interpreter interpreter, Object[] args) throws Exception {
290
            Object value;
291
            String where = null;
292
            String order = null;
293
            String expression_s = getStr(args, 0);
294
            FeatureStore store = (FeatureStore) getObject(args, 1);
295
            switch (args.length) {
296
                case 3:
297
                    where = getStr(args, 2);
298
                    break;
299
                case 4:
300
                    where = getStr(args, 2);
301
                    order = getStr(args, 3);
302
                    break;
303
            }
304
            try {
305
                FeatureSet set;
306
                if (where == null && order == null) {
307
                    set = store.getFeatureSet();
308
                } else {
309
                    FeatureQuery query = store.createFeatureQuery();
310
                    if (where != null) {
311
                        query.addFilter(where);
312
                    }
313
                    if (order != null) {
314
                        query.getOrder().add(order);
315
                    }
316
                    query.retrievesAllAttributes();
317
                    set = store.getFeatureSet(query);
318
                }
319
                Feature feature = set.first();
320
                if (feature == null) {
321
                    return null;
322
                }
323
                DataManager dataManager = DALLocator.getDataManager();
324
                FeatureSymbolTable symbolTable = dataManager.createFeatureSymbolTable();
325
                symbolTable.setFeature(feature);
326

    
327
                ExpressionEvaluatorManager expManager = ExpressionEvaluatorLocator.getManager();
328
                Expression expression = expManager.createExpression();
329
                expression.setPhrase(expression_s);
330
                value = expression.execute(symbolTable.createParent());
331
                
332
                return value;
333
            } catch (Exception ex) {
334
                throw new ExpressionRuntimeException("Problems calling '"+FETCH_FIRST_NAME+"' function", ex);
335
            }
336
        }
337
    }
338

    
339
    private class FetchFirstSelectedFunction extends AbstractFunction {
340

    
341
        public FetchFirstSelectedFunction() {
342
            super("Project",
343
                    FETCH_FIRST_SELECTED_NAME,
344
                    Range.is(2),
345
                    "Access to the first feature of the selection.",
346
                    FETCH_FIRST_SELECTED_NAME+"({{value}}, store)",
347
                    new String[]{
348
                        "value - value to retrieve from the store, usually an expression in the columns of this are involved.",
349
                        "store - data store from which values will be collected"
350
                    },
351
                    "Object"
352
            );
353
        }
354

    
355
        @Override
356
        public Object call(Interpreter interpreter, Object[] args) throws Exception {
357
            String expression_s = getStr(args, 0);
358
            FeatureStore store = (FeatureStore) getObject(args, 1);
359
            try {
360
                FeatureSet set = store.getFeatureSelection();
361
                Feature feature = set.first();
362
                if (feature == null) {
363
                    return null;
364
                }
365
                DataManager dataManager = DALLocator.getDataManager();
366
                FeatureSymbolTable symbolTable = dataManager.createFeatureSymbolTable();
367
                symbolTable.setFeature(feature);
368

    
369
                ExpressionEvaluatorManager expManager = ExpressionEvaluatorLocator.getManager();
370
                Expression expression = expManager.createExpression();
371
                expression.setPhrase(expression_s);
372
                Object value = expression.execute(symbolTable.createParent());
373
                
374
                return value;
375
            } catch (Exception ex) {
376
                throw new ExpressionRuntimeException("Problems calling '"+FETCH_FIRST_SELECTED_NAME+"' function", ex);
377
            }
378
        }
379
    }
380

    
381
    private class ViewFunction extends AbstractFunction {
382

    
383
        public ViewFunction() {
384
            super(
385
                    "Project",
386
                    "view",
387
                    Range.is(1),
388
                    "Access to the indicated view",
389
                    "view({{viewName}})",
390
                    new String[]{
391
                        "view - String value with the name of a view"
392
                    },
393
                    "DocumentView"
394
            );
395
        }
396

    
397
        @Override
398
        public Object call(Interpreter interpreter, Object[] args) throws Exception {
399
            String viewName = getStr(args, 0);
400
            Project project = currentProject.get();
401
            ViewDocument view = (ViewDocument) project.getDocument(viewName, ViewManager.TYPENAME);
402
            return view;
403
        }
404

    
405
    }
406

    
407
    private class ViewBBoxFunction extends AbstractFunction {
408

    
409
        public ViewBBoxFunction() {
410
            super(
411
                    "Project",
412
                    "viewbbox",
413
                    Range.is(0),
414
                    "Return the BBox of the active view.",
415
                    "viewbbox()",
416
                    null,
417
                    "Geometry"
418
            );
419
        }
420

    
421
        @Override
422
        public Object call(Interpreter interpreter, Object[] args) throws Exception {
423
            return currentViewEnvelope.get();
424
        }
425

    
426
    }
427

    
428

    
429
    private class SavedPointFunction extends AbstractFunction {
430

    
431
        public SavedPointFunction() {
432
            super(
433
                    "Project",
434
                    "savedpoint",
435
                    Range.is(1),
436
                    "Return the value of the saved point with the name indicated.\n"
437
                            + "If the named point do not exists return null.",
438
                    "savedpoint({{name}})",
439
                    new String[]{
440
                        "name - String value with the name of the point"
441
                    },
442
                    "Geometry"
443
            );
444
        }
445

    
446
        @Override
447
        public Object call(Interpreter interpreter, Object[] args) throws Exception {
448
            TemporaryStorageManager manager = TemporaryStorageLocator.getTemporaryStorageManager();
449
            TemporaryStorageGroup storage = manager.create("Points",Point.class);
450
            Geometry value = (Geometry) storage.get(getStr(args, 0));
451
            return value;
452
        }
453

    
454
    }
455

    
456
    private  class AreaFunction extends AbstractFunction {
457
        
458
        public AreaFunction() {
459
            super(
460
                    "Project",
461
                    AREA_NAME,
462
                    Range.between(2,3),
463
                    "Calculate the area of the geometry in the indicated units",
464
                    AREA_NAME+"({{geometry}}, 'm?')",
465
                    new String[]{
466
                        "geometry - Geometry",
467
                        "Projection - Optional. Projection of the geometry or a string with the projection name",
468
                        "units - String value with the name the units to use"
469
                    },
470
                    "Double"
471
            );
472
        }
473

    
474
        @Override
475
        public Object call(Interpreter interpreter, Object[] args) throws Exception {
476
            int units = 0;
477
            IProjection proj = null;
478
            Geometry geom = getGeom(args, 0);
479
            switch( args.length ) {
480
                case 2:
481
                    units = getUnitsArea(args, 1);
482
                    break;
483
                case 3:
484
                    proj = getProjection(args, 1);
485
                    units = getUnitsArea(args, 2);
486
                    break;
487
            }
488
            if (proj == null) {
489
                proj = geom.getProjection();
490
            }
491
            AreaAndPerimeterCalculator calculator = new AreaAndPerimeterCalculator();
492
            double area = calculator.area(geom, proj, units);
493
            return area;
494
        }
495
    }
496

    
497
    private class PerimeterFunction extends AbstractFunction {
498

    
499
        public PerimeterFunction() {
500
            super(
501
                    "Project",
502
                    PERIMETER_NAME,
503
                    Range.between(2,3),
504
                    "Calculate the perimeter of the geometry in the indicated units",
505
                    PERIMETER_NAME+"({{geometry}}, 'm')",
506
                    new String[]{
507
                        "geometry - Geometry",
508
                        "Projection - Optional. Projection of the geometry or a string with the projection name",
509
                        "units - String value with the name the units to use"
510
                    },
511
                    "Double"
512
            );
513
        }
514

    
515
        @Override
516
        public Object call(Interpreter interpreter, Object[] args) throws Exception {
517
            int units = 0;
518
            IProjection proj = null;
519
            Geometry geom = getGeom(args, 0);
520
            switch( args.length ) {
521
                case 2:
522
                    units = getUnitsArea(args, 1);
523
                    break;
524
                case 3:
525
                    proj = getProjection(args, 1);
526
                    units = getUnitsArea(args, 2);
527
                    break;
528
            }
529
            if (proj == null) {
530
                proj = geom.getProjection();
531
            }
532
            AreaAndPerimeterCalculator calculator = new AreaAndPerimeterCalculator();
533
            double area = calculator.perimeter(geom, proj, units);
534
            return area;
535
        }
536
    }
537

    
538
    private class PropertyFunction extends AbstractFunction {
539

    
540
        public PropertyFunction() {
541
            super(
542
                    "Project",
543
                    "property",
544
                    Range.between(2, 3),
545
                    "Access to a property value in a properties file. If the"
546
                    + "indicated filename is not absolute, access it relative"
547
                    + "to the project.",
548
                    "property({{filename}}, name, defaultValue)",
549
                    new String[]{
550
                        "filename - String value with the name of the properties file",
551
                        "name - String value with the name of the property to retrieve from the file",
552
                        "defaultValue - Optional. Default value if can't access the file or the property",},
553
                    "String"
554
            );
555
        }
556

    
557
        @Override
558
        public Object call(Interpreter interpreter, Object[] args) throws Exception {
559
            String filename = getStr(args, 0);
560
            String name = getStr(args, 1);
561
            String defaultValue = null;
562
            if (args.length == 3) {
563
                defaultValue = getStr(args, 2);
564
            }
565

    
566
            File file = new File(filename);
567
            if (!file.isAbsolute()) {
568
                Project project = currentProject.get();
569
                if (project.getFile() == null) {
570
                    return defaultValue;
571
                }
572
                file = new File(project.getFile().getParent(), filename);
573
            }
574
            Map<File, Properties> x = propertiesFiles.get();
575
            Properties properties = x.get(file);
576
            if (properties == null) {
577
                properties = new Properties();
578
                FileInputStream in = null;
579
                try {
580
                    in = new FileInputStream(file);
581
                    properties.load(in);
582
                } catch (Exception ex) {
583
                    return defaultValue;
584
                } finally {
585
                    IOUtils.closeQuietly(in);
586
                }
587
                x.put(file, properties);
588
            }
589
            String value = properties.getProperty(name, defaultValue);
590
            return value;
591
        }
592

    
593
    }
594

    
595
    ProjectValue currentProject = new ProjectValue();
596
    CurrentViewValue currentView = new CurrentViewValue();
597
    CurrentViewEnvelopeValue currentViewEnvelope = new CurrentViewEnvelopeValue();
598
    PropertiesValue propertiesFiles = new PropertiesValue();
599

    
600
    @SuppressWarnings("OverridableMethodCallInConstructor")
601
    public ProjectSymbolTable() {
602
        super(NAME);
603
        this.addFunction(new CurrentProjectFunction());
604
        this.addFunction(new StoreFunction());
605
        this.addFunction(new FetchFunction());
606
        this.addFunction(new FetchFirstFunction());
607
        this.addFunction(new FetchFirstSelectedFunction());
608
        this.addFunction(new ViewFunction());
609
        this.addFunction(new ViewBBoxFunction());
610
        this.addFunction(new PropertyFunction());
611
        this.addFunction(new AreaFunction());
612
        this.addFunction(new PerimeterFunction());
613
        this.addFunction(new SavedPointFunction());
614
    }
615

    
616
    private MapContext getMapContext(Feature feature) {
617
        FeatureStore store = feature.getStore();
618
        Project project = ProjectManager.getInstance().getCurrentProject();
619
        project.getDocuments(ViewManager.TYPENAME);
620
        for (Document document : project.getDocuments(ViewManager.TYPENAME)) {
621
            ViewDocument view = (ViewDocument) document;
622
            MapContext mapContext = view.getMapContext();
623
            FLayer layer = getLayer(mapContext, store);
624
            if (layer != null) {
625
                return mapContext;
626
            }
627
        }
628
        return null;
629
    }
630

    
631
    private FLayer getLayer(MapContext mapContext, FeatureStore store) {
632
        Iterator<FLayer> it = mapContext.deepiterator();
633
        while (it.hasNext()) {
634
            FLayer layer = it.next();
635
            if (layer instanceof FLyrVect) {
636
                FeatureStore layer_store = ((FLyrVect) layer).getFeatureStore();
637
                if (layer_store == store) {
638
                    return layer;
639
                }
640
            }
641
        }
642
        return null;
643
    }
644

    
645
    private IProjection getProjection(Object[] args, int i) {
646
        Object value = args[i];
647
        if (value == null) {
648
            return null;
649
        }
650
        if (value instanceof IProjection) {
651
            return (IProjection) value;
652
        }
653
        String code = value.toString();
654
        return CRSFactory.getCRS(code);
655
    }
656

    
657
    private int getUnitsArea(Object[] args, int i) {
658
        Object value = args[i];
659
        if (value == null) {
660
            throw new IllegalArgumentException("Illegal unit value 'null'");
661
        }
662
        if (value instanceof Number) {
663
            return ((Number) value).intValue();
664
        }
665
        String name = value.toString();
666
        String[] names = MapContext.getAreaAbbr();
667
        for (int j = 0; j < names.length; j++) {
668
            if (name.equalsIgnoreCase(names[j])) {
669
                return j;
670
            }
671
        }
672
        names = MapContext.getAreaNames();
673
        for (int j = 0; j < names.length; j++) {
674
            if (name.equalsIgnoreCase(names[j])) {
675
                return j;
676
            }
677
        }
678
        throw new IllegalArgumentException("Illegal unit name '" + name + "'");
679
    }
680

    
681
    private int getUnitsDistance(Object[] args, int i) {
682
        Object value = args[i];
683
        if (value == null) {
684
            throw new IllegalArgumentException("Illegal unit value 'null'");
685
        }
686
        if (value instanceof Number) {
687
            return ((Number) value).intValue();
688
        }
689
        String name = value.toString();
690
        String[] names = MapContext.getDistanceAbbr();
691
        for (int j = 0; j < names.length; j++) {
692
            if (name.equalsIgnoreCase(names[j])) {
693
                return j;
694
            }
695
        }
696
        names = MapContext.getDistanceNames();
697
        for (int j = 0; j < names.length; j++) {
698
            if (name.equalsIgnoreCase(names[j])) {
699
                return j;
700
            }
701
        }
702
        throw new IllegalArgumentException("Illegal unit name '" + name + "'");
703
    }
704

    
705
}