Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.remoteclient / src / main / java / org / gvsig / remoteclient / wfs / filters / filterencoding / FilterEncoding.java @ 40559

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

    
25
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
26
 *
27
 * Copyright (C) 2004 IVER T.I. and Generalitat Valenciana.
28
 *
29
 * This program is free software; you can redistribute it and/or
30
 * modify it under the terms of the GNU General Public License
31
 * as published by the Free Software Foundation; either version 2
32
 * of the License, or (at your option) any later version.
33
 *
34
 * This program is distributed in the hope that it will be useful,
35
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
37
 * GNU General Public License for more details.
38
 *
39
 * You should have received a copy of the GNU General Public License
40
 * along with this program; if not, write to the Free Software
41
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
42
 *
43
 * For more information, contact:
44
 *
45
 *  Generalitat Valenciana
46
 *   Conselleria d'Infraestructures i Transport
47
 *   Av. Blasco Ib??ez, 50
48
 *   46010 VALENCIA
49
 *   SPAIN
50
 *
51
 *      +34 963862235
52
 *   gvsig@gva.es
53
 *      www.gvsig.gva.es
54
 *
55
 *    or
56
 *
57
 *   IVER T.I. S.A
58
 *   Salamanca 50
59
 *   46005 Valencia
60
 *   Spain
61
 *
62
 *   +34 963163400
63
 *   dac@iver.es
64
 */
65
package org.gvsig.remoteclient.wfs.filters.filterencoding;
66
import java.util.ArrayList;
67
import java.util.Hashtable;
68
import java.util.Iterator;
69
import java.util.Set;
70

    
71
import org.gvsig.compat.CompatLocator;
72
import org.gvsig.compat.lang.StringUtils;
73
import org.gvsig.remoteclient.wfs.WFSStatus;
74
import org.gvsig.remoteclient.wfs.edition.WFSTTags;
75
import org.gvsig.remoteclient.wfs.filters.AbstractFilter;
76
import org.gvsig.remoteclient.wfs.filters.BinaryTree;
77
import org.gvsig.remoteclient.wfs.filters.BinaryTree.Node;
78
import org.gvsig.remoteclient.wfs.filters.DefaultSQLExpressionFormat;
79
import org.gvsig.remoteclient.wfs.filters.ISQLExpressionFormat;
80
import org.gvsig.remoteclient.wfs.filters.filterencoding.wfs_1_0_0.EnvelopeFEQuery1_0_0;
81
import org.gvsig.remoteclient.wfs.filters.filterencoding.wfs_1_1_0.EnvelopeFEQuery1_1_0;
82
import org.gvsig.remoteclient.wfs.filters.operations.WFSEnvelopeFilterOperation;
83
import org.gvsig.remoteclient.wfs.filters.operations.WFSGeometryFilterOperation;
84
import org.gvsig.remoteclient.wfs.filters.operations.WFSSpatialFilterOperation;
85

    
86
/**
87
 * This class implements the Filter Encoding Language. It is used to
88
 * create querys in this language
89
 * 
90
 * Name: OpenGIS? Filter Encoding Implementation Specification
91
 * Version: 1.1.0
92
 * Project Document: OGC 04-095 
93
 * @see http://portal.opengeospatial.org/files/?artifact_id=8340
94
 * 
95
 * @author Jorge Piera Llodra (piera_jor@gva.es)
96
 */
97
public class FilterEncoding extends AbstractFilter {
98
    public static final int RELATIONSHIP_PROPERTY = 0;
99
    public static final int RELATIONSHIP_VAUES = 1;
100

    
101
    private StringBuffer currentQuery = null;
102
    //Operation types
103
    private static final int OPERATION_PROPERTYNAME = 0;
104
    private static final int OPERATION_LITERAL = 1;
105
    
106
    //Filter namespace. 
107
    private String nameSpacePrefix = null;
108
    private String nameSpaceLocation = null;
109

    
110
    //If the Filter can have blanckSpaces
111
    private boolean hasBlankSpaces = true;
112
    private String defaultBlankSpace = "%20";
113
    //This character must be replaced by any set of characters (typically "*")
114
    private String wildCardChar = null;
115
    //This character must be replaced by one character (typically "?")
116
    private String singleChar = null;
117
    //Escape character (typically "\")
118
    private String escapeChar = null;
119
    //Default values
120
    public static final String DEFAULT_NAMESPACE_PREFIX = "ogc";
121
    public static final String DEFAULT_WILDCARD = "*";
122
    public static final String DEFAULT_SINGLECHAR = "?";
123
    public static final String DEFAULT_ESCAPE = "\\";
124
    public static final String DEFAULT_NAMESPACE = "xmlns:ogc=\"http://www.opengis.net/ogc\"";
125

    
126
    private Hashtable filterAttributes = new Hashtable();
127

    
128
    /**
129
     * If the namespace XML is qualified
130
     */
131
    private boolean isQualified = false;
132

    
133
    private static final StringUtils stringUtils = CompatLocator.getStringUtils();
134

    
135
    /**
136
     * Create a new Filter Encoding Parser
137
     * 
138
     * 
139
     * @param nameSpacePrefix
140
     * Filter namespace. (typically "ogc")
141
     * @param wildCardChar 
142
     * This character must be replaced by any set of characters (typically "*")
143
     * @param singleChar 
144
     * This character must be replaced by one character (typically "?")
145
     * @param escape 
146
     * Escape character
147
     * @param filterAttribute Sometimes, "Field" label needs an attribute.
148
     */
149
    public FilterEncoding(ISQLExpressionFormat formatter,String namesPacePrefix, String wildCard, String singleChar, String escape, Hashtable filterAttributes) {        
150
        super(formatter);
151
        if (namesPacePrefix == null){
152
            setQualified(false);
153
        }else{
154
            setQualified(true);
155
        }
156
        this.wildCardChar = wildCard;
157
        this.singleChar = singleChar;
158
        this.escapeChar = escape;
159
        this.filterAttributes = filterAttributes;
160
    } 
161

    
162

    
163
    /**
164
     * Create a new Filter Encoding Parser
165
     * @param formatter
166
     */
167
    public FilterEncoding(ISQLExpressionFormat formatter) {        
168
        this(formatter,null,DEFAULT_WILDCARD,DEFAULT_SINGLECHAR,
169
            DEFAULT_ESCAPE,new Hashtable());
170
    } 
171

    
172
    /**
173
     * Create a new Filter Encoding Parser
174
     */
175
    FilterEncoding() {        
176
        this(new DefaultSQLExpressionFormat());                
177
    }         
178

    
179
    /**
180
     * Create a new Filter Encoding Parser
181
     */
182
    public FilterEncoding(WFSStatus status) {        
183
        this();        
184
        this.nameSpacePrefix = status.getNamespacePrefix();
185
        this.nameSpaceLocation = status.getNamespaceLocation();
186
        setQueryByAttribute(status.getFilterByAttribute());
187
        clearSpatialFilters();
188
        addSpatialFilter(status.getFilterByArea());                
189
    } 
190

    
191
    /*
192
     *  (non-Javadoc)
193
     * @see org.gvsig.remoteClient.filterEncoding.QueryLanguage#toString(org.gvsig.remoteClient.filterEncoding.BinaryTree)
194
     */
195
    public String toString(BinaryTree tree, String version) {
196
        //If is a filter by ids...
197
        StringBuffer idQuery = null;
198
        if (getIds() != null){
199
            idQuery = new StringBuffer();
200
            ArrayList ids = getIds();
201
            for (int i=0 ; i<ids.size() ; i++){
202
                if (ids.get(i) != null){
203
                    Hashtable attributes = new Hashtable();
204
                    attributes.put("fid","\"" + ids.get(i).toString() + "\"");
205
                    idQuery.append(setTag("FeatureId", attributes, null));
206
                }
207
            }
208
            return enclosesWithFilterTag(idQuery.toString());
209
        }
210
        //If is a filter by attributes...
211
        String filterQuery = null;
212
        if ((tree.getRoot() == null) && (getSpatialFiltersCount() == 0)){
213
            return null;
214
        }
215
        if (tree.getRoot() != null){
216
            currentQuery = new StringBuffer();
217
            filterQuery = getFilterNode(tree.getRoot());
218
            if (getSpatialFiltersCount() == 0){
219
                return enclosesWithFilterTag(filterQuery);
220
            }
221
        }
222
        //If is a filter by area
223
        String bboxQuery = null;
224
        if (getSpatialFiltersCount() > 0){
225
            for (int i=0 ; i<getSpatialFiltersCount() ; i++){
226
                WFSSpatialFilterOperation spatialFilter = getSpatialFilterAt(i);
227
                SpatialFEQuery feQuery = null;
228
                if (spatialFilter instanceof WFSGeometryFilterOperation){
229
                    feQuery = new GeometryFEQuery((WFSGeometryFilterOperation)spatialFilter);
230
                }else if (spatialFilter instanceof WFSEnvelopeFilterOperation){
231
                    //TODO add this for a manager
232
                    if (version.equals("1.0.0")){
233
                        feQuery = new EnvelopeFEQuery1_0_0((WFSEnvelopeFilterOperation)spatialFilter);
234
                    }else{
235
                        feQuery = new EnvelopeFEQuery1_1_0((WFSEnvelopeFilterOperation)spatialFilter);  
236
                    }                                   
237
                }
238
                //If there is a spatial query
239
                if (feQuery != null){
240
                    bboxQuery = feQuery.getFilterEncoding();
241
                    if (tree.getRoot() == null){
242
                        String filter_bbox = enclosesWithFilterTag(bboxQuery); 
243
                        return filter_bbox;
244
                    }        
245
                }
246
            }
247
        }                
248
        return enclosesWithFilterTag(filterQuery + bboxQuery);
249
    }
250

    
251
    /**
252
     * Gets the filter code from a node
253
     * @param node
254
     */
255
    private String getFilterNode(Node node){
256
        if (node.isField()){
257
            return getExpression(node.getValue());
258
        }else{
259
            String left = "";
260
            String rigth = "";
261
            if (node.getLeftNode() != null){
262
                left = getFilterNode(node.getLeftNode());
263
            }
264
            if (node.getRigthNode() != null){
265
                rigth = getFilterNode(node.getRigthNode());
266
            }
267
            int operationCode = getLogicalOperator(node.getValue());
268
            String operation = getLogicalOperator(operationCode);
269
            return enterLabel(left+rigth, operation);
270
        }                
271
    }   
272

    
273
    /**
274
     * Parses a expresion like 'A op B' and returns the
275
     * expresion using the filter encoding language
276
     * @param expression
277
     * @return
278
     */
279
    private String getExpression(String expression){
280
        String[] words = stringUtils.split(expression, " ");
281
        //Param
282
        String param = words[0];
283
        if (param.charAt(0) == '"'){
284
            param = param.substring(1,param.length());
285
        }
286
        if (param.charAt(param.length()-1) == '"'){
287
            param = param.substring(0,param.length()-1);
288
        }
289
        //Operator
290
        String operator = words[1];
291
        //Value
292
        String value = words[2];                
293
        for (int i=3 ; i<words.length ; i++){
294
            value = value + " " + words[i];
295
        }
296
        if (value.charAt(0) == '\''){
297
            value = value.substring(1,value.length());
298
        }
299
        if (value.charAt(value.length()-1) == '\''){
300
            value = value.substring(0,value.length()-1);
301
        }
302
        int operatorCode = getRelationalOperator(operator);
303
        operator = getRelationalOperator(operatorCode);
304
        return createExpression(operator,param,value);
305
    }
306

    
307
    /**
308
     * It writes a "PropertyIsXXX" part of a filtyer encoding query
309
     * 
310
     * 
311
     * @return The part of the query
312
     * @param property Possible Values: PropertIsLike, PropertyIsLess, PropertyIsGreater,... See
313
     * the Filter Encoding documentation
314
     * @param parameter Parameter name
315
     * @param value Parameter value
316
     * @param type Values: "P" (to comparate two propertyes) or "L" (to comparate one property
317
     * and one literal value)
318
     */
319
    private String createExpression(String property, String parameter, String value) {        
320
        String cadena = "";
321
        cadena = "<" + WFSTTags.OGC_NAMESPACE_PREFIX + ":" + property;
322
        if (property.equals("PropertyIsLike")) {
323
            if (wildCardChar != null) {
324
                cadena = cadena + " wildCard=\"" + this.wildCardChar + "\"";
325
            }
326
            if (singleChar != null) {
327
                cadena = cadena + " singleChar=\"" + this.singleChar + "\"";
328
            }
329
            if (escapeChar != null) {
330
                cadena = cadena + " escape=\"" + this.escapeChar + "\"";
331
            }
332
        }
333
        cadena = cadena + ">" + enterLabel(nameSpacePrefix + ":" + parameter, "PropertyName");
334
        cadena = cadena + enterLabel(value, "Literal");
335
        return cadena + "</" + WFSTTags.OGC_NAMESPACE_PREFIX + ":" + property + ">";
336
    }         
337

    
338
    /**
339
     * Envuelve a una pregunta con una etiqueta
340
     * 
341
     * 
342
     * @return String : parte de la query en el lenguaje soportado
343
     * @param pregunta Pregunta a envolver
344
     * @param etiqueta Nombre de la etiqueta
345
     */
346
    private String enterLabel(String value, String tagName) {        
347
        if (tagName.equals("Filter") && (!(filterAttributes.isEmpty()))) {
348
            return setTag(tagName,filterAttributes,value);
349
        } else {
350
            return setTag(tagName,null,value);
351
        }
352
    } 
353

    
354
    /**
355
     * Envolves a value with an XML tag
356
     * 
357
     * @return String
358
     * XML tag with its value
359
     * @param tagName 
360
     * XML tag name
361
     * @param attributes
362
     * XML tag attributes
363
     * @param value 
364
     * Tag value
365
     */
366
    public String setTag(String tagName, Hashtable attributes, String value) {        
367
        StringBuffer tag = new StringBuffer();
368

    
369
        tag.append("<");
370
        tag.append(WFSTTags.OGC_NAMESPACE_PREFIX + ":");
371
        tag.append(tagName);            
372
        if (attributes != null){
373
            Set keys = attributes.keySet();
374
            if (attributes.size() > 0){
375
                Iterator it = keys.iterator();
376
                while (it.hasNext()){
377
                    String key = (String)it.next();
378
                    if (hasBlankSpaces){
379
                        tag.append(" ");
380
                    }else{
381
                        tag.append(defaultBlankSpace);
382
                    }
383
                    tag.append(key + "=" + (String)attributes.get(key));
384

    
385
                }
386
            }
387
        }
388
        if (value == null){
389
            tag.append("/>");
390
        }else{
391
            tag.append(">" + value);
392
            tag.append("</");
393
            tag.append(WFSTTags.OGC_NAMESPACE_PREFIX + ":");
394
            tag.append(tagName);
395
            tag.append(">");
396
        }
397
        return tag.toString();
398
    }
399

    
400

    
401
    /**
402
     * Encloses a query with the filter tag
403
     * @param query
404
     * @return
405
     */
406
    private String enclosesWithFilterTag(String query){
407
        StringBuffer filter = new StringBuffer();
408
        filter.append("<ogc:Filter");
409
        if (!isQualified){
410
            filter.append(" ");
411
            addNamespace(filter, WFSTTags.OGC_NAMESPACE_PREFIX, WFSTTags.OGC_NAMESPACE);
412
            addNamespace(filter, WFSTTags.GML_NAMESPACE_PREFIX, WFSTTags.GML_NAMESPACE);
413
            if (nameSpacePrefix != null){
414
                addNamespace(filter, nameSpacePrefix, nameSpaceLocation);
415
            }
416
            filter.append("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ");      
417
            filter.append("xsi:schemaLocation=\"http://www.opengis.net/ogc ../filter/1.0.0/filter.xsd http://www.opengis.net/gml ../gml/2.1.2/geometry.xsd\"");
418
        }
419
        filter.append(">");
420
        filter.append(query);
421
        filter.append("</ogc:Filter>");
422
        return filter.toString();
423
    }
424
    
425
    private void addNamespace(StringBuffer buffer, String nameSpacePrefix, String nameSpaceLocation){
426
        buffer.append(WFSTTags.XMLNS + ":" + nameSpacePrefix + "=\"" + nameSpaceLocation + "\" ");
427
    }
428

    
429
    /*
430
     *  (non-Javadoc)
431
     * @see org.gvsig.remoteClient.filterEncoding.AQueryLanguage#getLogicOperator(int)
432
     */
433
    public String getLogicalOperator(int operator) {
434
        switch (operator){
435
        case LOGICAL_OPERATOR_AND:
436
            return "And";
437
        case LOGICAL_OPERATOR_OR:
438
            return "Or";
439
        case LOGICAL_OPERATOR_NOT:
440
            return "Not";
441
        default:
442
            return "And";
443
        }    
444
    } 
445

    
446
    /*
447
     *  (non-Javadoc)
448
     * @see org.gvsig.remoteClient.filterEncoding.AQueryLanguage#getRelationalOperator(int)
449
     */
450
    public String getRelationalOperator(int operator) {
451
        switch (operator){
452
        case RELATIONAL_OPERATOR_IS_EQUALS_TO:
453
            return "PropertyIsEqualTo";
454
        case RELATIONAL_OPERATOR_IS_NOT_EQUALS_TO:
455
            return "PropertyIsNotEqualTo";
456
        case RELATIONAL_OPERATOR_IS_LESS_THAN:
457
            return "PropertyIsLessThan";
458
        case RELATIONAL_OPERATOR_IS_GREATER_THAN:
459
            return "PropertyIsGreaterThan";
460
        case RELATIONAL_OPERATOR_IS_LESS_THAN_OR_EQUAL_TO:
461
            return "PropertyIsLessThanOrEqualTo";
462
        case RELATIONAL_OPERATOR_IS_GREATER_THAN_OR_EQUAL_TO:
463
            return "PropertyIsGreaterThanOrEqualTo";
464
        case RELATIONAL_OPERATOR_IS_LIKE:
465
            return "PropertyIsLike";
466
        case RELATIONAL_OPERATOR_IS_NULL:
467
            return "PropertyIsNull";
468
        case RELATIONAL_OPERATOR_IS_BETWEEN:
469
            return "PropertyIsBetween";
470
        default:
471
            return "PropertyIsLike";
472
        }
473
    }
474

    
475
    /*
476
     *  (non-Javadoc)
477
     * @see org.gvsig.remoteClient.filterEncoding.AQueryLanguage#getGeometricOperator(int)
478
     */
479
    public String getGeometricOperator(int operator) {
480
        switch (operator){
481
        case GEOMETRIC_OPERATOR_EQUALS:
482
            return "Equals";
483
        case GEOMETRIC_OPERATOR_DISJOINT:
484
            return "Disjoint";
485
        case GEOMETRIC_OPERATOR_TOUCHES:
486
            return "Touches";
487
        case GEOMETRIC_OPERATOR_WITHIN:
488
            return "Within";
489
        case GEOMETRIC_OPERATOR_OVERLAPS:
490
            return "Overlaps";
491
        case GEOMETRIC_OPERATOR_CROSSES:
492
            return "Crosses";
493
        case GEOMETRIC_OPERATOR_INTERSECT:
494
            return "Intersect";
495
        case GEOMETRIC_OPERATOR_CONTAINS:
496
            return "Contains";
497
        case GEOMETRIC_OPERATOR_DWITHIN:
498
            return "Dwithin";
499
        case GEOMETRIC_OPERATOR_BEYOND:
500
            return "Beyond";
501
        case GEOMETRIC_OPERATOR_BBOX:
502
            return "BBOX";
503
        default:
504
            return "Equals";
505
        } 
506

    
507
    }
508

    
509
    public String getSeparator(int separator) {
510
        return null;
511
    }
512

    
513
    /**
514
     * @param isQualified the isQualified to set
515
     */
516
    public void setQualified(boolean isQualified) {
517
        this.isQualified = isQualified;
518
        if (isQualified){
519
            nameSpacePrefix = DEFAULT_NAMESPACE_PREFIX + ":";
520
        }else{
521
            nameSpacePrefix = "";
522
        }
523
    }
524

    
525

    
526
    /**
527
     * @param namepacePrefix the namepacePrefix to set
528
     */
529
    public void setNamepacePrefix(String namepacePrefix) {
530
        if ((namepacePrefix == null) || (namepacePrefix.equals(""))){
531
            this.nameSpacePrefix = "";
532
        }else{
533
            this.nameSpacePrefix = namepacePrefix + ":";
534
        }
535
    }
536

    
537

    
538
    /**
539
     * @param hasBlankSpaces the hasBlankSpaces to set
540
     */
541
    public void setHasBlankSpaces(boolean hasBlankSpaces) {
542
        this.hasBlankSpaces = hasBlankSpaces;
543
    }
544
}