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

History | View | Annotate | Download (32.4 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

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

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

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

    
98
    private String featureTypeId = null;
99

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

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

    
104
    private Evaluator filter;
105

    
106
    private FeatureQueryOrder order = new DefaultFeatureQueryOrder();
107

    
108
    private long limit;
109

    
110
    private long pageSize;
111

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
371
    @Override
372
    public Evaluator getFilter() {
373
      if( this.filter instanceof ExpressionEvaluator ) {
374
        ExpressionEvaluator eefilter = (ExpressionEvaluator) this.filter;
375
        if( symbolTable != null ) {
376
            eefilter.addSymbolTable(symbolTable);
377
        }
378
      }
379
      return filter;
380
    }
381

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

    
394
    @Override
395
    public void setFilter(Expression filter) {
396
        if( filter == null ) {
397
            this.clearFilter();
398
            return;
399
        }
400
        Evaluator x = new DefaultFeatureExpressionEvaluator(storeName, filter);
401
        this.setFilter(x);
402
    }
403

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

    
417
    @Override
418
    public void setFilter(Evaluator filter) {
419
        if( filter == null ) {
420
            this.clearFilter();
421
            return;
422
        }        
423
        this.filter = filter;
424
        addFilterAttributes(filter);
425
    }
426

    
427
    @Override
428
    public void addFilter(String filter) {
429
        if( StringUtils.isEmpty(filter) ) {
430
            return;
431
        }
432
        this.addFilter(ExpressionUtils.createExpression(filter));
433
    }
434

    
435
    @Override
436
    public void addFilter(Expression filter) {
437
        Evaluator x = new DefaultFeatureExpressionEvaluator(filter);
438
        this.addFilter(x);
439
    }
440

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

    
459
    @Override
460
    public void clearFilter() {
461
      this.filter = null;
462
    }
463

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

    
477
            for (int i=0 ; i<fieldNames.length ; i++){
478
                addAttributeName(fieldNames[i]);
479
            }
480
        }
481
    }
482

    
483
    @Override
484
    public FeatureQueryOrder getOrder() {
485
        return order;
486
    }
487

    
488
    @Override
489
    public void setOrder(FeatureQueryOrder order) {
490
        if(order == null){
491
            this.order = new DefaultFeatureQueryOrder();
492
        } else {
493
            this.order = order;
494
        }
495
    }
496

    
497
    @Override
498
    public boolean hasFilter() {
499
        return this.filter != null;
500
    }
501

    
502
    @Override
503
    public boolean hasLimit() {
504
        return this.limit != NO_LIMIT;
505
    }
506

    
507
    @Override
508
    public boolean hasOrder() {
509
        return this.order != null && this.order.size() > 0;
510
    }
511

    
512
    @Override
513
    public Object clone() throws CloneNotSupportedException {
514
        DefaultFeatureQuery clone = (DefaultFeatureQuery) super.clone();
515

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

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

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

    
587
    @Override
588
    public String getFeatureTypeId() {
589
        return featureTypeId;
590
    }
591

    
592
    @Override
593
    public void setFeatureTypeId(String featureTypeId) {
594
        this.featureTypeId = featureTypeId;
595
    }
596

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

    
640
    }
641
    
642

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

    
671
                    if (andEvaluator == null) {
672
                        andEvaluator = new AndEvaluator(evaluator);
673
                    } else {
674
                        andEvaluator.addEvaluator(evaluator);
675
                    }
676
                } catch (InitializeException ex) {
677
                    LOGGER.warn("Can't create AndEvaluator", ex);//TODO evaluator a null
678
                    break;
679
                }
680
                this.filter = evaluator;
681

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

    
705
    
706
    }
707

    
708
    /**
709
     * Register the class on PersistenceManager
710
     *
711
     */
712
    public static void registerPersistent() {
713
        DynStruct definition =
714
            ToolsLocator.getPersistenceManager()
715
            .addDefinition(DefaultFeatureQuery.class,
716
                "DefaultFeatureQuery",
717
                "DefaultFeatureQuery Persistent definition",
718
                null,
719
                null);
720

    
721
        definition.addDynFieldMap("queryParameters")
722
                .setClassOfItems(Object.class)
723
                .setMandatory(true);
724

    
725
        definition.addDynFieldString("featureTypeId").setMandatory(false);
726

    
727
        definition.addDynFieldList("attributeNames")
728
                .setClassOfItems(String.class)
729
                .setMandatory(false);
730

    
731
        definition.addDynFieldList("filter")
732
                .setClassOfItems(Expression.class)
733
                .setMandatory(false);
734

    
735
        definition.addDynFieldObject("order")
736
                .setClassOfValue(FeatureQueryOrder.class)
737
                .setMandatory(false);
738

    
739
        definition.addDynFieldLong("limit").setMandatory(false);
740

    
741
        definition.addDynFieldLong("pageSize").setMandatory(false);
742
        
743
        definition.addDynFieldBoolean("useSubquery").setMandatory(false);
744
       
745
        definition.addDynFieldList("groupByColumns")
746
                .setClassOfItems(String.class);
747

    
748
        definition.addDynFieldMap("aggregateFunctions")
749
                .setClassOfItems(String.class)
750
                .setClassOfValue(String.class);
751
    
752
        definition.addDynFieldObject("extraColumn")
753
                .setClassOfValue(DefaultFeatureExtraColumns.class);
754
                        
755
                definition.addDynFieldString("storeName").setMandatory(false);
756

    
757
    }
758

    
759
    @Override
760
    public long getLimit() {
761
        return limit;
762
    }
763

    
764
    @Override
765
    public long getPageSize() {
766
        return pageSize;
767
    }
768

    
769
    @Override
770
    public void setLimit(long limit) {
771
        this.limit = limit;
772
    }
773

    
774
    @Override
775
    public void clearLimit() {
776
        this.limit = NO_LIMIT;
777
    }
778
    
779
    @Override
780
    public void setPageSize(long pageSize) {
781
        this.pageSize = pageSize;
782
    }
783

    
784
    @Override
785
    public String[] getConstantsAttributeNames() {
786
        return (String[])constantsAttributeNames.toArray(new String[constantsAttributeNames.size()]);
787
    }
788

    
789
    @Override
790
    public void setConstantsAttributeNames(String[] constantsAttributeNames) {
791
        this.constantsAttributeNames.clear();
792
        if (constantsAttributeNames != null){
793
            for (int i=0 ; i<constantsAttributeNames.length ; i++){
794
                this.constantsAttributeNames.add(constantsAttributeNames[i]);
795
            }
796
        }
797
    }
798

    
799
    @Override
800
    public void addConstantAttributeName(String attributeName) {
801
        //If the attribute exists finish the method
802
        for (int i=0 ; i<constantsAttributeNames.size() ; i++){
803
            if (constantsAttributeNames.get(i).equals(attributeName)){
804
                return;
805
            }
806
        }
807
        this.constantsAttributeNames.add(attributeName);
808
    }
809

    
810
    @Override
811
    public boolean hasConstantsAttributeNames() {
812
        return !this.constantsAttributeNames.isEmpty();
813
    }
814

    
815
    @Override
816
    public void clearConstantsAttributeNames() {
817
        this.constantsAttributeNames = new ArrayList();
818
    }
819

    
820
  @Override
821
  public boolean isAGroupByColumn(String name) {
822
    if( groupByColumns==null ) {
823
        return false;
824
    }
825
    for (String columnName : groupByColumns) {
826
      if( StringUtils.equalsIgnoreCase(name, columnName) ) {
827
        return true;
828
      }
829
    }
830
    return false;
831
  }
832

    
833
  @Override
834
  public List<String> getGroupByColumns() {
835
    if( this.groupByColumns == null ) {
836
      this.groupByColumns = new ArrayList<>();
837
    }
838
    return this.groupByColumns;
839
  }
840

    
841
  @Override
842
  public void removeGroupByColumn(String colname) {
843
    if( this.groupByColumns == null ) {
844
      return;
845
    }
846
    this.groupByColumns.remove(colname);
847
  }
848
  
849
  @Override
850
  public void addAggregate(String funcName, String columnName) {
851
        Map<String, String> aggregateds = this.getAggregateFunctions();
852
        aggregateds.put(columnName, funcName);
853
  }
854

    
855
  @Override
856
  public Map<String, String> getAggregateFunctions() {
857
    if( this.aggregateFunctions == null ) {
858
      this.aggregateFunctions = new HashMap<>();
859
    }
860
    return this.aggregateFunctions;
861
  }
862

    
863
  @Override
864
  public void removeAggregateFunction(String colname) {
865
    if( this.aggregateFunctions == null ) {
866
      return;
867
    }
868
    for (Iterator<Map.Entry<String, String>> iterator = this.getAggregateFunctions().entrySet().iterator(); iterator.hasNext();) {
869
        Map.Entry<String, String> entry = iterator.next();
870
        String attrName = entry.getKey();
871
        String function = entry.getValue();
872
        if(StringUtils.equalsIgnoreCase(colname, attrName)){
873
            iterator.remove();
874
            return;
875
        }
876
    }
877
  }
878
  
879
  @Override
880
  public String getAggregateFunction(String name){
881
      for (Map.Entry<String, String> entry : this.getAggregateFunctions().entrySet()) {
882
          String attrName = entry.getKey();
883
          String function = entry.getValue();
884
          if(StringUtils.equalsIgnoreCase(name, attrName)){
885
              return function;
886
          }
887
      }
888
      return null;
889
  }
890
  
891
  @Override
892
  public String getAggregate(String name) {    
893
      String fn = this.getAggregateFunction(name);
894
      if( StringUtils.isAlphanumeric(fn) ) {
895
        return fn + "(\""+ name + "\")";
896
      }
897
      return fn;
898
  }
899
  
900
  @Override
901
  public String getAggregate(String tableName, String name) {    
902
      String fn = this.getAggregateFunction(name);
903
      if (!tableName.startsWith("\"")) {
904
         tableName = "\""+tableName+"\"";
905
      }
906
      if( StringUtils.isAlphanumeric(fn) ) {
907
        return fn + "("+tableName+".\""+ name + "\")";
908
      }
909
      return fn;
910
  }
911

    
912
    @Override
913
    public boolean isAggregate(String name) {
914
        return this.getAggregateFunction(name) != null;
915
    }
916

    
917
  @Override
918
  public boolean hasAggregateFunctions() {
919
    return this.aggregateFunctions != null && !this.aggregateFunctions.isEmpty();
920
  }
921

    
922
  @Override
923
  public boolean hasGroupByColumns() {
924
    return this.groupByColumns != null && !this.groupByColumns.isEmpty();
925
  }
926

    
927
  private void clear() {
928
        this.queryParameters = new HashMap();
929
        
930
//        this.featureTypeId = other.featureTypeId;
931
//        this.storeName = other.storeName;
932

    
933
        this.clearConstantsAttributeNames();
934
        this.clearAttributeNames();
935
        this.clearFilter();
936
        this.clearLimit();
937
        this.setOrder(null);
938
        this.useSubquery = true; // true for backwards compatibility. 
939
        this.limit = NO_LIMIT;
940
        this.pageSize = 0;
941
        this.groupByColumns = null;
942
        this.aggregateFunctions=null;
943
        this.extraColumns = new DefaultFeatureExtraColumns();
944
        this.symbolTable = null;
945

    
946
  }
947
  
948
  @Override
949
  public void copyFrom(FeatureQuery query) {
950
    if( query == null ) {
951
        this.clear();
952
        return;
953
    }
954
    DefaultFeatureQuery other = (DefaultFeatureQuery) query;
955
    this.queryParameters = new HashMap();
956
    this.queryParameters.putAll(other.queryParameters);
957
    
958
    this.featureTypeId = other.featureTypeId;
959

    
960
    this.attributeNames.clear();
961
    this.attributeNames.addAll(other.attributeNames);
962

    
963
    this.constantsAttributeNames.clear();
964
    this.constantsAttributeNames.addAll(other.constantsAttributeNames);
965

    
966
    this.filter = other.filter;
967

    
968
    this.order.copyFrom(other.order);
969

    
970
    this.limit = other.limit;
971

    
972
    this.pageSize = other.pageSize;
973
    this.useSubquery = other.useSubquery;
974

    
975
    if( this.groupByColumns!=null && other.groupByColumns!=null ) {
976
      this.groupByColumns.clear();
977
      this.groupByColumns.addAll(other.groupByColumns);
978
    } else if( other.groupByColumns!=null ) {
979
      this.groupByColumns = new ArrayList<>();
980
      this.groupByColumns.addAll(other.groupByColumns);
981
    } else if( this.groupByColumns!=null ) {
982
      this.groupByColumns = null;
983
    }
984
    
985
    if( this.aggregateFunctions!=null && other.aggregateFunctions!=null ) {
986
      this.aggregateFunctions.clear();
987
      this.aggregateFunctions.putAll(other.aggregateFunctions);
988
    } else if( other.aggregateFunctions!=null ) {
989
      this.aggregateFunctions = new HashMap<>(other.aggregateFunctions);
990
    } else if( this.aggregateFunctions!=null ) {
991
      this.aggregateFunctions=null;
992
    }
993
    this.extraColumns.copyFrom(other.extraColumns);
994
    if( other.symbolTable!=null ) {
995
        try {
996
            this.symbolTable = other.symbolTable.clone();
997
        } catch (CloneNotSupportedException ex) {
998
            LOGGER.debug("Can't clone symbol table",ex);
999
        }
1000
    }
1001
        this.storeName = other.storeName;
1002
  }
1003

    
1004
    @Override
1005
    public FeatureExtraColumns getExtraColumns() {
1006
        return this.extraColumns;
1007
    }
1008

    
1009
    @Override
1010
    @Deprecated
1011
    public FeatureExtraColumns getExtraColumn() {
1012
        return this.extraColumns;
1013
    }
1014

    
1015
    @Override
1016
    public MutableSymbolTable getSymbolTable() {
1017
        return symbolTable;
1018
    }
1019

    
1020
    @Override
1021
    public void setSymbolTable(MutableSymbolTable symbolTable) {
1022
        this.symbolTable = symbolTable;
1023
    }
1024

    
1025
    @Override
1026
    public void setVar(String name, Object value) {
1027
        if( this.symbolTable==null ) {
1028
            this.symbolTable = ExpressionUtils.createSymbolTable();
1029
        }
1030
        this.symbolTable.setVar(name, value);
1031
    }
1032

    
1033
    @Override
1034
    public boolean isUseSubquery() {
1035
        return useSubquery;
1036
    }
1037

    
1038
    @Override
1039
    public void setUseSubquery(boolean useSubquery) {
1040
        this.useSubquery = useSubquery;
1041
    }
1042
    
1043
}