Statistics
| Revision:

root / branches / v2_0_0_prep / libraries / libRemoteServices / src / org / gvsig / remoteclient / wfs / filters / filterencoding / FilterEncoding.java @ 34132

History | View | Annotate | Download (17.9 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
                        return bboxQuery;
220
                    }        
221
                }
222
            }
223
        }                
224
        return enclosesWithFilterTag(filterQuery + bboxQuery);
225
    }
226

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

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

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

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

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

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

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

    
376

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

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

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

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

    
483
    }
484

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

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

    
501

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

    
513

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