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

History | View | Annotate | Download (17.7 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
package org.gvsig.remoteclient.wfs.filters.filterencoding;
26
import java.util.ArrayList;
27
import java.util.Hashtable;
28
import java.util.Iterator;
29
import java.util.Set;
30

    
31
import org.gvsig.compat.CompatLocator;
32
import org.gvsig.compat.lang.StringUtils;
33
import org.gvsig.remoteclient.wfs.WFSStatus;
34
import org.gvsig.remoteclient.wfs.edition.WFSTTags;
35
import org.gvsig.remoteclient.wfs.filters.AbstractFilter;
36
import org.gvsig.remoteclient.wfs.filters.BinaryTree;
37
import org.gvsig.remoteclient.wfs.filters.BinaryTree.Node;
38
import org.gvsig.remoteclient.wfs.filters.DefaultSQLExpressionFormat;
39
import org.gvsig.remoteclient.wfs.filters.ISQLExpressionFormat;
40
import org.gvsig.remoteclient.wfs.filters.filterencoding.wfs_1_0_0.EnvelopeFEQuery1_0_0;
41
import org.gvsig.remoteclient.wfs.filters.filterencoding.wfs_1_1_0.EnvelopeFEQuery1_1_0;
42
import org.gvsig.remoteclient.wfs.filters.operations.WFSEnvelopeFilterOperation;
43
import org.gvsig.remoteclient.wfs.filters.operations.WFSGeometryFilterOperation;
44
import org.gvsig.remoteclient.wfs.filters.operations.WFSSpatialFilterOperation;
45

    
46
/**
47
 * This class implements the Filter Encoding Language. It is used to
48
 * create querys in this language
49
 * 
50
 * Name: OpenGIS? Filter Encoding Implementation Specification
51
 * Version: 1.1.0
52
 * Project Document: OGC 04-095 
53
 * @see http://portal.opengeospatial.org/files/?artifact_id=8340
54
 * 
55
 * @author Jorge Piera Llodra (piera_jor@gva.es)
56
 */
57
public class FilterEncoding extends AbstractFilter {
58
    public static final int RELATIONSHIP_PROPERTY = 0;
59
    public static final int RELATIONSHIP_VAUES = 1;
60

    
61
    private StringBuffer currentQuery = null;
62
    //Operation types
63
    private static final int OPERATION_PROPERTYNAME = 0;
64
    private static final int OPERATION_LITERAL = 1;
65
    
66
    //Filter namespace. 
67
    private String nameSpacePrefix = null;
68
    private String nameSpaceLocation = null;
69

    
70
    //If the Filter can have blanckSpaces
71
    private boolean hasBlankSpaces = true;
72
    private String defaultBlankSpace = "%20";
73
    //This character must be replaced by any set of characters (typically "*")
74
    private String wildCardChar = null;
75
    //This character must be replaced by one character (typically "?")
76
    private String singleChar = null;
77
    //Escape character (typically "\")
78
    private String escapeChar = null;
79
    //Default values
80
    public static final String DEFAULT_NAMESPACE_PREFIX = "ogc";
81
    public static final String DEFAULT_WILDCARD = "*";
82
    public static final String DEFAULT_SINGLECHAR = "?";
83
    public static final String DEFAULT_ESCAPE = "\\";
84
    public static final String DEFAULT_NAMESPACE = "xmlns:ogc=\"http://www.opengis.net/ogc\"";
85

    
86
    private Hashtable filterAttributes = new Hashtable();
87

    
88
    /**
89
     * If the namespace XML is qualified
90
     */
91
    private boolean isQualified = false;
92

    
93
    private static final StringUtils stringUtils = CompatLocator.getStringUtils();
94

    
95
    /**
96
     * Create a new Filter Encoding Parser
97
     * 
98
     * 
99
     * @param nameSpacePrefix
100
     * Filter namespace. (typically "ogc")
101
     * @param wildCardChar 
102
     * This character must be replaced by any set of characters (typically "*")
103
     * @param singleChar 
104
     * This character must be replaced by one character (typically "?")
105
     * @param escape 
106
     * Escape character
107
     * @param filterAttribute Sometimes, "Field" label needs an attribute.
108
     */
109
    public FilterEncoding(ISQLExpressionFormat formatter,String namesPacePrefix, String wildCard, String singleChar, String escape, Hashtable filterAttributes) {        
110
        super(formatter);
111
        if (namesPacePrefix == null){
112
            setQualified(false);
113
        }else{
114
            setQualified(true);
115
        }
116
        this.wildCardChar = wildCard;
117
        this.singleChar = singleChar;
118
        this.escapeChar = escape;
119
        this.filterAttributes = filterAttributes;
120
    } 
121

    
122

    
123
    /**
124
     * Create a new Filter Encoding Parser
125
     * @param formatter
126
     */
127
    public FilterEncoding(ISQLExpressionFormat formatter) {        
128
        this(formatter,null,DEFAULT_WILDCARD,DEFAULT_SINGLECHAR,
129
            DEFAULT_ESCAPE,new Hashtable());
130
    } 
131

    
132
    /**
133
     * Create a new Filter Encoding Parser
134
     */
135
    FilterEncoding() {        
136
        this(new DefaultSQLExpressionFormat());                
137
    }         
138

    
139
    /**
140
     * Create a new Filter Encoding Parser
141
     */
142
    public FilterEncoding(WFSStatus status) {        
143
        this();        
144
        this.nameSpacePrefix = status.getNamespacePrefix();
145
        this.nameSpaceLocation = status.getNamespaceLocation();
146
        setQueryByAttribute(status.getFilterByAttribute());
147
        clearSpatialFilters();
148
        addSpatialFilter(status.getFilterByArea());                
149
    } 
150

    
151
    /*
152
     *  (non-Javadoc)
153
     * @see org.gvsig.remoteClient.filterEncoding.QueryLanguage#toString(org.gvsig.remoteClient.filterEncoding.BinaryTree)
154
     */
155
    public String toString(BinaryTree tree, String version) {
156
        //If is a filter by ids...
157
        StringBuffer idQuery = null;
158
        if (getIds() != null){
159
            idQuery = new StringBuffer();
160
            ArrayList ids = getIds();
161
            for (int i=0 ; i<ids.size() ; i++){
162
                if (ids.get(i) != null){
163
                    Hashtable attributes = new Hashtable();
164
                    attributes.put("fid","\"" + ids.get(i).toString() + "\"");
165
                    idQuery.append(setTag("FeatureId", attributes, null));
166
                }
167
            }
168
            return enclosesWithFilterTag(idQuery.toString());
169
        }
170
        //If is a filter by attributes...
171
        String filterQuery = null;
172
        if ((tree.getRoot() == null) && (getSpatialFiltersCount() == 0)){
173
            return null;
174
        }
175
        if (tree.getRoot() != null){
176
            currentQuery = new StringBuffer();
177
            filterQuery = getFilterNode(tree.getRoot());
178
            if (getSpatialFiltersCount() == 0){
179
                return enclosesWithFilterTag(filterQuery);
180
            }
181
        }
182
        //If is a filter by area
183
        String bboxQuery = null;
184
        if (getSpatialFiltersCount() > 0){
185
            for (int i=0 ; i<getSpatialFiltersCount() ; i++){
186
                WFSSpatialFilterOperation spatialFilter = getSpatialFilterAt(i);
187
                SpatialFEQuery feQuery = null;
188
                if (spatialFilter instanceof WFSGeometryFilterOperation){
189
                    feQuery = new GeometryFEQuery((WFSGeometryFilterOperation)spatialFilter);
190
                }else if (spatialFilter instanceof WFSEnvelopeFilterOperation){
191
                    //TODO add this for a manager
192
                    if (version.equals("1.0.0")){
193
                        feQuery = new EnvelopeFEQuery1_0_0((WFSEnvelopeFilterOperation)spatialFilter);
194
                    }else{
195
                        feQuery = new EnvelopeFEQuery1_1_0((WFSEnvelopeFilterOperation)spatialFilter);  
196
                    }                                   
197
                }
198
                //If there is a spatial query
199
                if (feQuery != null){
200
                    bboxQuery = feQuery.getFilterEncoding();
201
                    if (tree.getRoot() == null){
202
                        String filter_bbox = enclosesWithFilterTag(bboxQuery); 
203
                        return filter_bbox;
204
                    }        
205
                }
206
            }
207
        }                
208
        return enclosesWithFilterTag(filterQuery + bboxQuery);
209
    }
210

    
211
    /**
212
     * Gets the filter code from a node
213
     * @param node
214
     */
215
    private String getFilterNode(Node node){
216
        if (node.isField()){
217
            return getExpression(node.getValue());
218
        }else{
219
            String left = "";
220
            String rigth = "";
221
            if (node.getLeftNode() != null){
222
                left = getFilterNode(node.getLeftNode());
223
            }
224
            if (node.getRigthNode() != null){
225
                rigth = getFilterNode(node.getRigthNode());
226
            }
227
            int operationCode = getLogicalOperator(node.getValue());
228
            String operation = getLogicalOperator(operationCode);
229
            return enterLabel(left+rigth, operation);
230
        }                
231
    }   
232

    
233
    /**
234
     * Parses a expresion like 'A op B' and returns the
235
     * expresion using the filter encoding language
236
     * @param expression
237
     * @return
238
     */
239
    private String getExpression(String expression){
240
        String[] words = stringUtils.split(expression, " ");
241
        //Param
242
        String param = words[0];
243
        if (param.charAt(0) == '"'){
244
            param = param.substring(1,param.length());
245
        }
246
        if (param.charAt(param.length()-1) == '"'){
247
            param = param.substring(0,param.length()-1);
248
        }
249
        //Operator
250
        String operator = words[1];
251
        //Value
252
        String value = words[2];                
253
        for (int i=3 ; i<words.length ; i++){
254
            value = value + " " + words[i];
255
        }
256
        if (value.charAt(0) == '\''){
257
            value = value.substring(1,value.length());
258
        }
259
        if (value.charAt(value.length()-1) == '\''){
260
            value = value.substring(0,value.length()-1);
261
        }
262
        int operatorCode = getRelationalOperator(operator);
263
        operator = getRelationalOperator(operatorCode);
264
        return createExpression(operator,param,value);
265
    }
266

    
267
    /**
268
     * It writes a "PropertyIsXXX" part of a filtyer encoding query
269
     * 
270
     * 
271
     * @return The part of the query
272
     * @param property Possible Values: PropertIsLike, PropertyIsLess, PropertyIsGreater,... See
273
     * the Filter Encoding documentation
274
     * @param parameter Parameter name
275
     * @param value Parameter value
276
     * @param type Values: "P" (to comparate two propertyes) or "L" (to comparate one property
277
     * and one literal value)
278
     */
279
    private String createExpression(String property, String parameter, String value) {        
280
        String cadena = "";
281
        cadena = "<" + WFSTTags.OGC_NAMESPACE_PREFIX + ":" + property;
282
        if (property.equals("PropertyIsLike")) {
283
            if (wildCardChar != null) {
284
                cadena = cadena + " wildCard=\"" + this.wildCardChar + "\"";
285
            }
286
            if (singleChar != null) {
287
                cadena = cadena + " singleChar=\"" + this.singleChar + "\"";
288
            }
289
            if (escapeChar != null) {
290
                cadena = cadena + " escape=\"" + this.escapeChar + "\"";
291
            }
292
        }
293
        cadena = cadena + ">" + enterLabel(nameSpacePrefix + ":" + parameter, "PropertyName");
294
        cadena = cadena + enterLabel(value, "Literal");
295
        return cadena + "</" + WFSTTags.OGC_NAMESPACE_PREFIX + ":" + property + ">";
296
    }         
297

    
298
    /**
299
     * Envuelve a una pregunta con una etiqueta
300
     * 
301
     * 
302
     * @return String : parte de la query en el lenguaje soportado
303
     * @param pregunta Pregunta a envolver
304
     * @param etiqueta Nombre de la etiqueta
305
     */
306
    private String enterLabel(String value, String tagName) {        
307
        if (tagName.equals("Filter") && (!(filterAttributes.isEmpty()))) {
308
            return setTag(tagName,filterAttributes,value);
309
        } else {
310
            return setTag(tagName,null,value);
311
        }
312
    } 
313

    
314
    /**
315
     * Envolves a value with an XML tag
316
     * 
317
     * @return String
318
     * XML tag with its value
319
     * @param tagName 
320
     * XML tag name
321
     * @param attributes
322
     * XML tag attributes
323
     * @param value 
324
     * Tag value
325
     */
326
    public String setTag(String tagName, Hashtable attributes, String value) {        
327
        StringBuffer tag = new StringBuffer();
328

    
329
        tag.append("<");
330
        tag.append(WFSTTags.OGC_NAMESPACE_PREFIX + ":");
331
        tag.append(tagName);            
332
        if (attributes != null){
333
            Set keys = attributes.keySet();
334
            if (attributes.size() > 0){
335
                Iterator it = keys.iterator();
336
                while (it.hasNext()){
337
                    String key = (String)it.next();
338
                    if (hasBlankSpaces){
339
                        tag.append(" ");
340
                    }else{
341
                        tag.append(defaultBlankSpace);
342
                    }
343
                    tag.append(key + "=" + (String)attributes.get(key));
344

    
345
                }
346
            }
347
        }
348
        if (value == null){
349
            tag.append("/>");
350
        }else{
351
            tag.append(">" + value);
352
            tag.append("</");
353
            tag.append(WFSTTags.OGC_NAMESPACE_PREFIX + ":");
354
            tag.append(tagName);
355
            tag.append(">");
356
        }
357
        return tag.toString();
358
    }
359

    
360

    
361
    /**
362
     * Encloses a query with the filter tag
363
     * @param query
364
     * @return
365
     */
366
    private String enclosesWithFilterTag(String query){
367
        StringBuffer filter = new StringBuffer();
368
        filter.append("<ogc:Filter");
369
        if (!isQualified){
370
            filter.append(" ");
371
            addNamespace(filter, WFSTTags.OGC_NAMESPACE_PREFIX, WFSTTags.OGC_NAMESPACE);
372
            addNamespace(filter, WFSTTags.GML_NAMESPACE_PREFIX, WFSTTags.GML_NAMESPACE);
373
            if (nameSpacePrefix != null){
374
                addNamespace(filter, nameSpacePrefix, nameSpaceLocation);
375
            }
376
            filter.append("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ");      
377
            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\"");
378
        }
379
        filter.append(">");
380
        filter.append(query);
381
        filter.append("</ogc:Filter>");
382
        return filter.toString();
383
    }
384
    
385
    private void addNamespace(StringBuffer buffer, String nameSpacePrefix, String nameSpaceLocation){
386
        buffer.append(WFSTTags.XMLNS + ":" + nameSpacePrefix + "=\"" + nameSpaceLocation + "\" ");
387
    }
388

    
389
    /*
390
     *  (non-Javadoc)
391
     * @see org.gvsig.remoteClient.filterEncoding.AQueryLanguage#getLogicOperator(int)
392
     */
393
    public String getLogicalOperator(int operator) {
394
        switch (operator){
395
        case LOGICAL_OPERATOR_AND:
396
            return "And";
397
        case LOGICAL_OPERATOR_OR:
398
            return "Or";
399
        case LOGICAL_OPERATOR_NOT:
400
            return "Not";
401
        default:
402
            return "And";
403
        }    
404
    } 
405

    
406
    /*
407
     *  (non-Javadoc)
408
     * @see org.gvsig.remoteClient.filterEncoding.AQueryLanguage#getRelationalOperator(int)
409
     */
410
    public String getRelationalOperator(int operator) {
411
        switch (operator){
412
        case RELATIONAL_OPERATOR_IS_EQUALS_TO:
413
            return "PropertyIsEqualTo";
414
        case RELATIONAL_OPERATOR_IS_NOT_EQUALS_TO:
415
            return "PropertyIsNotEqualTo";
416
        case RELATIONAL_OPERATOR_IS_LESS_THAN:
417
            return "PropertyIsLessThan";
418
        case RELATIONAL_OPERATOR_IS_GREATER_THAN:
419
            return "PropertyIsGreaterThan";
420
        case RELATIONAL_OPERATOR_IS_LESS_THAN_OR_EQUAL_TO:
421
            return "PropertyIsLessThanOrEqualTo";
422
        case RELATIONAL_OPERATOR_IS_GREATER_THAN_OR_EQUAL_TO:
423
            return "PropertyIsGreaterThanOrEqualTo";
424
        case RELATIONAL_OPERATOR_IS_LIKE:
425
            return "PropertyIsLike";
426
        case RELATIONAL_OPERATOR_IS_NULL:
427
            return "PropertyIsNull";
428
        case RELATIONAL_OPERATOR_IS_BETWEEN:
429
            return "PropertyIsBetween";
430
        default:
431
            return "PropertyIsLike";
432
        }
433
    }
434

    
435
    /*
436
     *  (non-Javadoc)
437
     * @see org.gvsig.remoteClient.filterEncoding.AQueryLanguage#getGeometricOperator(int)
438
     */
439
    public String getGeometricOperator(int operator) {
440
        switch (operator){
441
        case GEOMETRIC_OPERATOR_EQUALS:
442
            return "Equals";
443
        case GEOMETRIC_OPERATOR_DISJOINT:
444
            return "Disjoint";
445
        case GEOMETRIC_OPERATOR_TOUCHES:
446
            return "Touches";
447
        case GEOMETRIC_OPERATOR_WITHIN:
448
            return "Within";
449
        case GEOMETRIC_OPERATOR_OVERLAPS:
450
            return "Overlaps";
451
        case GEOMETRIC_OPERATOR_CROSSES:
452
            return "Crosses";
453
        case GEOMETRIC_OPERATOR_INTERSECT:
454
            return "Intersect";
455
        case GEOMETRIC_OPERATOR_CONTAINS:
456
            return "Contains";
457
        case GEOMETRIC_OPERATOR_DWITHIN:
458
            return "Dwithin";
459
        case GEOMETRIC_OPERATOR_BEYOND:
460
            return "Beyond";
461
        case GEOMETRIC_OPERATOR_BBOX:
462
            return "BBOX";
463
        default:
464
            return "Equals";
465
        } 
466

    
467
    }
468

    
469
    public String getSeparator(int separator) {
470
        return null;
471
    }
472

    
473
    /**
474
     * @param isQualified the isQualified to set
475
     */
476
    public void setQualified(boolean isQualified) {
477
        this.isQualified = isQualified;
478
        if (isQualified){
479
            nameSpacePrefix = DEFAULT_NAMESPACE_PREFIX + ":";
480
        }else{
481
            nameSpacePrefix = "";
482
        }
483
    }
484

    
485

    
486
    /**
487
     * @param namepacePrefix the namepacePrefix to set
488
     */
489
    public void setNamepacePrefix(String namepacePrefix) {
490
        if ((namepacePrefix == null) || (namepacePrefix.equals(""))){
491
            this.nameSpacePrefix = "";
492
        }else{
493
            this.nameSpacePrefix = namepacePrefix + ":";
494
        }
495
    }
496

    
497

    
498
    /**
499
     * @param hasBlankSpaces the hasBlankSpaces to set
500
     */
501
    public void setHasBlankSpaces(boolean hasBlankSpaces) {
502
        this.hasBlankSpaces = hasBlankSpaces;
503
    }
504
}