Statistics
| Revision:

root / tags / v2_0_0_Build_2049 / libraries / libRemoteServices / src / org / gvsig / remoteclient / wfs / filters / filterencoding / FilterEncoding.java @ 38492

History | View | Annotate | Download (18 KB)

1

    
2
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
3
 *
4
 * Copyright (C) 2004 IVER T.I. and Generalitat Valenciana.
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 2
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., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
19
 *
20
 * For more information, contact:
21
 *
22
 *  Generalitat Valenciana
23
 *   Conselleria d'Infraestructures i Transport
24
 *   Av. Blasco Ib??ez, 50
25
 *   46010 VALENCIA
26
 *   SPAIN
27
 *
28
 *      +34 963862235
29
 *   gvsig@gva.es
30
 *      www.gvsig.gva.es
31
 *
32
 *    or
33
 *
34
 *   IVER T.I. S.A
35
 *   Salamanca 50
36
 *   46005 Valencia
37
 *   Spain
38
 *
39
 *   +34 963163400
40
 *   dac@iver.es
41
 */
42
package org.gvsig.remoteclient.wfs.filters.filterencoding;
43
import java.util.ArrayList;
44
import java.util.Hashtable;
45
import java.util.Iterator;
46
import java.util.Set;
47

    
48
import org.gvsig.compat.CompatLocator;
49
import org.gvsig.compat.lang.StringUtils;
50
import org.gvsig.remoteclient.wfs.WFSStatus;
51
import org.gvsig.remoteclient.wfs.edition.WFSTTags;
52
import org.gvsig.remoteclient.wfs.filters.AbstractFilter;
53
import org.gvsig.remoteclient.wfs.filters.BinaryTree;
54
import org.gvsig.remoteclient.wfs.filters.BinaryTree.Node;
55
import org.gvsig.remoteclient.wfs.filters.DefaultSQLExpressionFormat;
56
import org.gvsig.remoteclient.wfs.filters.ISQLExpressionFormat;
57
import org.gvsig.remoteclient.wfs.filters.filterencoding.wfs_1_0_0.EnvelopeFEQuery1_0_0;
58
import org.gvsig.remoteclient.wfs.filters.filterencoding.wfs_1_1_0.EnvelopeFEQuery1_1_0;
59
import org.gvsig.remoteclient.wfs.filters.operations.WFSEnvelopeFilterOperation;
60
import org.gvsig.remoteclient.wfs.filters.operations.WFSGeometryFilterOperation;
61
import org.gvsig.remoteclient.wfs.filters.operations.WFSSpatialFilterOperation;
62

    
63
/**
64
 * This class implements the Filter Encoding Language. It is used to
65
 * create querys in this language
66
 * 
67
 * Name: OpenGIS? Filter Encoding Implementation Specification
68
 * Version: 1.1.0
69
 * Project Document: OGC 04-095 
70
 * @see http://portal.opengeospatial.org/files/?artifact_id=8340
71
 * 
72
 * @author Jorge Piera Llodra (piera_jor@gva.es)
73
 */
74
public class FilterEncoding extends AbstractFilter {
75
    public static final int RELATIONSHIP_PROPERTY = 0;
76
    public static final int RELATIONSHIP_VAUES = 1;
77

    
78
    private StringBuffer currentQuery = null;
79
    //Operation types
80
    private static final int OPERATION_PROPERTYNAME = 0;
81
    private static final int OPERATION_LITERAL = 1;
82
    
83
    //Filter namespace. 
84
    private String nameSpacePrefix = null;
85
    private String nameSpaceLocation = null;
86

    
87
    //If the Filter can have blanckSpaces
88
    private boolean hasBlankSpaces = true;
89
    private String defaultBlankSpace = "%20";
90
    //This character must be replaced by any set of characters (typically "*")
91
    private String wildCardChar = null;
92
    //This character must be replaced by one character (typically "?")
93
    private String singleChar = null;
94
    //Escape character (typically "\")
95
    private String escapeChar = null;
96
    //Default values
97
    public static final String DEFAULT_NAMESPACE_PREFIX = "ogc";
98
    public static final String DEFAULT_WILDCARD = "*";
99
    public static final String DEFAULT_SINGLECHAR = "?";
100
    public static final String DEFAULT_ESCAPE = "\\";
101
    public static final String DEFAULT_NAMESPACE = "xmlns:ogc=\"http://www.opengis.net/ogc\"";
102

    
103
    private Hashtable filterAttributes = new Hashtable();
104

    
105
    /**
106
     * If the namespace XML is qualified
107
     */
108
    private boolean isQualified = false;
109

    
110
    private static final StringUtils stringUtils = CompatLocator.getStringUtils();
111

    
112
    /**
113
     * Create a new Filter Encoding Parser
114
     * 
115
     * 
116
     * @param nameSpacePrefix
117
     * Filter namespace. (typically "ogc")
118
     * @param wildCardChar 
119
     * This character must be replaced by any set of characters (typically "*")
120
     * @param singleChar 
121
     * This character must be replaced by one character (typically "?")
122
     * @param escape 
123
     * Escape character
124
     * @param filterAttribute Sometimes, "Field" label needs an attribute.
125
     */
126
    public FilterEncoding(ISQLExpressionFormat formatter,String namesPacePrefix, String wildCard, String singleChar, String escape, Hashtable filterAttributes) {        
127
        super(formatter);
128
        if (namesPacePrefix == null){
129
            setQualified(false);
130
        }else{
131
            setQualified(true);
132
        }
133
        this.wildCardChar = wildCard;
134
        this.singleChar = singleChar;
135
        this.escapeChar = escape;
136
        this.filterAttributes = filterAttributes;
137
    } 
138

    
139

    
140
    /**
141
     * Create a new Filter Encoding Parser
142
     * @param formatter
143
     */
144
    public FilterEncoding(ISQLExpressionFormat formatter) {        
145
        this(formatter,null,DEFAULT_WILDCARD,DEFAULT_SINGLECHAR,
146
            DEFAULT_ESCAPE,new Hashtable());
147
    } 
148

    
149
    /**
150
     * Create a new Filter Encoding Parser
151
     */
152
    FilterEncoding() {        
153
        this(new DefaultSQLExpressionFormat());                
154
    }         
155

    
156
    /**
157
     * Create a new Filter Encoding Parser
158
     */
159
    public FilterEncoding(WFSStatus status) {        
160
        this();        
161
        this.nameSpacePrefix = status.getNamespacePrefix();
162
        this.nameSpaceLocation = status.getNamespaceLocation();
163
        setQueryByAttribute(status.getFilterByAttribute());
164
        clearSpatialFilters();
165
        addSpatialFilter(status.getFilterByArea());                
166
    } 
167

    
168
    /*
169
     *  (non-Javadoc)
170
     * @see org.gvsig.remoteClient.filterEncoding.QueryLanguage#toString(org.gvsig.remoteClient.filterEncoding.BinaryTree)
171
     */
172
    public String toString(BinaryTree tree, String version) {
173
        //If is a filter by ids...
174
        StringBuffer idQuery = null;
175
        if (getIds() != null){
176
            idQuery = new StringBuffer();
177
            ArrayList ids = getIds();
178
            for (int i=0 ; i<ids.size() ; i++){
179
                if (ids.get(i) != null){
180
                    Hashtable attributes = new Hashtable();
181
                    attributes.put("fid","\"" + ids.get(i).toString() + "\"");
182
                    idQuery.append(setTag("FeatureId", attributes, null));
183
                }
184
            }
185
            return enclosesWithFilterTag(idQuery.toString());
186
        }
187
        //If is a filter by attributes...
188
        String filterQuery = null;
189
        if ((tree.getRoot() == null) && (getSpatialFiltersCount() == 0)){
190
            return null;
191
        }
192
        if (tree.getRoot() != null){
193
            currentQuery = new StringBuffer();
194
            filterQuery = getFilterNode(tree.getRoot());
195
            if (getSpatialFiltersCount() == 0){
196
                return enclosesWithFilterTag(filterQuery);
197
            }
198
        }
199
        //If is a filter by area
200
        String bboxQuery = null;
201
        if (getSpatialFiltersCount() > 0){
202
            for (int i=0 ; i<getSpatialFiltersCount() ; i++){
203
                WFSSpatialFilterOperation spatialFilter = getSpatialFilterAt(i);
204
                SpatialFEQuery feQuery = null;
205
                if (spatialFilter instanceof WFSGeometryFilterOperation){
206
                    feQuery = new GeometryFEQuery((WFSGeometryFilterOperation)spatialFilter);
207
                }else if (spatialFilter instanceof WFSEnvelopeFilterOperation){
208
                    //TODO add this for a manager
209
                    if (version.equals("1.0.0")){
210
                        feQuery = new EnvelopeFEQuery1_0_0((WFSEnvelopeFilterOperation)spatialFilter);
211
                    }else{
212
                        feQuery = new EnvelopeFEQuery1_1_0((WFSEnvelopeFilterOperation)spatialFilter);  
213
                    }                                   
214
                }
215
                //If there is a spatial query
216
                if (feQuery != null){
217
                    bboxQuery = feQuery.getFilterEncoding();
218
                    if (tree.getRoot() == null){
219
                        String filter_bbox = enclosesWithFilterTag(bboxQuery); 
220
                        return filter_bbox;
221
                    }        
222
                }
223
            }
224
        }                
225
        return enclosesWithFilterTag(filterQuery + bboxQuery);
226
    }
227

    
228
    /**
229
     * Gets the filter code from a node
230
     * @param node
231
     */
232
    private String getFilterNode(Node node){
233
        if (node.isField()){
234
            return getExpression(node.getValue());
235
        }else{
236
            String left = "";
237
            String rigth = "";
238
            if (node.getLeftNode() != null){
239
                left = getFilterNode(node.getLeftNode());
240
            }
241
            if (node.getRigthNode() != null){
242
                rigth = getFilterNode(node.getRigthNode());
243
            }
244
            int operationCode = getLogicalOperator(node.getValue());
245
            String operation = getLogicalOperator(operationCode);
246
            return enterLabel(left+rigth, operation);
247
        }                
248
    }   
249

    
250
    /**
251
     * Parses a expresion like 'A op B' and returns the
252
     * expresion using the filter encoding language
253
     * @param expression
254
     * @return
255
     */
256
    private String getExpression(String expression){
257
        String[] words = stringUtils.split(expression, " ");
258
        //Param
259
        String param = words[0];
260
        if (param.charAt(0) == '"'){
261
            param = param.substring(1,param.length());
262
        }
263
        if (param.charAt(param.length()-1) == '"'){
264
            param = param.substring(0,param.length()-1);
265
        }
266
        //Operator
267
        String operator = words[1];
268
        //Value
269
        String value = words[2];                
270
        for (int i=3 ; i<words.length ; i++){
271
            value = value + " " + words[i];
272
        }
273
        if (value.charAt(0) == '\''){
274
            value = value.substring(1,value.length());
275
        }
276
        if (value.charAt(value.length()-1) == '\''){
277
            value = value.substring(0,value.length()-1);
278
        }
279
        int operatorCode = getRelationalOperator(operator);
280
        operator = getRelationalOperator(operatorCode);
281
        return createExpression(operator,param,value);
282
    }
283

    
284
    /**
285
     * It writes a "PropertyIsXXX" part of a filtyer encoding query
286
     * 
287
     * 
288
     * @return The part of the query
289
     * @param property Possible Values: PropertIsLike, PropertyIsLess, PropertyIsGreater,... See
290
     * the Filter Encoding documentation
291
     * @param parameter Parameter name
292
     * @param value Parameter value
293
     * @param type Values: "P" (to comparate two propertyes) or "L" (to comparate one property
294
     * and one literal value)
295
     */
296
    private String createExpression(String property, String parameter, String value) {        
297
        String cadena = "";
298
        cadena = "<" + WFSTTags.OGC_NAMESPACE_PREFIX + ":" + property;
299
        if (property.equals("PropertyIsLike")) {
300
            if (wildCardChar != null) {
301
                cadena = cadena + " wildCard=\"" + this.wildCardChar + "\"";
302
            }
303
            if (singleChar != null) {
304
                cadena = cadena + " singleChar=\"" + this.singleChar + "\"";
305
            }
306
            if (escapeChar != null) {
307
                cadena = cadena + " escape=\"" + this.escapeChar + "\"";
308
            }
309
        }
310
        cadena = cadena + ">" + enterLabel(nameSpacePrefix + ":" + parameter, "PropertyName");
311
        cadena = cadena + enterLabel(value, "Literal");
312
        return cadena + "</" + WFSTTags.OGC_NAMESPACE_PREFIX + ":" + property + ">";
313
    }         
314

    
315
    /**
316
     * Envuelve a una pregunta con una etiqueta
317
     * 
318
     * 
319
     * @return String : parte de la query en el lenguaje soportado
320
     * @param pregunta Pregunta a envolver
321
     * @param etiqueta Nombre de la etiqueta
322
     */
323
    private String enterLabel(String value, String tagName) {        
324
        if (tagName.equals("Filter") && (!(filterAttributes.isEmpty()))) {
325
            return setTag(tagName,filterAttributes,value);
326
        } else {
327
            return setTag(tagName,null,value);
328
        }
329
    } 
330

    
331
    /**
332
     * Envolves a value with an XML tag
333
     * 
334
     * @return String
335
     * XML tag with its value
336
     * @param tagName 
337
     * XML tag name
338
     * @param attributes
339
     * XML tag attributes
340
     * @param value 
341
     * Tag value
342
     */
343
    public String setTag(String tagName, Hashtable attributes, String value) {        
344
        StringBuffer tag = new StringBuffer();
345

    
346
        tag.append("<");
347
        tag.append(WFSTTags.OGC_NAMESPACE_PREFIX + ":");
348
        tag.append(tagName);            
349
        if (attributes != null){
350
            Set keys = attributes.keySet();
351
            if (attributes.size() > 0){
352
                Iterator it = keys.iterator();
353
                while (it.hasNext()){
354
                    String key = (String)it.next();
355
                    if (hasBlankSpaces){
356
                        tag.append(" ");
357
                    }else{
358
                        tag.append(defaultBlankSpace);
359
                    }
360
                    tag.append(key + "=" + (String)attributes.get(key));
361

    
362
                }
363
            }
364
        }
365
        if (value == null){
366
            tag.append("/>");
367
        }else{
368
            tag.append(">" + value);
369
            tag.append("</");
370
            tag.append(WFSTTags.OGC_NAMESPACE_PREFIX + ":");
371
            tag.append(tagName);
372
            tag.append(">");
373
        }
374
        return tag.toString();
375
    }
376

    
377

    
378
    /**
379
     * Encloses a query with the filter tag
380
     * @param query
381
     * @return
382
     */
383
    private String enclosesWithFilterTag(String query){
384
        StringBuffer filter = new StringBuffer();
385
        filter.append("<ogc:Filter");
386
        if (!isQualified){
387
            filter.append(" ");
388
            addNamespace(filter, WFSTTags.OGC_NAMESPACE_PREFIX, WFSTTags.OGC_NAMESPACE);
389
            addNamespace(filter, WFSTTags.GML_NAMESPACE_PREFIX, WFSTTags.GML_NAMESPACE);
390
            if (nameSpacePrefix != null){
391
                addNamespace(filter, nameSpacePrefix, nameSpaceLocation);
392
            }
393
            filter.append("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ");      
394
            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\"");
395
        }
396
        filter.append(">");
397
        filter.append(query);
398
        filter.append("</ogc:Filter>");
399
        return filter.toString();
400
    }
401
    
402
    private void addNamespace(StringBuffer buffer, String nameSpacePrefix, String nameSpaceLocation){
403
        buffer.append(WFSTTags.XMLNS + ":" + nameSpacePrefix + "=\"" + nameSpaceLocation + "\" ");
404
    }
405

    
406
    /*
407
     *  (non-Javadoc)
408
     * @see org.gvsig.remoteClient.filterEncoding.AQueryLanguage#getLogicOperator(int)
409
     */
410
    public String getLogicalOperator(int operator) {
411
        switch (operator){
412
        case LOGICAL_OPERATOR_AND:
413
            return "And";
414
        case LOGICAL_OPERATOR_OR:
415
            return "Or";
416
        case LOGICAL_OPERATOR_NOT:
417
            return "Not";
418
        default:
419
            return "And";
420
        }    
421
    } 
422

    
423
    /*
424
     *  (non-Javadoc)
425
     * @see org.gvsig.remoteClient.filterEncoding.AQueryLanguage#getRelationalOperator(int)
426
     */
427
    public String getRelationalOperator(int operator) {
428
        switch (operator){
429
        case RELATIONAL_OPERATOR_IS_EQUALS_TO:
430
            return "PropertyIsEqualTo";
431
        case RELATIONAL_OPERATOR_IS_NOT_EQUALS_TO:
432
            return "PropertyIsNotEqualTo";
433
        case RELATIONAL_OPERATOR_IS_LESS_THAN:
434
            return "PropertyIsLessThan";
435
        case RELATIONAL_OPERATOR_IS_GREATER_THAN:
436
            return "PropertyIsGreaterThan";
437
        case RELATIONAL_OPERATOR_IS_LESS_THAN_OR_EQUAL_TO:
438
            return "PropertyIsLessThanOrEqualTo";
439
        case RELATIONAL_OPERATOR_IS_GREATER_THAN_OR_EQUAL_TO:
440
            return "PropertyIsGreaterThanOrEqualTo";
441
        case RELATIONAL_OPERATOR_IS_LIKE:
442
            return "PropertyIsLike";
443
        case RELATIONAL_OPERATOR_IS_NULL:
444
            return "PropertyIsNull";
445
        case RELATIONAL_OPERATOR_IS_BETWEEN:
446
            return "PropertyIsBetween";
447
        default:
448
            return "PropertyIsLike";
449
        }
450
    }
451

    
452
    /*
453
     *  (non-Javadoc)
454
     * @see org.gvsig.remoteClient.filterEncoding.AQueryLanguage#getGeometricOperator(int)
455
     */
456
    public String getGeometricOperator(int operator) {
457
        switch (operator){
458
        case GEOMETRIC_OPERATOR_EQUALS:
459
            return "Equals";
460
        case GEOMETRIC_OPERATOR_DISJOINT:
461
            return "Disjoint";
462
        case GEOMETRIC_OPERATOR_TOUCHES:
463
            return "Touches";
464
        case GEOMETRIC_OPERATOR_WITHIN:
465
            return "Within";
466
        case GEOMETRIC_OPERATOR_OVERLAPS:
467
            return "Overlaps";
468
        case GEOMETRIC_OPERATOR_CROSSES:
469
            return "Crosses";
470
        case GEOMETRIC_OPERATOR_INTERSECT:
471
            return "Intersect";
472
        case GEOMETRIC_OPERATOR_CONTAINS:
473
            return "Contains";
474
        case GEOMETRIC_OPERATOR_DWITHIN:
475
            return "Dwithin";
476
        case GEOMETRIC_OPERATOR_BEYOND:
477
            return "Beyond";
478
        case GEOMETRIC_OPERATOR_BBOX:
479
            return "BBOX";
480
        default:
481
            return "Equals";
482
        } 
483

    
484
    }
485

    
486
    public String getSeparator(int separator) {
487
        return null;
488
    }
489

    
490
    /**
491
     * @param isQualified the isQualified to set
492
     */
493
    public void setQualified(boolean isQualified) {
494
        this.isQualified = isQualified;
495
        if (isQualified){
496
            nameSpacePrefix = DEFAULT_NAMESPACE_PREFIX + ":";
497
        }else{
498
            nameSpacePrefix = "";
499
        }
500
    }
501

    
502

    
503
    /**
504
     * @param namepacePrefix the namepacePrefix to set
505
     */
506
    public void setNamepacePrefix(String namepacePrefix) {
507
        if ((namepacePrefix == null) || (namepacePrefix.equals(""))){
508
            this.nameSpacePrefix = "";
509
        }else{
510
            this.nameSpacePrefix = namepacePrefix + ":";
511
        }
512
    }
513

    
514

    
515
    /**
516
     * @param hasBlankSpaces the hasBlankSpaces to set
517
     */
518
    public void setHasBlankSpaces(boolean hasBlankSpaces) {
519
        this.hasBlankSpaces = hasBlankSpaces;
520
    }
521
}