Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.impl / src / main / java / org / gvsig / fmap / dal / feature / impl / DefaultFeatureQuery.java @ 47198

History | View | Annotate | Download (39.8 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
package org.gvsig.fmap.dal.feature.impl;
25

    
26
import java.util.ArrayList;
27
import java.util.Arrays;
28
import java.util.Collection;
29
import java.util.HashMap;
30
import java.util.Iterator;
31
import java.util.List;
32
import java.util.Map;
33
import javax.json.JsonObject;
34
import org.apache.commons.lang3.ArrayUtils;
35
import org.apache.commons.lang3.StringUtils;
36
import org.apache.commons.lang3.builder.ToStringBuilder;
37
import org.gvsig.expressionevaluator.Expression;
38
import org.gvsig.expressionevaluator.ExpressionEvaluator;
39
import org.gvsig.expressionevaluator.ExpressionUtils;
40
import org.gvsig.expressionevaluator.MutableSymbolTable;
41
import org.gvsig.fmap.dal.DALLocator;
42
import org.gvsig.fmap.dal.DataManager;
43
import org.gvsig.fmap.dal.DataTypes;
44
import org.gvsig.fmap.dal.exception.DataException;
45
import org.gvsig.fmap.dal.exception.InitializeException;
46
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
47
import org.gvsig.fmap.dal.feature.FeatureExtraColumns;
48
import org.gvsig.fmap.dal.feature.FeatureQuery;
49
import org.gvsig.fmap.dal.feature.FeatureQueryOrder;
50
import org.gvsig.fmap.dal.feature.FeatureStore;
51
import org.gvsig.fmap.dal.feature.FeatureType;
52
import org.gvsig.fmap.dal.impl.expressionevaluator.DefaultFeatureExpressionEvaluator;
53
import org.gvsig.json.Json;
54
import org.gvsig.json.JsonArrayBuilder;
55
import org.gvsig.json.JsonObjectBuilder;
56
import org.gvsig.json.SupportJson;
57
import org.gvsig.json.SupportToJson;
58
import org.gvsig.tools.ToolsLocator;
59
import org.gvsig.tools.dynobject.DynStruct;
60
import org.gvsig.tools.evaluator.AndEvaluator;
61
import org.gvsig.tools.evaluator.Evaluator;
62
import org.gvsig.tools.evaluator.EvaluatorFieldsInfo;
63
import org.gvsig.tools.packageutils.Version;
64
import org.gvsig.tools.packageutils.impl.DefaultVersion;
65
import org.gvsig.tools.persistence.PersistentState;
66
import org.gvsig.tools.persistence.exception.PersistenceException;
67
import org.slf4j.Logger;
68
import org.slf4j.LoggerFactory;
69

    
70
/**
71
 * Defines the properties of a collection of Features, as a result of a query
72
 * through a FeatureStore.
73
 * 
74
 * A FeatureQuery is always defined by a FeatureType, or by the list of
75
 * attribute names of the FeatureStore to return.
76
 * 
77
 * The filter allows to select Features whose properties have values with the
78
 * characteristics defined by the filter.
79
 * 
80
 * The order is used to set the order of the result FeatureCollection, based on
81
 * the values of the properties of the Features.
82
 * 
83
 * The scale parameter can be used by the FeatureStore as a hint about the
84
 * quality or resolution of the data needed to view or operate with the data
85
 * returned. As an example, the FeatureStore may use the scale to return only a
86
 * representative subset of the data, or maybe to return Features with less
87
 * detail, like a point or a line instead of a polygon.
88
 * 
89
 * If an implementation of FeatureStore is able to get other parameters to
90
 * customize the behavior of the getDataCollection methods, there is an option
91
 * to set more parameters through the setAttribute method.
92
 */
93
@SuppressWarnings("UseSpecificCatch")
94
public class DefaultFeatureQuery implements FeatureQuery {
95
    
96
    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultFeatureQuery.class);
97

    
98
    public static final String SCALE_PARAM_NAME = "Scale";
99
    
100
    private static final Version VERSION_2_6_0 = ToolsLocator.getPackageManager().createVersion("2.6.0");
101
    private static final Version VERSION_2_6_0_1 = ToolsLocator.getPackageManager().createVersion("2.6.0-1");
102

    
103
    private Map<String,Object> queryParameters = new HashMap();
104

    
105
    private String featureTypeId = null;
106

    
107
    private List<String> attributeNames = new ArrayList();
108

    
109
    private List<String> constantsAttributeNames = new ArrayList();
110

    
111
    private Evaluator filter;
112

    
113
    private FeatureQueryOrder order = new DefaultFeatureQueryOrder();
114

    
115
    private long limit;
116

    
117
    private long pageSize;
118

    
119
    private List<String> groupByColumns;
120
    
121
    private Map<String,String> aggregateFunctions;
122
    
123
    private FeatureExtraColumns extraColumns = new DefaultFeatureExtraColumns();
124
    
125
    private MutableSymbolTable symbolTable;
126
    
127
    private String storeName;
128
    
129
    private boolean useSubquery;
130
    
131
    /**
132
     * Creates a FeatureQuery which will load all available Features of a type.
133
     *
134
     */
135
    public DefaultFeatureQuery() {
136
        super();
137
        this.useSubquery = true; // true for backwards compatibility. 
138
        this.limit = NO_LIMIT;
139
        this.pageSize = 0;
140
    }
141
        
142
    public DefaultFeatureQuery(String storeName) {
143
        this();
144
        this.storeName = storeName;
145
                
146
    }
147

    
148
    /**
149
     * Creates a FeatureQuery which will load all available Features of a type.
150
     *
151
     * @param featureType
152
     *            the type of Features of the query
153
     */
154
    public DefaultFeatureQuery(FeatureType featureType) {
155
        this();
156
        this.setFeatureType(featureType);
157
    }
158

    
159
    /**
160
     * Creates a FeatureQuery with the type of features, a filter and the order
161
     * for the FeatureCollection.
162
     *
163
     * @param featureType
164
     *            the type of Features of the query
165
     * @param filter
166
     *            based on the properties of the Features
167
     */
168
    public DefaultFeatureQuery(FeatureType featureType, Evaluator filter) {
169
        this();
170
        this.setFeatureType(featureType);
171
        this.filter = filter;
172
    }
173

    
174
    /**
175
     * Creates a FeatureQuery with the type of features, a filter, the order for
176
     * the FeatureCollection and the view scale.
177
     *
178
     * @param featureType
179
     *            the type of Features of the query
180
     * @param filter
181
     *            based on the properties of the Features
182
     * @param scale
183
     *            to view the Features.
184
     */
185
    public DefaultFeatureQuery(FeatureType featureType, Evaluator filter,
186
        double scale) {
187
        this();
188
        this.setFeatureType(featureType);
189
        this.filter = filter;
190
        this.setScale(scale);
191
    }
192

    
193
    /**
194
     * Creates a FeatureQuery which will load a list of attribute names of all
195
     * available Features.
196
     *
197
     * @param attributeNames
198
     *            the list of attribute names to load
199
     */
200
    public DefaultFeatureQuery(String[] attributeNames) {
201
        this();
202
        setAttributeNames(attributeNames);
203
    }
204

    
205
    /**
206
     * Creates a FeatureQuery with the list of attribute names of feature, a
207
     * filter and the order for the FeatureCollection.
208
     *
209
     * @param attributeNames
210
     *            the list of attribute names to load
211
     * @param filter
212
     *            based on the properties of the Features
213
     */
214
    public DefaultFeatureQuery(String[] attributeNames, Evaluator filter) {
215
        this();
216
        setAttributeNames(attributeNames);
217
        this.filter = filter;
218
    }
219

    
220
    /**
221
     * Creates a FeatureQuery with the list of attribute names of feature, a
222
     * filter, the order for the FeatureCollection and the view scale.
223
     *
224
     * @param attributeNames
225
     *            the list of attribute names to load
226
     * @param filter
227
     *            based on the properties of the Features
228
     * @param scale
229
     *            to view the Features.
230
     */
231
    public DefaultFeatureQuery(String[] attributeNames, Evaluator filter,
232
        double scale) {
233
        this();
234
        setAttributeNames(attributeNames);
235
        this.filter = filter;
236
        this.setScale(scale);
237
    }
238

    
239
    @Override
240
    public double getScale() {
241
        Double scale = (Double) this.getQueryParameter(SCALE_PARAM_NAME);
242
        if (scale == null) {
243
            return 0;
244
        }
245
        return scale;
246
    }
247

    
248
    @Override
249
    public final void setScale(double scale) {
250
        this.setQueryParameter(SCALE_PARAM_NAME, scale);
251
    }
252

    
253
    @Override
254
    public Object getQueryParameter(String name) {
255
        return queryParameters.get(name);
256
    }
257

    
258
    @Override
259
    public void setQueryParameter(String name, Object value) {
260
        queryParameters.put(name, value);
261
    }
262

    
263
    @Override
264
    public final void setFeatureType(FeatureType featureType) {
265
        this.featureTypeId = featureType.getId();
266
    }
267

    
268
    @Override
269
    public String[] getAttributeNames() {
270
        if (this.hasExtraColumnDeclaredAsGroupByField()) {
271
            this.retrievesAllAttributes();
272
        }
273
        return (String[])attributeNames.toArray(new String[attributeNames.size()]);
274
    }
275
    
276
    private boolean hasExtraColumnDeclaredAsGroupByField() {
277
        // indica si un campo de agrupaciones es una columna calculada
278
        if (this.hasGroupByColumns()) {
279
            for (String groupByColumn : groupByColumns) {
280
                if (this.extraColumns.get(groupByColumn)!=null) {
281
                    return true;
282
                }
283
            }
284
        }
285
        return false;
286
    }
287

    
288
    @Override
289
    public final void setAttributeNames(String[] attributeNames) {
290
        this.attributeNames.clear();
291
        if (attributeNames != null){
292
            this.attributeNames.addAll(Arrays.asList(attributeNames));
293
        }
294
    }
295

    
296
    @Override
297
    public void retrievesAllAttributes() {
298
        this.attributeNames.clear();
299
    } 
300
    
301
    @Override
302
    public void addAttributeName(String attributeName){
303
        //If the attribute exists finish the method
304
        for (int i=0 ; i<attributeNames.size() ; i++){
305
            if (attributeNames.get(i).equals(attributeName)){
306
                return;
307
            }
308
        }
309
        this.attributeNames.add(attributeName);
310
    }
311

    
312
    @Override
313
    public void addEssentialAttributeNames(FeatureStore store) {
314
        FeatureType storeType;
315
        try {
316
            storeType = store.getDefaultFeatureType();
317
        } catch (DataException ex) {
318
            throw new RuntimeException("Can't access to the default feature type of tghe store", ex);
319
        }
320
        FeatureAttributeDescriptor[] pks = storeType.getPrimaryKey();
321
        if( storeType.hasOID() || ArrayUtils.isEmpty(pks) ) {
322
            FeatureAttributeDescriptor attrInt = null;
323
            FeatureAttributeDescriptor attrStr = null;
324
            FeatureAttributeDescriptor attrNotGeom = null;
325
            for (FeatureAttributeDescriptor attr : storeType) {
326
                if( attrInt == null && (attr.getType()==DataTypes.INT || attr.getType()==DataTypes.LONG) ) {
327
                    attrInt = attr;
328
                } else if( attrStr == null && attr.getType()==DataTypes.STRING ) {
329
                    attrStr = attr;
330
                } else if( attrNotGeom == null && attr.getType()!=DataTypes.GEOMETRY ) {
331
                    attrNotGeom = attr;
332
                }
333
            }
334
            if( attrInt != null ) {
335
                this.addAttributeName(attrInt.getName());
336
            } else if( attrStr != null ) {
337
                this.addAttributeName(attrStr.getName());
338
            } else if( attrNotGeom != null ) {
339
                this.addAttributeName(attrNotGeom.getName());
340
            } else {
341
                this.addAttributeName(storeType.getAttributeDescriptor(0).getName());
342
            }
343
        } else {
344
            for(FeatureAttributeDescriptor attr : pks ) {
345
                this.addAttributeName(attr.getName());
346
            }
347
        }
348
    }
349
    
350
    @Override
351
    public void addPrimaryKeyAttributeNames(FeatureStore store) {
352
        FeatureType storeType;
353
        try {
354
            storeType = store.getDefaultFeatureType();
355
        } catch (DataException ex) {
356
            throw new RuntimeException("Can't access to the default feature type of tghe store", ex);
357
        }
358
        for(FeatureAttributeDescriptor attr : storeType.getPrimaryKey() ) {
359
            this.addAttributeName(attr.getName());
360
        }
361
    }
362

    
363
    @Override
364
    public boolean hasAttributeNames() {
365
        if (hasExtraColumnDeclaredAsGroupByField()) {
366
            return true;
367
        }
368
        return !this.attributeNames.isEmpty();
369
    }
370

    
371
    @Override
372
    public void clearAttributeNames() {
373
        this.attributeNames = new ArrayList();
374
    }
375

    
376
    @Override
377
    public Evaluator getFilter() {
378
      if( this.filter instanceof ExpressionEvaluator ) {
379
        ExpressionEvaluator eefilter = (ExpressionEvaluator) this.filter;
380
        if( symbolTable != null ) {
381
            eefilter.addSymbolTable(symbolTable);
382
        }
383
      }
384
      return filter;
385
    }
386

    
387
    @Override
388
    public Expression getExpressionFilter() {
389
      if( this.filter instanceof ExpressionEvaluator ) {
390
        ExpressionEvaluator eefilter = (ExpressionEvaluator) this.filter;
391
        if( symbolTable != null ) {
392
            eefilter.addSymbolTable(symbolTable);
393
        }
394
        return eefilter.toExpression();
395
      }
396
      return null;
397
    }
398

    
399
    @Override
400
    public void setFilter(Expression filter) {
401
        if( filter == null ) {
402
            this.clearFilter();
403
            return;
404
        }
405
        Evaluator x = new DefaultFeatureExpressionEvaluator(storeName, filter);
406
        this.setFilter(x);
407
    }
408

    
409
   @Override
410
    public void setFilter(String filter) {
411
        if( StringUtils.isEmpty(filter) ) {
412
            this.clearFilter();
413
            return;
414
        }
415
        try {
416
            this.setFilter(ExpressionUtils.createExpression(filter));
417
        } catch (Exception ex) {
418
            throw new RuntimeException("Can't create filter from '"+filter+"'",ex);
419
        }
420
    }
421

    
422
    @Override
423
    public void setFilter(Evaluator filter) {
424
        if( filter == null ) {
425
            this.clearFilter();
426
            return;
427
        }        
428
        this.filter = filter;
429
        addFilterAttributes(filter);
430
    }
431

    
432
    @Override
433
    public void addFilter(String filter) {
434
        if( StringUtils.isEmpty(filter) ) {
435
            return;
436
        }
437
        this.addFilter(ExpressionUtils.createExpression(filter));
438
    }
439

    
440
    @Override
441
    public void addFilter(Expression filter) {
442
        Evaluator x = new DefaultFeatureExpressionEvaluator(filter);
443
        this.addFilter(x);
444
    }
445

    
446
    @Override
447
    public void addFilter(Evaluator evaluator) {
448
        if (evaluator == null) {
449
            return;
450
        }
451
        if (this.filter == null) {
452
            this.filter = evaluator;
453
        } else {
454
            if (this.filter instanceof AndEvaluator) {
455
                ((AndEvaluator) this.filter).addEvaluator(evaluator);
456
            } else {
457
                this.filter = new AndEvaluator(this.filter);
458
                ((AndEvaluator) this.filter).addEvaluator(evaluator);
459
            }
460
        }
461
        addFilterAttributes(evaluator);
462
    }
463

    
464
    @Override
465
    public void clearFilter() {
466
      this.filter = null;
467
    }
468

    
469
    private void addFilterAttributes(Evaluator evaluator){
470
        if (evaluator != null){
471
            EvaluatorFieldsInfo fieldsInfo = evaluator.getFieldsInfo();
472
            if (fieldsInfo == null){
473
                // FieldsInfo is not available in this evaluator
474
                return;
475
            }
476
            String[] fieldNames = fieldsInfo.getFieldNames();
477
            if (fieldNames== null){
478
                // fieldNames is not available in this evaluator
479
                return;
480
            }
481

    
482
            for (String fieldName : fieldNames) {
483
                addAttributeName(fieldName);
484
            }
485
        }
486
    }
487

    
488
    @Override
489
    public FeatureQueryOrder getOrder() {
490
        return order;
491
    }
492

    
493
    @Override
494
    public void setOrder(FeatureQueryOrder order) {
495
        if(order == null){
496
            this.order = new DefaultFeatureQueryOrder();
497
        } else {
498
            this.order = order;
499
        }
500
    }
501

    
502
    @Override
503
    public boolean hasFilter() {
504
        return this.filter != null;
505
    }
506

    
507
    @Override
508
    public boolean hasLimit() {
509
        return this.limit != NO_LIMIT;
510
    }
511

    
512
    @Override
513
    public boolean hasOrder() {
514
        return this.order != null && this.order.size() > 0;
515
    }
516

    
517
    @Override
518
    public Object clone() throws CloneNotSupportedException {
519
        DefaultFeatureQuery clone = (DefaultFeatureQuery) super.clone();
520

    
521
        // Clone attribute names array
522
        if (attributeNames != null) {
523
            clone.attributeNames = new ArrayList();
524
            for (int i=0 ; i<attributeNames.size() ; i++){
525
                clone.attributeNames.add(attributeNames.get(i));
526
            }
527
        }
528

    
529
        // Clone order
530
        if (order != null) {
531
            clone.order = (FeatureQueryOrder) order.clone();
532
        }
533
        
534
        clone.extraColumns = extraColumns.getCopy();
535
        
536
        if( this.filter instanceof ExpressionEvaluator ) {
537
            Expression exp = ((ExpressionEvaluator)this.filter).toExpression();
538
            clone.filter =  new DefaultFeatureExpressionEvaluator(exp);
539
        }
540
        
541
        if (groupByColumns!=null) {
542
            clone.groupByColumns = new ArrayList<>();
543
            for (String value : groupByColumns) {
544
                clone.groupByColumns.add(value);
545
            }
546
        } else {
547
            clone.groupByColumns = null;
548
        }
549
                
550
                
551
        if (aggregateFunctions!=null) {
552
            clone.aggregateFunctions = new HashMap<>();
553
            for (String key : aggregateFunctions.keySet()) {
554
                clone.aggregateFunctions.put(key, aggregateFunctions.get(key));
555
            }
556
        } else {
557
            clone.aggregateFunctions = null;
558
        }
559
        if( this.symbolTable!=null ) {
560
            clone.symbolTable = this.symbolTable.clone();
561
        }
562
        
563
        return clone;
564
    }
565

    
566
    @Override
567
    public FeatureQuery getCopy() {
568
        try {
569
            return (FeatureQuery) clone();
570
        } catch (CloneNotSupportedException e) {
571
            LOGGER.debug("Can't clone feature query",e);
572
            return null;
573
        }
574
        // DefaultFeatureQuery aCopy = new DefaultFeatureQuery();
575
        //
576
        // aCopy.featureTypeId = this.featureTypeId;
577
        //
578
        // if (this.attributeNames != null) {
579
        // aCopy.attributeNames = (String[]) Arrays
580
        // .asList(this.attributeNames).toArray(new String[0]);
581
        // }
582
        //
583
        // aCopy.filter = this.filter;
584
        //
585
        // if (this.order != null) {
586
        // aCopy.order = this.order.getCopy();
587
        // }
588
        //
589
        // return aCopy;
590
    }
591

    
592
    @Override
593
    public String getFeatureTypeId() {
594
        return featureTypeId;
595
    }
596

    
597
    @Override
598
    public void setFeatureTypeId(String featureTypeId) {
599
        this.featureTypeId = featureTypeId;
600
    }
601

    
602
    @Override
603
    public void saveToState(PersistentState state) throws PersistenceException {
604
        // FIXME: falta por terminar de implementar
605
        state.set("version", VERSION_2_6_0_1);
606
        state.set("queryParameters", this.queryParameters);
607
        state.set("featureTypeId", this.featureTypeId);
608
        state.set("attributeNames", this.attributeNames);
609
        
610
        ArrayList<Expression> filterList = new ArrayList<>();
611
        if (this.filter instanceof DefaultFeatureExpressionEvaluator) {
612
            DefaultFeatureExpressionEvaluator filterExpression = (DefaultFeatureExpressionEvaluator) this.filter;
613
           filterList.add(filterExpression.toExpression());
614
        } else if (this.filter instanceof AndEvaluator) {
615
            AndEvaluator filterAnd = (AndEvaluator) this.filter;
616
            List<Evaluator> evaluators = filterAnd.getEvaluators();
617
            for (Evaluator evaluator : evaluators) {
618
                if (evaluator instanceof DefaultFeatureExpressionEvaluator) {
619
                    DefaultFeatureExpressionEvaluator expressionEvaluator = (DefaultFeatureExpressionEvaluator) evaluator;
620
                    filterList.add(expressionEvaluator.toExpression());
621
                } else {
622
                    filterList.clear();
623
                    LOGGER.warn(StringUtils.join("Filters in this FeatureQuery will not persist:", this.toString()));
624
                    break;
625
                }
626
            }
627
        } else {
628
            filterList.clear();
629
            if( this.filter!=null ) {
630
                LOGGER.warn(StringUtils.join("Filters in this FeatureQuery will not persist:", this.toString()));
631
            }
632
        }
633
        
634
        state.set("filter", filterList);
635
        state.set("limit", this.limit);
636
        state.set("pageSize", this.pageSize);
637
        state.set("useSubquery", this.useSubquery);
638
        
639
        state.set("order", this.order);
640
        state.set("groupByColumns", this.groupByColumns);
641
        state.set("aggregateFunctions", this.aggregateFunctions);
642
        state.set("extraColumn", this.extraColumns);
643
        state.set("storeName", this.storeName);
644
        
645

    
646
    }
647
    
648

    
649
    @Override
650
    public void loadFromState(PersistentState state) throws PersistenceException {
651
        // FIXME: falta por terminar de implementar
652
        Version version = (Version) state.get("version");
653
        this.queryParameters = (Map) state.get("queryParameters");
654
        this.featureTypeId = state.getString("featureTypeId");
655
        this.attributeNames = state.getList("attributeNames");
656
        List<Expression> filterList = state.getList("filter");
657
        String stateFilter = "";
658
        DataManager dataManager = DALLocator.getDataManager();
659
        if (filterList.isEmpty()) {
660
            this.filter = null;
661
        } else if (filterList.size() == 1) {
662
            Expression expression = filterList.get(0);
663
            Evaluator evaluator;
664
            try {
665
                evaluator = dataManager.createFilter(expression);
666
            } catch (InitializeException ex) {
667
                LOGGER.warn("Can't create evaluator", ex);
668
                evaluator = null;
669
            }
670
            this.filter = evaluator;
671
        } else {
672
            AndEvaluator andEvaluator = null;
673
            for (Expression expression : filterList) {
674
                Evaluator evaluator;
675
                try {
676
                    evaluator = dataManager.createFilter(expression);
677

    
678
                    if (andEvaluator == null) {
679
                        andEvaluator = new AndEvaluator(evaluator);
680
                    } else {
681
                        andEvaluator.addEvaluator(evaluator);
682
                    }
683
                } catch (InitializeException ex) {
684
                    LOGGER.warn("Can't create AndEvaluator", ex);//TODO evaluator a null
685
                    break;
686
                }
687
                this.filter = evaluator;
688

    
689
            }
690
        }
691
        this.limit = state.getLong("limit");
692
        
693
        this.pageSize = state.getLong("pageSize");
694
        this.useSubquery = state.getBoolean("useSubquery",true);
695
        this.storeName = state.getString("storeName");
696
        
697
        
698
        this.order = (FeatureQueryOrder) state.get("order");
699
        List asListGroupByColumns = (List) state.getList("groupByColumns");
700
        if (asListGroupByColumns!=null) {
701
            this.groupByColumns = new ArrayList<>(asListGroupByColumns);
702
        } else {
703
            this.groupByColumns = null;
704
        }
705
        Map asMapAggregateFunctions = (Map) state.getMap("aggregateFunctions");
706
        if (asMapAggregateFunctions!=null) {
707
            this.aggregateFunctions = new HashMap<>(asMapAggregateFunctions);
708
        } else {
709
            this.aggregateFunctions = null;
710
        }
711
        this.extraColumns = (FeatureExtraColumns) state.get("extraColumn");
712

    
713
        //
714
        // -------------------------------------------------------------
715
        // Correcciones por perdida de compatibilidad entre versiones
716
        //
717
        
718
        if(version == null || version.compareTo(VERSION_2_6_0)<0){
719
            if(this.limit == 0) {
720
                this.clearLimit();
721
            }
722
        }
723
    }
724

    
725
    public static void selfRegister() {
726
        registerPersistent();
727
        Json.registerSerializer(DefaultFeatureQuery.class);            
728
    }
729
    
730
    /**
731
     * Register the class on PersistenceManager
732
     *
733
     */
734
    private static void registerPersistent() {
735
        DynStruct definition =
736
            ToolsLocator.getPersistenceManager()
737
            .addDefinition(DefaultFeatureQuery.class,
738
                "DefaultFeatureQuery",
739
                "DefaultFeatureQuery Persistent definition",
740
                null,
741
                null);
742

    
743
        
744
        definition.addDynFieldObject("version")
745
                .setClassOfValue(DefaultVersion.class)
746
                .setMandatory(false);
747

    
748
        definition.addDynFieldMap("queryParameters")
749
                .setClassOfItems(Object.class)
750
                .setMandatory(true);
751

    
752
        definition.addDynFieldString("featureTypeId").setMandatory(false);
753

    
754
        definition.addDynFieldList("attributeNames")
755
                .setClassOfItems(String.class)
756
                .setMandatory(false);
757

    
758
        definition.addDynFieldList("filter")
759
                .setClassOfItems(Expression.class)
760
                .setMandatory(false);
761

    
762
        definition.addDynFieldObject("order")
763
                .setClassOfValue(FeatureQueryOrder.class)
764
                .setMandatory(false);
765

    
766
        definition.addDynFieldLong("limit").setMandatory(false);
767

    
768
        definition.addDynFieldLong("pageSize").setMandatory(false);
769
        
770
        definition.addDynFieldBoolean("useSubquery").setMandatory(false);
771
       
772
        definition.addDynFieldList("groupByColumns")
773
                .setClassOfItems(String.class);
774

    
775
        definition.addDynFieldMap("aggregateFunctions")
776
                .setClassOfItems(String.class)
777
                .setClassOfValue(String.class);
778
    
779
        definition.addDynFieldObject("extraColumn")
780
                .setClassOfValue(DefaultFeatureExtraColumns.class);
781
                        
782
                definition.addDynFieldString("storeName").setMandatory(false);
783

    
784
    }
785

    
786
    @Override
787
    public long getLimit() {
788
        return limit;
789
    }
790

    
791
    @Override
792
    public long getPageSize() {
793
        return pageSize;
794
    }
795

    
796
    @Override
797
    public void setLimit(long limit) {
798
        this.limit = limit;
799
    }
800

    
801
    @Override
802
    public void clearLimit() {
803
        this.limit = NO_LIMIT;
804
    }
805
    
806
    @Override
807
    public void setPageSize(long pageSize) {
808
        this.pageSize = pageSize;
809
    }
810

    
811
    @Override
812
    public String[] getConstantsAttributeNames() {
813
        return (String[])constantsAttributeNames.toArray(new String[constantsAttributeNames.size()]);
814
    }
815

    
816
    @Override
817
    public void setConstantsAttributeNames(String[] constantsAttributeNames) {
818
        this.constantsAttributeNames.clear();
819
        if (constantsAttributeNames != null){
820
            this.constantsAttributeNames.addAll(Arrays.asList(constantsAttributeNames));
821
        }
822
    }
823

    
824
    @Override
825
    public void addConstantAttributeName(String attributeName) {
826
        //If the attribute exists finish the method
827
        for (int i=0 ; i<constantsAttributeNames.size() ; i++){
828
            if (constantsAttributeNames.get(i).equals(attributeName)){
829
                return;
830
            }
831
        }
832
        this.constantsAttributeNames.add(attributeName);
833
    }
834

    
835
    @Override
836
    public boolean hasConstantsAttributeNames() {
837
        return !this.constantsAttributeNames.isEmpty();
838
    }
839

    
840
    @Override
841
    public void clearConstantsAttributeNames() {
842
        this.constantsAttributeNames = new ArrayList();
843
    }
844

    
845
  @Override
846
  public boolean isAGroupByColumn(String name) {
847
    if( groupByColumns==null ) {
848
        return false;
849
    }
850
    for (String columnName : groupByColumns) {
851
      if( StringUtils.equalsIgnoreCase(name, columnName) ) {
852
        return true;
853
      }
854
    }
855
    return false;
856
  }
857

    
858
  @Override
859
  public List<String> getGroupByColumns() {
860
    if( this.groupByColumns == null ) {
861
      this.groupByColumns = new ArrayList<>();
862
    }
863
    return this.groupByColumns;
864
  }
865

    
866
  @Override
867
  public void removeGroupByColumn(String colname) {
868
    if( this.groupByColumns == null ) {
869
      return;
870
    }
871
    this.groupByColumns.remove(colname);
872
  }
873
  
874
  @Override
875
  public void addAggregate(String funcName, String columnName) {
876
        Map<String, String> aggregateds = this.getAggregateFunctions();
877
        aggregateds.put(columnName, funcName);
878
  }
879

    
880
  @Override
881
  public Map<String, String> getAggregateFunctions() {
882
    if( this.aggregateFunctions == null ) {
883
      this.aggregateFunctions = new HashMap<>();
884
    }
885
    return this.aggregateFunctions;
886
  }
887

    
888
  @Override
889
  public void removeAggregateFunction(String colname) {
890
    if( this.aggregateFunctions == null ) {
891
      return;
892
    }
893
    for (Iterator<Map.Entry<String, String>> iterator = this.getAggregateFunctions().entrySet().iterator(); iterator.hasNext();) {
894
        Map.Entry<String, String> entry = iterator.next();
895
        String attrName = entry.getKey();
896
        String function = entry.getValue();
897
        if(StringUtils.equalsIgnoreCase(colname, attrName)){
898
            iterator.remove();
899
            return;
900
        }
901
    }
902
  }
903
  
904
  @Override
905
  public String getAggregateFunction(String name){
906
      for (Map.Entry<String, String> entry : this.getAggregateFunctions().entrySet()) {
907
          String attrName = entry.getKey();
908
          String function = entry.getValue();
909
          if(StringUtils.equalsIgnoreCase(name, attrName)){
910
              return function;
911
          }
912
      }
913
      return null;
914
  }
915
  
916
  @Override
917
  public String getAggregate(String name) {    
918
      String fn = this.getAggregateFunction(name);
919
      if( StringUtils.isAlphanumeric(fn) ) {
920
        return fn + "(\""+ name + "\")";
921
      }
922
      return fn;
923
  }
924
  
925
  @Override
926
  public String getAggregate(String tableName, String name) {    
927
      String fn = this.getAggregateFunction(name);
928
      if (!tableName.startsWith("\"")) {
929
         tableName = "\""+tableName+"\"";
930
      }
931
      if( StringUtils.isAlphanumeric(fn) ) {
932
        return fn + "("+tableName+".\""+ name + "\")";
933
      }
934
      return fn;
935
  }
936

    
937
    @Override
938
    public boolean isAggregate(String name) {
939
        return this.getAggregateFunction(name) != null;
940
    }
941

    
942
  @Override
943
  public boolean hasAggregateFunctions() {
944
    return this.aggregateFunctions != null && !this.aggregateFunctions.isEmpty();
945
  }
946

    
947
  @Override
948
  public boolean hasGroupByColumns() {
949
    return this.groupByColumns != null && !this.groupByColumns.isEmpty();
950
  }
951

    
952
  private void clear() {
953
        this.queryParameters = new HashMap();
954
        
955
//        this.featureTypeId = other.featureTypeId;
956
//        this.storeName = other.storeName;
957

    
958
        this.clearConstantsAttributeNames();
959
        this.clearAttributeNames();
960
        this.clearFilter();
961
        this.clearLimit();
962
        this.setOrder(null);
963
        this.useSubquery = true; // true for backwards compatibility. 
964
        this.limit = NO_LIMIT;
965
        this.pageSize = 0;
966
        this.groupByColumns = null;
967
        this.aggregateFunctions=null;
968
        this.extraColumns = new DefaultFeatureExtraColumns();
969
        this.symbolTable = null;
970

    
971
  }
972
  
973
  @Override
974
  public void copyFrom(FeatureQuery query) {
975
    if( query == null ) {
976
        this.clear();
977
        return;
978
    }
979
    DefaultFeatureQuery other = (DefaultFeatureQuery) query;
980
    this.queryParameters = new HashMap();
981
    this.queryParameters.putAll(other.queryParameters);
982
    
983
    this.featureTypeId = other.featureTypeId;
984

    
985
    this.attributeNames.clear();
986
    this.attributeNames.addAll(other.attributeNames);
987

    
988
    this.constantsAttributeNames.clear();
989
    this.constantsAttributeNames.addAll(other.constantsAttributeNames);
990

    
991
    this.filter = other.filter;
992

    
993
    this.order.copyFrom(other.order);
994

    
995
    this.limit = other.limit;
996

    
997
    this.pageSize = other.pageSize;
998
    this.useSubquery = other.useSubquery;
999

    
1000
    if( this.groupByColumns!=null && other.groupByColumns!=null ) {
1001
      this.groupByColumns.clear();
1002
      this.groupByColumns.addAll(other.groupByColumns);
1003
    } else if( other.groupByColumns!=null ) {
1004
      this.groupByColumns = new ArrayList<>();
1005
      this.groupByColumns.addAll(other.groupByColumns);
1006
    } else if( this.groupByColumns!=null ) {
1007
      this.groupByColumns = null;
1008
    }
1009
    
1010
    if( this.aggregateFunctions!=null && other.aggregateFunctions!=null ) {
1011
      this.aggregateFunctions.clear();
1012
      this.aggregateFunctions.putAll(other.aggregateFunctions);
1013
    } else if( other.aggregateFunctions!=null ) {
1014
      this.aggregateFunctions = new HashMap<>(other.aggregateFunctions);
1015
    } else if( this.aggregateFunctions!=null ) {
1016
      this.aggregateFunctions=null;
1017
    }
1018
    this.extraColumns.copyFrom(other.extraColumns);
1019
    if( other.symbolTable!=null ) {
1020
        try {
1021
            this.symbolTable = other.symbolTable.clone();
1022
        } catch (CloneNotSupportedException ex) {
1023
            LOGGER.debug("Can't clone symbol table",ex);
1024
        }
1025
    }
1026
        this.storeName = other.storeName;
1027
  }
1028

    
1029
    @Override
1030
    public FeatureExtraColumns getExtraColumns() {
1031
        return this.extraColumns;
1032
    }
1033

    
1034
    @Override
1035
    @Deprecated
1036
    public FeatureExtraColumns getExtraColumn() {
1037
        return this.extraColumns;
1038
    }
1039

    
1040
    @Override
1041
    public MutableSymbolTable getSymbolTable() {
1042
        return symbolTable;
1043
    }
1044

    
1045
    @Override
1046
    public void setSymbolTable(MutableSymbolTable symbolTable) {
1047
        this.symbolTable = symbolTable;
1048
    }
1049

    
1050
    @Override
1051
    public void setVar(String name, Object value) {
1052
        if( this.symbolTable==null ) {
1053
            this.symbolTable = ExpressionUtils.createSymbolTable();
1054
        }
1055
        this.symbolTable.setVar(name, value);
1056
    }
1057

    
1058
    @Override
1059
    public boolean isUseSubquery() {
1060
        return useSubquery;
1061
    }
1062

    
1063
    @Override
1064
    public void setUseSubquery(boolean useSubquery) {
1065
        this.useSubquery = useSubquery;
1066
    }
1067

    
1068
    @Override
1069
    public void fromJson(JsonObject json) {
1070
        DataManager dataManager = DALLocator.getDataManager();
1071

    
1072
        String s = json.getString("version",null);
1073
        Version version = s==null?null:Version.valueOf(s);
1074
        
1075
        this.queryParameters = Json.toMap(json, "queryParameters");
1076
        this.featureTypeId = json.getString("featureTypeId", null);
1077

    
1078
        this.attributeNames = new ArrayList<>();
1079
        Collection theAttributeNames = Json.toCollection(json,"attributeNames");
1080
        if( theAttributeNames!=null ) {
1081
            this.attributeNames.addAll(theAttributeNames);
1082
        }
1083
        
1084
        List<Expression> filterList = null;
1085
        Collection theFilter = Json.toCollection(json, "filter");
1086
        if( theFilter!=null ) {
1087
            filterList = new ArrayList<>(theFilter);
1088
        }
1089
        if (filterList==null || filterList.isEmpty()) {
1090
            this.filter = null;
1091
        } else if (filterList.size() == 1) {
1092
            Expression expression = filterList.get(0);
1093
            Evaluator evaluator;
1094
            try {
1095
                evaluator = dataManager.createFilter(expression);
1096
            } catch (InitializeException ex) {
1097
                LOGGER.warn("Can't create evaluator", ex);
1098
                evaluator = null;
1099
            }
1100
            this.filter = evaluator;
1101
        } else {
1102
            AndEvaluator andEvaluator = null;
1103
            for (Expression expression : filterList) {
1104
                Evaluator evaluator;
1105
                try {
1106
                    evaluator = dataManager.createFilter(expression);
1107

    
1108
                    if (andEvaluator == null) {
1109
                        andEvaluator = new AndEvaluator(evaluator);
1110
                    } else {
1111
                        andEvaluator.addEvaluator(evaluator);
1112
                    }
1113
                } catch (InitializeException ex) {
1114
                    LOGGER.warn("Can't create AndEvaluator", ex);//TODO evaluator a null
1115
                    break;
1116
                }
1117
                this.filter = evaluator;
1118

    
1119
            }
1120
        }
1121
        this.limit = json.getInt("limit");
1122
        if(version == null || version.compareTo(VERSION_2_6_0)<0){
1123
            if(this.limit == 0) {
1124
                this.clearLimit();
1125
            }
1126
        }
1127
        this.pageSize = json.getInt("pageSize");
1128
        this.useSubquery = json.getBoolean("useSubquery",true);
1129
        this.storeName = json.getString("storeName");
1130
        
1131
        
1132
        this.order = (FeatureQueryOrder) Json.toObject(json, "order");
1133
        
1134
        Collection<String> theGroupByColumns = Json.toCollection(json.getJsonArray("groupByColumns"));
1135
        if (theGroupByColumns!=null) {
1136
            this.groupByColumns = new ArrayList<>(theGroupByColumns);
1137
        } else {
1138
            this.groupByColumns = null;
1139
        }
1140
        
1141
        
1142
        Map asMapAggregateFunctions = Json.toMap(json,"aggregateFunctions");
1143
        if (asMapAggregateFunctions!=null) {
1144
            this.aggregateFunctions = new HashMap<>(asMapAggregateFunctions);
1145
        } else {
1146
            this.aggregateFunctions = null;
1147
        }
1148
        this.extraColumns = (FeatureExtraColumns) Json.toObject(json,"extraColumn");
1149
    }
1150

    
1151
    @Override
1152
    public JsonObjectBuilder toJsonBuilder() {
1153
        JsonObjectBuilder state = Json.createObjectBuilder();
1154
        state.add("version", VERSION_2_6_0.toString());
1155
        state.add("queryParameters", this.queryParameters);
1156
        state.add("featureTypeId", this.featureTypeId);
1157
        state.add("attributeNames", this.attributeNames);
1158
        
1159
        JsonArrayBuilder filterList = Json.createArrayBuilder();
1160
        if (this.filter instanceof DefaultFeatureExpressionEvaluator) {
1161
            DefaultFeatureExpressionEvaluator filterExpression = (DefaultFeatureExpressionEvaluator) this.filter;
1162
           filterList.add(filterExpression.toExpression());
1163
        } else if (this.filter instanceof AndEvaluator) {
1164
            AndEvaluator filterAnd = (AndEvaluator) this.filter;
1165
            List<Evaluator> evaluators = filterAnd.getEvaluators();
1166
            for (Evaluator evaluator : evaluators) {
1167
                if (evaluator instanceof DefaultFeatureExpressionEvaluator) {
1168
                    DefaultFeatureExpressionEvaluator expressionEvaluator = (DefaultFeatureExpressionEvaluator) evaluator;
1169
                    filterList.add(expressionEvaluator.toExpression());
1170
                } else {
1171
                    filterList = Json.createArrayBuilder();
1172
                    LOGGER.warn(StringUtils.join("Filters in this FeatureQuery will not persist:", this.toString()));
1173
                    break;
1174
                }
1175
            }
1176
        } else {
1177
            filterList = Json.createArrayBuilder();
1178
            if( this.filter!=null ) {
1179
                LOGGER.warn(StringUtils.join("Filters in this FeatureQuery will not persist:", this.toString()));
1180
            }
1181
        }
1182
        
1183
        state.add("filter", filterList);
1184
        state.add("limit", this.limit);
1185
        state.add("pageSize", this.pageSize);
1186
        state.add("useSubquery", this.useSubquery);
1187
        
1188
        state.add("order", (SupportJson) this.order); 
1189
        state.add("groupByColumns", this.groupByColumns); 
1190
        state.add("aggregateFunctions", this.aggregateFunctions);
1191
        state.add("extraColumn", (SupportToJson) this.extraColumns); 
1192
        state.add("storeName", this.storeName);
1193
        
1194
        return state;
1195
    }
1196

    
1197
    @Override
1198
    public String toString() {
1199
        try {
1200
            ToStringBuilder builder = new ToStringBuilder(this);
1201
            builder.append("storeName", this.storeName);
1202
            builder.append("filter", this.filter, true);
1203
            builder.append("order", this.order, true); 
1204
            builder.append("limit", this.limit);
1205
            builder.append("attributeNames", this.attributeNames, true);
1206
            builder.append("queryParameters", this.queryParameters, true);
1207
            builder.append("pageSize", this.pageSize);
1208
            builder.append("useSubquery", this.useSubquery);
1209
            builder.append("groupByColumns", this.groupByColumns); 
1210
            builder.append("aggregateFunctions", this.aggregateFunctions);
1211
            builder.append("featureTypeId", this.featureTypeId);
1212
            builder.append("extraColumn", this.extraColumns); 
1213

    
1214
            return builder.toString();
1215
        } catch (Exception e) {
1216
            return super.toString();
1217
        }
1218
    }
1219
    
1220
}