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

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

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

    
96
    public static final String SCALE_PARAM_NAME = "Scale";
97
    
98
    private static final Version VERSION_2_6_0 = ToolsLocator.getPackageManager().createVersion("2.6.0");
99

    
100
    private Map<String,Object> queryParameters = new HashMap();
101

    
102
    private String featureTypeId = null;
103

    
104
    private List<String> attributeNames = new ArrayList();
105

    
106
    private List<String> constantsAttributeNames = new ArrayList();
107

    
108
    private Evaluator filter;
109

    
110
    private FeatureQueryOrder order = new DefaultFeatureQueryOrder();
111

    
112
    private long limit;
113

    
114
    private long pageSize;
115

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

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

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

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

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

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

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

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

    
245
    @Override
246
    public void setScale(double scale) {
247
        this.setQueryParameter(SCALE_PARAM_NAME, scale);
248
    }
249

    
250
    @Override
251
    public Object getQueryParameter(String name) {
252
        return queryParameters.get(name);
253
    }
254

    
255
    @Override
256
    public void setQueryParameter(String name, Object value) {
257
        queryParameters.put(name, value);
258
    }
259

    
260
    @Override
261
    public void setFeatureType(FeatureType featureType) {
262
        this.featureTypeId = featureType.getId();
263
    }
264

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

    
285
    @Override
286
    public void setAttributeNames(String[] attributeNames) {
287
        this.attributeNames.clear();
288
        if (attributeNames != null){
289
            for (int i=0 ; i<attributeNames.length ; i++){
290
                this.attributeNames.add(attributeNames[i]);
291
            }
292
        }
293
    }
294

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
481
            for (int i=0 ; i<fieldNames.length ; i++){
482
                addAttributeName(fieldNames[i]);
483
            }
484
        }
485
    }
486

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

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

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

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

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

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

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

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

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

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

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

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

    
645
    }
646
    
647

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

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

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

    
716
    
717
    }
718

    
719
    /**
720
     * Register the class on PersistenceManager
721
     *
722
     */
723
    public static void registerPersistent() {
724
        DynStruct definition =
725
            ToolsLocator.getPersistenceManager()
726
            .addDefinition(DefaultFeatureQuery.class,
727
                "DefaultFeatureQuery",
728
                "DefaultFeatureQuery Persistent definition",
729
                null,
730
                null);
731

    
732
        
733
        definition.addDynFieldObject("version")
734
                .setClassOfValue(DefaultVersion.class)
735
                .setMandatory(false);
736

    
737
        definition.addDynFieldMap("queryParameters")
738
                .setClassOfItems(Object.class)
739
                .setMandatory(true);
740

    
741
        definition.addDynFieldString("featureTypeId").setMandatory(false);
742

    
743
        definition.addDynFieldList("attributeNames")
744
                .setClassOfItems(String.class)
745
                .setMandatory(false);
746

    
747
        definition.addDynFieldList("filter")
748
                .setClassOfItems(Expression.class)
749
                .setMandatory(false);
750

    
751
        definition.addDynFieldObject("order")
752
                .setClassOfValue(FeatureQueryOrder.class)
753
                .setMandatory(false);
754

    
755
        definition.addDynFieldLong("limit").setMandatory(false);
756

    
757
        definition.addDynFieldLong("pageSize").setMandatory(false);
758
        
759
        definition.addDynFieldBoolean("useSubquery").setMandatory(false);
760
       
761
        definition.addDynFieldList("groupByColumns")
762
                .setClassOfItems(String.class);
763

    
764
        definition.addDynFieldMap("aggregateFunctions")
765
                .setClassOfItems(String.class)
766
                .setClassOfValue(String.class);
767
    
768
        definition.addDynFieldObject("extraColumn")
769
                .setClassOfValue(DefaultFeatureExtraColumns.class);
770
                        
771
                definition.addDynFieldString("storeName").setMandatory(false);
772

    
773
    }
774

    
775
    @Override
776
    public long getLimit() {
777
        return limit;
778
    }
779

    
780
    @Override
781
    public long getPageSize() {
782
        return pageSize;
783
    }
784

    
785
    @Override
786
    public void setLimit(long limit) {
787
        this.limit = limit;
788
    }
789

    
790
    @Override
791
    public void clearLimit() {
792
        this.limit = NO_LIMIT;
793
    }
794
    
795
    @Override
796
    public void setPageSize(long pageSize) {
797
        this.pageSize = pageSize;
798
    }
799

    
800
    @Override
801
    public String[] getConstantsAttributeNames() {
802
        return (String[])constantsAttributeNames.toArray(new String[constantsAttributeNames.size()]);
803
    }
804

    
805
    @Override
806
    public void setConstantsAttributeNames(String[] constantsAttributeNames) {
807
        this.constantsAttributeNames.clear();
808
        if (constantsAttributeNames != null){
809
            for (int i=0 ; i<constantsAttributeNames.length ; i++){
810
                this.constantsAttributeNames.add(constantsAttributeNames[i]);
811
            }
812
        }
813
    }
814

    
815
    @Override
816
    public void addConstantAttributeName(String attributeName) {
817
        //If the attribute exists finish the method
818
        for (int i=0 ; i<constantsAttributeNames.size() ; i++){
819
            if (constantsAttributeNames.get(i).equals(attributeName)){
820
                return;
821
            }
822
        }
823
        this.constantsAttributeNames.add(attributeName);
824
    }
825

    
826
    @Override
827
    public boolean hasConstantsAttributeNames() {
828
        return !this.constantsAttributeNames.isEmpty();
829
    }
830

    
831
    @Override
832
    public void clearConstantsAttributeNames() {
833
        this.constantsAttributeNames = new ArrayList();
834
    }
835

    
836
  @Override
837
  public boolean isAGroupByColumn(String name) {
838
    if( groupByColumns==null ) {
839
        return false;
840
    }
841
    for (String columnName : groupByColumns) {
842
      if( StringUtils.equalsIgnoreCase(name, columnName) ) {
843
        return true;
844
      }
845
    }
846
    return false;
847
  }
848

    
849
  @Override
850
  public List<String> getGroupByColumns() {
851
    if( this.groupByColumns == null ) {
852
      this.groupByColumns = new ArrayList<>();
853
    }
854
    return this.groupByColumns;
855
  }
856

    
857
  @Override
858
  public void removeGroupByColumn(String colname) {
859
    if( this.groupByColumns == null ) {
860
      return;
861
    }
862
    this.groupByColumns.remove(colname);
863
  }
864
  
865
  @Override
866
  public void addAggregate(String funcName, String columnName) {
867
        Map<String, String> aggregateds = this.getAggregateFunctions();
868
        aggregateds.put(columnName, funcName);
869
  }
870

    
871
  @Override
872
  public Map<String, String> getAggregateFunctions() {
873
    if( this.aggregateFunctions == null ) {
874
      this.aggregateFunctions = new HashMap<>();
875
    }
876
    return this.aggregateFunctions;
877
  }
878

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

    
928
    @Override
929
    public boolean isAggregate(String name) {
930
        return this.getAggregateFunction(name) != null;
931
    }
932

    
933
  @Override
934
  public boolean hasAggregateFunctions() {
935
    return this.aggregateFunctions != null && !this.aggregateFunctions.isEmpty();
936
  }
937

    
938
  @Override
939
  public boolean hasGroupByColumns() {
940
    return this.groupByColumns != null && !this.groupByColumns.isEmpty();
941
  }
942

    
943
  private void clear() {
944
        this.queryParameters = new HashMap();
945
        
946
//        this.featureTypeId = other.featureTypeId;
947
//        this.storeName = other.storeName;
948

    
949
        this.clearConstantsAttributeNames();
950
        this.clearAttributeNames();
951
        this.clearFilter();
952
        this.clearLimit();
953
        this.setOrder(null);
954
        this.useSubquery = true; // true for backwards compatibility. 
955
        this.limit = NO_LIMIT;
956
        this.pageSize = 0;
957
        this.groupByColumns = null;
958
        this.aggregateFunctions=null;
959
        this.extraColumns = new DefaultFeatureExtraColumns();
960
        this.symbolTable = null;
961

    
962
  }
963
  
964
  @Override
965
  public void copyFrom(FeatureQuery query) {
966
    if( query == null ) {
967
        this.clear();
968
        return;
969
    }
970
    DefaultFeatureQuery other = (DefaultFeatureQuery) query;
971
    this.queryParameters = new HashMap();
972
    this.queryParameters.putAll(other.queryParameters);
973
    
974
    this.featureTypeId = other.featureTypeId;
975

    
976
    this.attributeNames.clear();
977
    this.attributeNames.addAll(other.attributeNames);
978

    
979
    this.constantsAttributeNames.clear();
980
    this.constantsAttributeNames.addAll(other.constantsAttributeNames);
981

    
982
    this.filter = other.filter;
983

    
984
    this.order.copyFrom(other.order);
985

    
986
    this.limit = other.limit;
987

    
988
    this.pageSize = other.pageSize;
989
    this.useSubquery = other.useSubquery;
990

    
991
    if( this.groupByColumns!=null && other.groupByColumns!=null ) {
992
      this.groupByColumns.clear();
993
      this.groupByColumns.addAll(other.groupByColumns);
994
    } else if( other.groupByColumns!=null ) {
995
      this.groupByColumns = new ArrayList<>();
996
      this.groupByColumns.addAll(other.groupByColumns);
997
    } else if( this.groupByColumns!=null ) {
998
      this.groupByColumns = null;
999
    }
1000
    
1001
    if( this.aggregateFunctions!=null && other.aggregateFunctions!=null ) {
1002
      this.aggregateFunctions.clear();
1003
      this.aggregateFunctions.putAll(other.aggregateFunctions);
1004
    } else if( other.aggregateFunctions!=null ) {
1005
      this.aggregateFunctions = new HashMap<>(other.aggregateFunctions);
1006
    } else if( this.aggregateFunctions!=null ) {
1007
      this.aggregateFunctions=null;
1008
    }
1009
    this.extraColumns.copyFrom(other.extraColumns);
1010
    if( other.symbolTable!=null ) {
1011
        try {
1012
            this.symbolTable = other.symbolTable.clone();
1013
        } catch (CloneNotSupportedException ex) {
1014
            LOGGER.debug("Can't clone symbol table",ex);
1015
        }
1016
    }
1017
        this.storeName = other.storeName;
1018
  }
1019

    
1020
    @Override
1021
    public FeatureExtraColumns getExtraColumns() {
1022
        return this.extraColumns;
1023
    }
1024

    
1025
    @Override
1026
    @Deprecated
1027
    public FeatureExtraColumns getExtraColumn() {
1028
        return this.extraColumns;
1029
    }
1030

    
1031
    @Override
1032
    public MutableSymbolTable getSymbolTable() {
1033
        return symbolTable;
1034
    }
1035

    
1036
    @Override
1037
    public void setSymbolTable(MutableSymbolTable symbolTable) {
1038
        this.symbolTable = symbolTable;
1039
    }
1040

    
1041
    @Override
1042
    public void setVar(String name, Object value) {
1043
        if( this.symbolTable==null ) {
1044
            this.symbolTable = ExpressionUtils.createSymbolTable();
1045
        }
1046
        this.symbolTable.setVar(name, value);
1047
    }
1048

    
1049
    @Override
1050
    public boolean isUseSubquery() {
1051
        return useSubquery;
1052
    }
1053

    
1054
    @Override
1055
    public void setUseSubquery(boolean useSubquery) {
1056
        this.useSubquery = useSubquery;
1057
    }
1058
    
1059
}