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

History | View | Annotate | Download (30.9 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.HashMap;
28
import java.util.List;
29
import java.util.Map;
30
import java.util.logging.Level;
31
import org.apache.commons.lang3.ArrayUtils;
32
import org.apache.commons.lang3.StringUtils;
33
import org.gvsig.expressionevaluator.Expression;
34
import org.gvsig.expressionevaluator.ExpressionUtils;
35
import org.gvsig.fmap.dal.DALLocator;
36
import org.gvsig.fmap.dal.DataManager;
37
import org.gvsig.fmap.dal.DataTypes;
38
import org.gvsig.fmap.dal.exception.DataException;
39
import org.gvsig.fmap.dal.exception.InitializeException;
40
import org.gvsig.expressionevaluator.ExpressionEvaluator;
41
import org.gvsig.expressionevaluator.MutableSymbolTable;
42
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
43
import org.gvsig.fmap.dal.feature.FeatureQuery;
44
import org.gvsig.fmap.dal.feature.FeatureQueryOrder;
45
import org.gvsig.fmap.dal.feature.FeatureStore;
46
import org.gvsig.fmap.dal.feature.FeatureType;
47
import org.gvsig.fmap.dal.impl.expressionevaluator.DefaultFeatureExpressionEvaluator;
48
import org.gvsig.tools.ToolsLocator;
49
import org.gvsig.tools.dynobject.DynStruct;
50
import org.gvsig.tools.evaluator.AndEvaluator;
51
import org.gvsig.tools.evaluator.Evaluator;
52
import org.gvsig.tools.evaluator.EvaluatorFieldsInfo;
53
import org.gvsig.tools.persistence.PersistentState;
54
import org.gvsig.tools.persistence.exception.PersistenceException;
55
import org.slf4j.Logger;
56
import org.slf4j.LoggerFactory;
57
import org.gvsig.fmap.dal.feature.FeatureExtraColumns;
58

    
59
/**
60
 * Defines the properties of a collection of Features, as a result of a query
61
 * through a FeatureStore.
62
 * <p>
63
 * A FeatureQuery is always defined by a FeatureType, or by the list of
64
 * attribute names of the FeatureStore to return.
65
 * </p>
66
 * <p>
67
 * The filter allows to select Features whose properties have values with the
68
 * characteristics defined by the filter.
69
 * </p>
70
 * <p>
71
 * The order is used to set the order of the result FeatureCollection, based on
72
 * the values of the properties of the Features.
73
 * </p>
74
 * <p>
75
 * The scale parameter can be used by the FeatureStore as a hint about the
76
 * quality or resolution of the data needed to view or operate with the data
77
 * returned. As an example, the FeatureStore may use the scale to return only a
78
 * representative subset of the data, or maybe to return Features with less
79
 * detail, like a point or a line instead of a polygon.
80
 * </p>
81
 * <p>
82
 * If an implementation of FeatureStore is able to get other parameters to
83
 * customize the behavior of the getDataCollection methods, there is an option
84
 * to set more parameters through the setAttribute method.
85
 * </p>
86
 *
87
 * @author 2009- <a href="cordinyana@gvsig.org">C?sar Ordi?ana</a> - gvSIG team
88
 */
89
public class DefaultFeatureQuery implements FeatureQuery {
90
    
91
    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultFeatureQuery.class);
92

    
93
    public static final String SCALE_PARAM_NAME = "Scale";
94

    
95
    private Map<String,Object> queryParameters = new HashMap();
96

    
97
    private String featureTypeId = null;
98

    
99
    private List<String> attributeNames = new ArrayList();
100

    
101
    private List<String> constantsAttributeNames = new ArrayList();
102

    
103
    private Evaluator filter;
104

    
105
    private FeatureQueryOrder order = new DefaultFeatureQueryOrder();
106

    
107
    private long limit;
108

    
109
    private long pageSize;
110

    
111
    private List<String> groupByColumns;
112
    
113
    private Map<String,String> aggregateFunctions;
114
    
115
    private FeatureExtraColumns extraColumns = new DefaultFeatureExtraColumns();
116
    
117
    private MutableSymbolTable symbolTable;
118
    
119
    private String storeName;
120
    
121
    private boolean useSubquery;
122
    
123
    /**
124
     * Creates a FeatureQuery which will load all available Features of a type.
125
     *
126
     */
127
    public DefaultFeatureQuery() {
128
        super();
129
        this.useSubquery = true; // true for backwards compatibility. 
130
        this.limit = NO_LIMIT;
131
    }
132
        
133
    public DefaultFeatureQuery(String storeName) {
134
        this();
135
        this.storeName = storeName;
136
                
137
    }
138

    
139
    /**
140
     * Creates a FeatureQuery which will load all available Features of a type.
141
     *
142
     * @param featureType
143
     *            the type of Features of the query
144
     */
145
    public DefaultFeatureQuery(FeatureType featureType) {
146
        this();
147
        this.setFeatureType(featureType);
148
    }
149

    
150
    /**
151
     * Creates a FeatureQuery with the type of features, a filter and the order
152
     * for the FeatureCollection.
153
     *
154
     * @param featureType
155
     *            the type of Features of the query
156
     * @param filter
157
     *            based on the properties of the Features
158
     */
159
    public DefaultFeatureQuery(FeatureType featureType, Evaluator filter) {
160
        this();
161
        this.setFeatureType(featureType);
162
        this.filter = filter;
163
    }
164

    
165
    /**
166
     * Creates a FeatureQuery with the type of features, a filter, the order for
167
     * the FeatureCollection and the view scale.
168
     *
169
     * @param featureType
170
     *            the type of Features of the query
171
     * @param filter
172
     *            based on the properties of the Features
173
     * @param scale
174
     *            to view the Features.
175
     */
176
    public DefaultFeatureQuery(FeatureType featureType, Evaluator filter,
177
        double scale) {
178
        this();
179
        this.setFeatureType(featureType);
180
        this.filter = filter;
181
        this.setScale(scale);
182
    }
183

    
184
    /**
185
     * Creates a FeatureQuery which will load a list of attribute names of all
186
     * available Features.
187
     *
188
     * @param attributeNames
189
     *            the list of attribute names to load
190
     */
191
    public DefaultFeatureQuery(String[] attributeNames) {
192
        this();
193
        setAttributeNames(attributeNames);
194
    }
195

    
196
    /**
197
     * Creates a FeatureQuery with the list of attribute names of feature, a
198
     * filter and the order for the FeatureCollection.
199
     *
200
     * @param attributeNames
201
     *            the list of attribute names to load
202
     * @param filter
203
     *            based on the properties of the Features
204
     */
205
    public DefaultFeatureQuery(String[] attributeNames, Evaluator filter) {
206
        this();
207
        setAttributeNames(attributeNames);
208
        this.filter = filter;
209
    }
210

    
211
    /**
212
     * Creates a FeatureQuery with the list of attribute names of feature, a
213
     * filter, the order for the FeatureCollection and the view scale.
214
     *
215
     * @param attributeNames
216
     *            the list of attribute names to load
217
     * @param filter
218
     *            based on the properties of the Features
219
     * @param scale
220
     *            to view the Features.
221
     */
222
    public DefaultFeatureQuery(String[] attributeNames, Evaluator filter,
223
        double scale) {
224
        this();
225
        setAttributeNames(attributeNames);
226
        this.filter = filter;
227
        this.setScale(scale);
228
    }
229

    
230
    @Override
231
    public double getScale() {
232
        Double scale = (Double) this.getQueryParameter(SCALE_PARAM_NAME);
233
        if (scale == null) {
234
            return 0;
235
        }
236
        return scale;
237
    }
238

    
239
    @Override
240
    public void setScale(double scale) {
241
        this.setQueryParameter(SCALE_PARAM_NAME, scale);
242
    }
243

    
244
    @Override
245
    public Object getQueryParameter(String name) {
246
        return queryParameters.get(name);
247
    }
248

    
249
    @Override
250
    public void setQueryParameter(String name, Object value) {
251
        queryParameters.put(name, value);
252
    }
253

    
254
    @Override
255
    public void setFeatureType(FeatureType featureType) {
256
        this.featureTypeId = featureType.getId();
257
    }
258

    
259
    @Override
260
    public String[] getAttributeNames() {
261
        if (this.hasExtraColumnDeclaredAsGroupByField()) {
262
            this.retrievesAllAttributes();
263
        }
264
        return (String[])attributeNames.toArray(new String[attributeNames.size()]);
265
    }
266
    
267
    private boolean hasExtraColumnDeclaredAsGroupByField() {
268
        // indica si un campo de agrupaciones es una columna calculada
269
        if (this.hasGroupByColumns()) {
270
            for (String groupByColumn : groupByColumns) {
271
                if (this.extraColumns.get(groupByColumn)!=null) {
272
                    return true;
273
                }
274
            }
275
        }
276
        return false;
277
    }
278

    
279
    @Override
280
    public void setAttributeNames(String[] attributeNames) {
281
        this.attributeNames.clear();
282
        if (attributeNames != null){
283
            for (int i=0 ; i<attributeNames.length ; i++){
284
                this.attributeNames.add(attributeNames[i]);
285
            }
286
        }
287
    }
288

    
289
    @Override
290
    public void retrievesAllAttributes() {
291
        this.attributeNames.clear();
292
    } 
293
    
294
    @Override
295
    public void addAttributeName(String attributeName){
296
        //If the attribute exists finish the method
297
        for (int i=0 ; i<attributeNames.size() ; i++){
298
            if (attributeNames.get(i).equals(attributeName)){
299
                return;
300
            }
301
        }
302
        this.attributeNames.add(attributeName);
303
    }
304

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

    
356
    @Override
357
    public boolean hasAttributeNames() {
358
        if (hasExtraColumnDeclaredAsGroupByField()) {
359
            return true;
360
        }
361
        return !this.attributeNames.isEmpty();
362
    }
363

    
364
    @Override
365
    public void clearAttributeNames() {
366
        this.attributeNames = new ArrayList();
367
    }
368

    
369
    @Override
370
    public Evaluator getFilter() {
371
      if( this.filter instanceof ExpressionEvaluator ) {
372
        ExpressionEvaluator ee = (ExpressionEvaluator) this.filter;
373
        ee.addSymbolTable(symbolTable);
374
      }
375
      return filter;
376
    }
377

    
378
    @Override
379
    public Expression getExpressionFilter() {
380
      if( this.filter instanceof ExpressionEvaluator ) {
381
        ExpressionEvaluator ee = (ExpressionEvaluator) this.filter;
382
        ee.addSymbolTable(symbolTable);
383
        return ee.toExpression();
384
      }
385
      return null;
386
    }
387

    
388
    @Override
389
    public void setFilter(Expression filter) {
390
        if( filter == null ) {
391
            this.clearFilter();
392
            return;
393
        }
394
        Evaluator x = new DefaultFeatureExpressionEvaluator(storeName, filter);
395
        this.setFilter(x);
396
    }
397

    
398
   @Override
399
    public void setFilter(String filter) {
400
        if( StringUtils.isEmpty(filter) ) {
401
            this.clearFilter();
402
            return;
403
        }
404
        try {
405
            this.setFilter(ExpressionUtils.createExpression(filter));
406
        } catch (Exception ex) {
407
            throw new RuntimeException("Can't create filter from '"+filter+"'",ex);
408
        }
409
    }
410

    
411
    @Override
412
    public void setFilter(Evaluator filter) {
413
        if( filter == null ) {
414
            this.clearFilter();
415
            return;
416
        }        
417
        this.filter = filter;
418
        addFilterAttributes(filter);
419
    }
420

    
421
    @Override
422
    public void addFilter(String filter) {
423
        if( StringUtils.isEmpty(filter) ) {
424
            return;
425
        }
426
        this.addFilter(ExpressionUtils.createExpression(filter));
427
    }
428

    
429
    @Override
430
    public void addFilter(Expression filter) {
431
        Evaluator x = new DefaultFeatureExpressionEvaluator(filter);
432
        this.addFilter(x);
433
    }
434

    
435
    @Override
436
    public void addFilter(Evaluator evaluator) {
437
        if (evaluator == null) {
438
            return;
439
        }
440
        if (this.filter == null) {
441
            this.filter = evaluator;
442
        } else {
443
            if (this.filter instanceof AndEvaluator) {
444
                ((AndEvaluator) this.filter).addEvaluator(evaluator);
445
            } else {
446
                this.filter = new AndEvaluator(this.filter);
447
                ((AndEvaluator) this.filter).addEvaluator(evaluator);
448
            }
449
        }
450
        addFilterAttributes(evaluator);
451
    }
452

    
453
    @Override
454
    public void clearFilter() {
455
      this.filter = null;
456
    }
457

    
458
    private void addFilterAttributes(Evaluator evaluator){
459
        if (evaluator != null){
460
            EvaluatorFieldsInfo fieldsInfo = evaluator.getFieldsInfo();
461
            if (fieldsInfo == null){
462
                // FieldsInfo is not available in this evaluator
463
                return;
464
            }
465
            String[] fieldNames = fieldsInfo.getFieldNames();
466
            if (fieldNames== null){
467
                // fieldNames is not available in this evaluator
468
                return;
469
            }
470

    
471
            for (int i=0 ; i<fieldNames.length ; i++){
472
                addAttributeName(fieldNames[i]);
473
            }
474
        }
475
    }
476

    
477
    @Override
478
    public FeatureQueryOrder getOrder() {
479
        return order;
480
    }
481

    
482
    @Override
483
    public void setOrder(FeatureQueryOrder order) {
484
        if(order == null){
485
            this.order = new DefaultFeatureQueryOrder();
486
        } else {
487
            this.order = order;
488
        }
489
    }
490

    
491
    @Override
492
    public boolean hasFilter() {
493
        return this.filter != null;
494
    }
495

    
496
    @Override
497
    public boolean hasLimit() {
498
        return this.limit != NO_LIMIT;
499
    }
500

    
501
    @Override
502
    public boolean hasOrder() {
503
        return this.order != null && this.order.size() > 0;
504
    }
505

    
506
    @Override
507
    public Object clone() throws CloneNotSupportedException {
508
        DefaultFeatureQuery clone = (DefaultFeatureQuery) super.clone();
509

    
510
        // Clone attribute names array
511
        if (attributeNames != null) {
512
            clone.attributeNames = new ArrayList();
513
            for (int i=0 ; i<attributeNames.size() ; i++){
514
                clone.attributeNames.add(attributeNames.get(i));
515
            }
516
        }
517

    
518
        // Clone order
519
        if (order != null) {
520
            clone.order = (FeatureQueryOrder) order.clone();
521
        }
522
        
523
        clone.extraColumns = extraColumns.getCopy();
524
        
525
        if( this.filter instanceof ExpressionEvaluator ) {
526
            Expression exp = ((ExpressionEvaluator)this.filter).toExpression();
527
            clone.filter =  new DefaultFeatureExpressionEvaluator(exp);
528
        }
529
        
530
        if (groupByColumns!=null) {
531
            clone.groupByColumns = new ArrayList<String>();
532
            for (String value : groupByColumns) {
533
                clone.groupByColumns.add(value);
534
            }
535
        } else {
536
            clone.groupByColumns = null;
537
        }
538
                
539
                
540
        if (aggregateFunctions!=null) {
541
            clone.aggregateFunctions = new HashMap<String, String>();
542
            for (String key : aggregateFunctions.keySet()) {
543
                clone.aggregateFunctions.put(key, aggregateFunctions.get(key));
544
            }
545
        } else {
546
            clone.aggregateFunctions = null;
547
        }
548
        if( this.symbolTable!=null ) {
549
            clone.symbolTable = this.symbolTable.clone();
550
        }
551
        
552
        return clone;
553
    }
554

    
555
    @Override
556
    public FeatureQuery getCopy() {
557
        try {
558
            return (FeatureQuery) clone();
559
        } catch (CloneNotSupportedException e) {
560
            LOGGER.debug("Can't clone feature query",e);
561
            return null;
562
        }
563
        // DefaultFeatureQuery aCopy = new DefaultFeatureQuery();
564
        //
565
        // aCopy.featureTypeId = this.featureTypeId;
566
        //
567
        // if (this.attributeNames != null) {
568
        // aCopy.attributeNames = (String[]) Arrays
569
        // .asList(this.attributeNames).toArray(new String[0]);
570
        // }
571
        //
572
        // aCopy.filter = this.filter;
573
        //
574
        // if (this.order != null) {
575
        // aCopy.order = this.order.getCopy();
576
        // }
577
        //
578
        // return aCopy;
579
    }
580

    
581
    @Override
582
    public String getFeatureTypeId() {
583
        return featureTypeId;
584
    }
585

    
586
    @Override
587
    public void setFeatureTypeId(String featureTypeId) {
588
        this.featureTypeId = featureTypeId;
589
    }
590

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

    
634
    }
635
    
636

    
637
    @Override
638
    public void loadFromState(PersistentState state) throws PersistenceException {
639
        // FIXME: falta por terminar de implementar
640
        this.queryParameters = (Map) state.get("queryParameters");
641
        this.featureTypeId = state.getString("featureTypeId");
642
        this.attributeNames = state.getList("attributeNames");
643
        List<Expression> filterList = state.getList("filter");
644
        String stateFilter = "";
645
        DataManager dataManager = DALLocator.getDataManager();
646
        if (filterList.size() == 0) {
647
            this.filter = null;
648
        } else if (filterList.size() == 1) {
649
            Expression expression = filterList.get(0);
650
            Evaluator evaluator;
651
            try {
652
                evaluator = dataManager.createFilter(expression);
653
            } catch (InitializeException ex) {
654
                LOGGER.warn("Can't create evaluator", ex);
655
                evaluator = null;
656
            }
657
            this.filter = evaluator;
658
        } else {
659
            AndEvaluator andEvaluator = null;
660
            for (Expression expression : filterList) {
661
                Evaluator evaluator;
662
                try {
663
                    evaluator = dataManager.createFilter(expression);
664

    
665
                    if (andEvaluator == null) {
666
                        andEvaluator = new AndEvaluator(evaluator);
667
                    } else {
668
                        andEvaluator.addEvaluator(evaluator);
669
                    }
670
                } catch (InitializeException ex) {
671
                    LOGGER.warn("Can't create AndEvaluator", ex);//TODO evaluator a null
672
                    break;
673
                }
674
                this.filter = evaluator;
675

    
676
            }
677
        }
678
        this.limit = state.getLong("limit");
679
        this.pageSize = state.getLong("pageSize");
680
        this.useSubquery = state.getBoolean("useSubquery",true);
681
        this.storeName = state.getString("storeName");
682
        
683
        
684
        this.order = (FeatureQueryOrder) state.get("order");
685
        List asListGroupByColumns = (List) state.getList("groupByColumns");
686
        if (asListGroupByColumns!=null) {
687
            this.groupByColumns = new ArrayList<>(asListGroupByColumns);
688
        } else {
689
            this.groupByColumns = null;
690
        }
691
        Map asMapAggregateFunctions = (Map) state.getMap("aggregateFunctions");
692
        if (asMapAggregateFunctions!=null) {
693
            this.aggregateFunctions = new HashMap<>(asMapAggregateFunctions);
694
        } else {
695
            this.aggregateFunctions = null;
696
        }
697
        this.extraColumns = (FeatureExtraColumns) state.get("extraColumn");
698

    
699
    
700
    }
701

    
702
    /**
703
     * Register the class on PersistenceManager
704
     *
705
     */
706
    public static void registerPersistent() {
707
        DynStruct definition =
708
            ToolsLocator.getPersistenceManager()
709
            .addDefinition(DefaultFeatureQuery.class,
710
                "DefaultFeatureQuery",
711
                "DefaultFeatureQuery Persistent definition",
712
                null,
713
                null);
714

    
715
        definition.addDynFieldMap("queryParameters")
716
                .setClassOfItems(Object.class)
717
                .setMandatory(true);
718

    
719
        definition.addDynFieldString("featureTypeId").setMandatory(false);
720

    
721
        definition.addDynFieldList("attributeNames")
722
                .setClassOfItems(String.class)
723
                .setMandatory(false);
724

    
725
        definition.addDynFieldList("filter")
726
                .setClassOfItems(Expression.class)
727
                .setMandatory(false);
728

    
729
        definition.addDynFieldObject("order")
730
                .setClassOfValue(FeatureQueryOrder.class)
731
                .setMandatory(false);
732

    
733
        definition.addDynFieldLong("limit").setMandatory(false);
734

    
735
        definition.addDynFieldLong("pageSize").setMandatory(false);
736
        
737
        definition.addDynFieldBoolean("useSubquery").setMandatory(false);
738
       
739
        definition.addDynFieldList("groupByColumns")
740
                .setClassOfItems(String.class);
741

    
742
        definition.addDynFieldMap("aggregateFunctions")
743
                .setClassOfItems(String.class)
744
                .setClassOfValue(String.class);
745
    
746
        definition.addDynFieldObject("extraColumn")
747
                .setClassOfValue(DefaultFeatureExtraColumns.class);
748
                        
749
                definition.addDynFieldString("storeName").setMandatory(false);
750

    
751
    }
752

    
753
    @Override
754
    public long getLimit() {
755
        return limit;
756
    }
757

    
758
    @Override
759
    public long getPageSize() {
760
        return pageSize;
761
    }
762

    
763
    @Override
764
    public void setLimit(long limit) {
765
        this.limit = limit;
766
    }
767

    
768
    @Override
769
    public void clearLimit() {
770
        this.limit = NO_LIMIT;
771
    }
772
    
773
    @Override
774
    public void setPageSize(long pageSize) {
775
        this.pageSize = pageSize;
776
    }
777

    
778
    @Override
779
    public String[] getConstantsAttributeNames() {
780
        return (String[])constantsAttributeNames.toArray(new String[constantsAttributeNames.size()]);
781
    }
782

    
783
    @Override
784
    public void setConstantsAttributeNames(String[] constantsAttributeNames) {
785
        this.constantsAttributeNames.clear();
786
        if (constantsAttributeNames != null){
787
            for (int i=0 ; i<constantsAttributeNames.length ; i++){
788
                this.constantsAttributeNames.add(constantsAttributeNames[i]);
789
            }
790
        }
791
    }
792

    
793
    @Override
794
    public void addConstantAttributeName(String attributeName) {
795
        //If the attribute exists finish the method
796
        for (int i=0 ; i<constantsAttributeNames.size() ; i++){
797
            if (constantsAttributeNames.get(i).equals(attributeName)){
798
                return;
799
            }
800
        }
801
        this.constantsAttributeNames.add(attributeName);
802
    }
803

    
804
    @Override
805
    public boolean hasConstantsAttributeNames() {
806
        return !this.constantsAttributeNames.isEmpty();
807
    }
808

    
809
    @Override
810
    public void clearConstantsAttributeNames() {
811
        this.constantsAttributeNames = new ArrayList();
812
    }
813

    
814
  @Override
815
  public boolean isAGroupByColumn(String name) {
816
    if( groupByColumns==null ) {
817
        return false;
818
    }
819
    for (String columnName : groupByColumns) {
820
      if( StringUtils.equalsIgnoreCase(name, columnName) ) {
821
        return true;
822
      }
823
    }
824
    return false;
825
  }
826

    
827
  @Override
828
  public List<String> getGroupByColumns() {
829
    if( this.groupByColumns == null ) {
830
      this.groupByColumns = new ArrayList<>();
831
    }
832
    return this.groupByColumns;
833
  }
834

    
835
  @Override
836
  public void removeGroupByColumn(String colname) {
837
    if( this.groupByColumns == null ) {
838
      return;
839
    }
840
    this.groupByColumns.remove(colname);
841
  }
842
  
843
  @Override
844
  public void addAggregate(String funcName, String columnName) {
845
        Map<String, String> aggregateds = this.getAggregateFunctions();
846
        aggregateds.put(columnName, funcName);
847
  }
848

    
849
  @Override
850
  public Map<String, String> getAggregateFunctions() {
851
    if( this.aggregateFunctions == null ) {
852
      this.aggregateFunctions = new HashMap<>();
853
    }
854
    return this.aggregateFunctions;
855
  }
856

    
857
  @Override
858
  public void removeAggregateFunction(String colname) {
859
    if( this.aggregateFunctions == null ) {
860
      return;
861
    }
862
    this.aggregateFunctions.remove(colname);
863
  }
864
  
865
  @Override
866
  public String getAggregate(String name) {    
867
      String fn = this.getAggregateFunctions().get(name);
868
      if( StringUtils.isAlphanumeric(fn) ) {
869
        return fn + "(\""+ name + "\")";
870
      }
871
      return fn;
872
  }
873
  
874
  @Override
875
  public String getAggregate(String tableName, String name) {    
876
      String fn = this.getAggregateFunctions().get(name);
877
      if (!tableName.startsWith("\"")) {
878
         tableName = "\""+tableName+"\"";
879
      }
880
      if( StringUtils.isAlphanumeric(fn) ) {
881
        return fn + "("+tableName+".\""+ name + "\")";
882
      }
883
      return fn;
884
  }
885

    
886
    @Override
887
    public boolean isAggregate(String name) {
888
        return this.getAggregateFunctions().get(name) != null;
889
    }
890

    
891
  @Override
892
  public boolean hasAggregateFunctions() {
893
    return this.aggregateFunctions != null && !this.aggregateFunctions.isEmpty();
894
  }
895

    
896
  @Override
897
  public boolean hasGroupByColumns() {
898
    return this.groupByColumns != null && !this.groupByColumns.isEmpty();
899
  }
900

    
901
  @Override
902
  public void copyFrom(FeatureQuery query) {
903
    DefaultFeatureQuery other = (DefaultFeatureQuery) query;
904
    this.queryParameters = new HashMap();
905
    this.queryParameters.putAll(other.queryParameters);
906
    
907
    this.featureTypeId = other.featureTypeId;
908

    
909
    this.attributeNames.clear();
910
    this.attributeNames.addAll(other.attributeNames);
911

    
912
    this.constantsAttributeNames.clear();
913
    this.constantsAttributeNames.addAll(other.constantsAttributeNames);
914

    
915
    this.filter = other.filter;
916

    
917
    this.order.copyFrom(other.order);
918

    
919
    this.limit = other.limit;
920

    
921
    this.pageSize = other.pageSize;
922
    this.useSubquery = other.useSubquery;
923

    
924
    if( this.groupByColumns!=null && other.groupByColumns!=null ) {
925
      this.groupByColumns.clear();
926
      this.groupByColumns.addAll(other.groupByColumns);
927
    } else if( other.groupByColumns!=null ) {
928
      this.groupByColumns = new ArrayList<>();
929
      this.groupByColumns.addAll(other.groupByColumns);
930
    } else if( this.groupByColumns!=null ) {
931
      this.groupByColumns = null;
932
    }
933
    
934
    if( this.aggregateFunctions!=null && other.aggregateFunctions!=null ) {
935
      this.aggregateFunctions.clear();
936
      this.aggregateFunctions.putAll(other.aggregateFunctions);
937
    } else if( other.aggregateFunctions!=null ) {
938
      this.aggregateFunctions = new HashMap<>(other.aggregateFunctions);
939
    } else if( this.aggregateFunctions!=null ) {
940
      this.aggregateFunctions=null;
941
    }
942
    this.extraColumns.copyFrom(other.extraColumns);
943
    if( other.symbolTable!=null ) {
944
        try {
945
            this.symbolTable = other.symbolTable.clone();
946
        } catch (CloneNotSupportedException ex) {
947
            LOGGER.debug("Can't clone symbol table",ex);
948
        }
949
    }
950
        this.storeName = other.storeName;
951
  }
952

    
953
    @Override
954
    public FeatureExtraColumns getExtraColumns() {
955
        return this.extraColumns;
956
    }
957

    
958
    @Override
959
    @Deprecated
960
    public FeatureExtraColumns getExtraColumn() {
961
        return this.extraColumns;
962
    }
963

    
964
    @Override
965
    public MutableSymbolTable getSymbolTable() {
966
        return symbolTable;
967
    }
968

    
969
    @Override
970
    public void setSymbolTable(MutableSymbolTable symbolTable) {
971
        this.symbolTable = symbolTable;
972
    }
973

    
974
    @Override
975
    public void setVar(String name, Object value) {
976
        if( this.symbolTable==null ) {
977
            this.symbolTable = ExpressionUtils.createSymbolTable();
978
        }
979
        this.symbolTable.setVar(name, value);
980
    }
981

    
982
    @Override
983
    public boolean isUseSubquery() {
984
        return useSubquery;
985
    }
986

    
987
    @Override
988
    public void setUseSubquery(boolean useSubquery) {
989
        this.useSubquery = useSubquery;
990
    }
991
    
992
}