-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
FilterCapabilities.java
470 lines (422 loc) · 19.2 KB
/
FilterCapabilities.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2002-2008, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.filter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.geotools.api.filter.And;
import org.geotools.api.filter.BinaryLogicOperator;
import org.geotools.api.filter.Filter;
import org.geotools.api.filter.Id;
import org.geotools.api.filter.Not;
import org.geotools.api.filter.Or;
import org.geotools.api.filter.PropertyIsBetween;
import org.geotools.api.filter.PropertyIsEqualTo;
import org.geotools.api.filter.PropertyIsGreaterThan;
import org.geotools.api.filter.PropertyIsGreaterThanOrEqualTo;
import org.geotools.api.filter.PropertyIsLessThan;
import org.geotools.api.filter.PropertyIsLessThanOrEqualTo;
import org.geotools.api.filter.PropertyIsLike;
import org.geotools.api.filter.PropertyIsNotEqualTo;
import org.geotools.api.filter.PropertyIsNull;
import org.geotools.api.filter.expression.Add;
import org.geotools.api.filter.expression.Divide;
import org.geotools.api.filter.expression.Multiply;
import org.geotools.api.filter.expression.Subtract;
import org.geotools.api.filter.spatial.BBOX;
import org.geotools.api.filter.spatial.Beyond;
import org.geotools.api.filter.spatial.Contains;
import org.geotools.api.filter.spatial.Crosses;
import org.geotools.api.filter.spatial.DWithin;
import org.geotools.api.filter.spatial.Disjoint;
import org.geotools.api.filter.spatial.Equals;
import org.geotools.api.filter.spatial.Intersects;
import org.geotools.api.filter.spatial.Overlaps;
import org.geotools.api.filter.spatial.Touches;
import org.geotools.api.filter.spatial.Within;
/**
* Represents the Filter capabilities that are supported by a SQLEncoder
*
* <p>Each SQLEncoder class should have one static FilterCapabilities, representing the filter
* encoding operations that it can successfully perform.
*
* <p>This class is used as one big mask to detect filters that cannot be performed
*
* @author Chris Holmes, TOPP TODO: check if possible to deprecate @ deprecated use {@link
* org.geotools.api.filter.capability.FilterCapabilities}.
*/
public class FilterCapabilities {
/** Mask for no operation */
public static final long NO_OP = 0;
/** Mask for Filter.INCLUDE */
public static final long NONE = 0x01 << 30;
/** Mask for Filter.EXCLUDE */
public static final long ALL = 0x01 << 31;
// spatial masks
/** Spatial Mask for bbox operation */
public static final long SPATIAL_BBOX = 0x01;
/** Spatial Mask for equals operation */
public static final long SPATIAL_EQUALS = 0x01 << 1;
/** Spatial Mask for disjoint operation */
public static final long SPATIAL_DISJOINT = 0x01 << 2;
/** Spatial Mask for intersect operation */
public static final long SPATIAL_INTERSECT = 0x01 << 3;
/** Spatial Mask for touches operation */
public static final long SPATIAL_TOUCHES = 0x01 << 4;
/** Spatial Mask for crosses operation */
public static final long SPATIAL_CROSSES = 0x01 << 5;
/** Spatial Mask for within operation */
public static final long SPATIAL_WITHIN = 0x01 << 6;
/** Spatial Mask for contains operation */
public static final long SPATIAL_CONTAINS = 0x01 << 7;
/** Spatial Mask for overlaps operation */
public static final long SPATIAL_OVERLAPS = 0x01 << 8;
/** Spatial Mask for beyond operation */
public static final long SPATIAL_BEYOND = 0x01 << 9;
/** Spatial Mask for dwithin operation */
public static final long SPATIAL_DWITHIN = 0x01 << 10;
// scalar masks
/** Scalar Mask for like operation */
public static final long LIKE = 0x01 << 11;
/** Scalar Mask for between opelongion */
public static final long BETWEEN = 0x01 << 12;
/** Scalar Mask for null check operation */
public static final long NULL_CHECK = 0x01 << 13;
/** Scalar Mask for simple arithmetic operations */
public static final long SIMPLE_ARITHMETIC = 0x01 << 14;
/** Scalar Mask for function operations */
public static final long FUNCTIONS = 0x01 << 15;
// masks for different comparison filters
public static final long COMPARE_EQUALS = 0x01 << 16;
public static final long COMPARE_GREATER_THAN = 0x01 << 17;
public static final long COMPARE_GREATER_THAN_EQUAL = 0x01 << 18;
public static final long COMPARE_LESS_THAN = 0x01 << 19;
public static final long COMPARE_LESS_THAN_EQUAL = 0x01 << 20;
public static final long COMPARE_NOT_EQUALS = 0x01 << 21;
public static final long FID = 0x01 << 22;
// masks for different logic filters
public static final long LOGIC_AND = 0x01 << 23;
public static final long LOGIC_NOT = 0x01 << 24;
public static final long LOGIC_OR = 0x01 << 25;
/** Scalar Mask for logical operation */
public static final long LOGICAL = (LOGIC_AND | LOGIC_OR | LOGIC_NOT);
/** Scalar Mask for simple comparison operations */
public static final long SIMPLE_COMPARISONS =
COMPARE_EQUALS
| COMPARE_GREATER_THAN
| COMPARE_GREATER_THAN_EQUAL
| COMPARE_LESS_THAN
| COMPARE_LESS_THAN_EQUAL
| COMPARE_NOT_EQUALS;
public static final FilterCapabilities SIMPLE_COMPARISONS_OPENGIS;
public static final FilterCapabilities LOGICAL_OPENGIS;
static final Map<Long, Object> intTypeToOpenGisTypeMap = new HashMap<>();
static {
SIMPLE_COMPARISONS_OPENGIS = new FilterCapabilities();
SIMPLE_COMPARISONS_OPENGIS.addType(PropertyIsEqualTo.class);
SIMPLE_COMPARISONS_OPENGIS.addType(PropertyIsGreaterThan.class);
SIMPLE_COMPARISONS_OPENGIS.addType(PropertyIsGreaterThanOrEqualTo.class);
SIMPLE_COMPARISONS_OPENGIS.addType(PropertyIsLessThanOrEqualTo.class);
SIMPLE_COMPARISONS_OPENGIS.addType(PropertyIsLessThan.class);
SIMPLE_COMPARISONS_OPENGIS.addType(PropertyIsNotEqualTo.class);
LOGICAL_OPENGIS = new FilterCapabilities();
LOGICAL_OPENGIS.addType(And.class);
LOGICAL_OPENGIS.addType(Not.class);
LOGICAL_OPENGIS.addType(Or.class);
intTypeToOpenGisTypeMap.put(Long.valueOf(SPATIAL_BBOX), BBOX.class);
intTypeToOpenGisTypeMap.put(Long.valueOf(SPATIAL_EQUALS), Equals.class);
intTypeToOpenGisTypeMap.put(Long.valueOf(SPATIAL_DISJOINT), Disjoint.class);
intTypeToOpenGisTypeMap.put(Long.valueOf(SPATIAL_INTERSECT), Intersects.class);
intTypeToOpenGisTypeMap.put(Long.valueOf(SPATIAL_TOUCHES), Touches.class);
intTypeToOpenGisTypeMap.put(Long.valueOf(SPATIAL_CROSSES), Crosses.class);
intTypeToOpenGisTypeMap.put(Long.valueOf(SPATIAL_WITHIN), Within.class);
intTypeToOpenGisTypeMap.put(Long.valueOf(SPATIAL_CONTAINS), Contains.class);
intTypeToOpenGisTypeMap.put(Long.valueOf(SPATIAL_OVERLAPS), Overlaps.class);
intTypeToOpenGisTypeMap.put(Long.valueOf(SPATIAL_BEYOND), Beyond.class);
intTypeToOpenGisTypeMap.put(Long.valueOf(SPATIAL_DWITHIN), DWithin.class);
intTypeToOpenGisTypeMap.put(
Long.valueOf(SIMPLE_ARITHMETIC),
new Class[] {Add.class, Subtract.class, Multiply.class, Divide.class});
intTypeToOpenGisTypeMap.put(Long.valueOf(COMPARE_EQUALS), PropertyIsEqualTo.class);
intTypeToOpenGisTypeMap.put(Long.valueOf(COMPARE_NOT_EQUALS), PropertyIsNotEqualTo.class);
intTypeToOpenGisTypeMap.put(
Long.valueOf(COMPARE_GREATER_THAN), PropertyIsGreaterThan.class);
intTypeToOpenGisTypeMap.put(
Long.valueOf(COMPARE_GREATER_THAN_EQUAL), PropertyIsGreaterThanOrEqualTo.class);
intTypeToOpenGisTypeMap.put(Long.valueOf(COMPARE_LESS_THAN), PropertyIsLessThan.class);
intTypeToOpenGisTypeMap.put(
Long.valueOf(COMPARE_LESS_THAN_EQUAL), PropertyIsLessThanOrEqualTo.class);
intTypeToOpenGisTypeMap.put(Long.valueOf(NULL_CHECK), PropertyIsNull.class);
intTypeToOpenGisTypeMap.put(Long.valueOf(LIKE), PropertyIsLike.class);
intTypeToOpenGisTypeMap.put(Long.valueOf(BETWEEN), PropertyIsBetween.class);
intTypeToOpenGisTypeMap.put(Long.valueOf(LOGIC_AND), And.class);
intTypeToOpenGisTypeMap.put(Long.valueOf(LOGIC_OR), Or.class);
intTypeToOpenGisTypeMap.put(Long.valueOf(LOGIC_NOT), Not.class);
}
private long ops = NO_OP;
private Set<Class> functions = new HashSet<>();
public FilterCapabilities(long filterCapabilitiesType) {
addType(filterCapabilitiesType);
}
public FilterCapabilities() {
this(NO_OP);
}
public FilterCapabilities(Class type) {
addType(type);
}
/**
* Adds a new support type to capabilities.
*
* @param type The one of the masks enumerated in this class
*/
public void addType(long type) {
// avoid infinite recursion with addType(class)
if ((ops & type) != 0) return;
ops = ops | type;
// the type can be a mask signifying multiple filter types, we have to add them all
for (Map.Entry<Long, Object> longObjectEntry : intTypeToOpenGisTypeMap.entrySet()) {
Map.Entry entry = (Map.Entry) longObjectEntry;
long key = ((Long) entry.getKey()).longValue();
if ((key & type) != 0) {
Object filter = entry.getValue();
if (filter != null) {
if (filter instanceof Class[]) {
Class[] filters = (Class[]) filter;
for (Class aClass : filters) {
addType(aClass, false);
}
} else {
addType((Class) filter, false);
}
}
}
}
}
/**
* Adds a new support type to capabilities. For 2.2 only function expression support is added
* this way. As of geotools 2.3 this will be the supported way of adding to Filtercapabilities.
*
* @param type the Class that indicates the new support.
*/
public void addType(Class type) {
if (org.geotools.api.filter.Filter.class.isAssignableFrom(type)
|| org.geotools.api.filter.expression.Expression.class.isAssignableFrom(type)) {
addType(FUNCTIONS);
functions.add(type);
}
}
/**
* Adds a new support type to capabilities. For 2.2 only function expression support is added
* this way. As of geotools 2.3 this will be the supported way of adding to Filtercapabilities.
*
* @param type the Class that indicates the new support.
*/
public void addType(Class type, boolean addFunctionType) {
if (org.geotools.api.filter.Filter.class.isAssignableFrom(type)
|| org.geotools.api.filter.expression.Expression.class.isAssignableFrom(type)) {
if (addFunctionType) addType(FUNCTIONS);
functions.add(type);
}
}
/**
* Add all the capabilities in the provided FilterCapabilities to this capabilities.
*
* @param capabilities capabilities to add.
*/
public void addAll(FilterCapabilities capabilities) {
addType(capabilities.ops);
functions.addAll(capabilities.functions);
}
/**
* Returns the mask that is equivalent to the FilterType constant.
*
* @param type a constant from {@link FilterType}
* @return the mask that is equivalent to the FilterType constant.
*/
public FilterCapabilities convertFilterTypeToMask(short type) {
if (type == FilterType.ALL) return FilterNameTypeMapping.NO_OP_CAPS;
if (type == FilterType.NONE) return FilterNameTypeMapping.ALL_CAPS;
Object object =
FilterNameTypeMapping.filterTypeToFilterCapabilitiesMap.get(Short.valueOf(type));
return (FilterCapabilities) object;
}
/**
* Determines if the filter passed in is supported.
*
* @param filter The Filter to be tested.
* @return true if supported, false otherwise.
*/
public boolean supports(org.geotools.api.filter.Filter filter) {
for (Class<?> function : functions) {
if (function.isAssignableFrom(filter.getClass())) return true;
}
if (functions.contains(filter.getClass())) return true;
short filterType = getFilterType(filter);
if (filterType == 0) {
// unknown type
return false;
}
return supports(filterType);
}
/**
* Determines if the filter and all its sub filters are supported. Is most important for logic
* filters, as they are the only ones with subFilters. Null filters should not be used here, if
* nothing should be filtered than Filter.INCLUDE can be used. Embedded nulls can be a
* particular source of problems, buried in logic filters.
*
* @param filter the filter to be tested.
* @return true if all sub filters are supported, false otherwise.
* @throws IllegalArgumentException If a null filter is passed in. As this function is recursive
* a null in a logic filter will also cause an error.
*/
public boolean fullySupports(org.geotools.api.filter.Filter filter) {
boolean supports = true;
if (filter == null) {
throw new IllegalArgumentException(
"Null filters can not be " + "unpacked, did you mean " + "Filter.INCLUDE?");
}
if (filter instanceof BinaryLogicOperator) {
BinaryLogicOperator lf = (BinaryLogicOperator) filter;
for (Filter testFilter : lf.getChildren()) {
if (!(this.fullySupports(testFilter))) {
supports = false;
break;
}
}
} else if (filter instanceof Not) {
Not lf = (Not) filter;
if (!(this.fullySupports(lf.getFilter()))) {
supports = false;
}
} else {
supports = this.supports(filter);
}
return supports;
}
private boolean supports(long type) {
return (ops & type) == type;
}
public boolean supports(FilterCapabilities type) {
return (ops & type.ops) == type.ops && functions.containsAll(type.functions);
}
public boolean supports(Class type) {
if (functions.contains(type)) {
return true;
}
for (Class<?> functionClass : functions) {
if (functionClass.isAssignableFrom(type)) {
return true;
}
}
return false;
}
public long getScalarOps() {
return ops
& (SIMPLE_ARITHMETIC
| SIMPLE_COMPARISONS
| FID
| FUNCTIONS
| LIKE
| LOGICAL
| NULL_CHECK
| BETWEEN);
}
public long getSpatialOps() {
return ops
& (SPATIAL_BBOX
| SPATIAL_BEYOND
| SPATIAL_CONTAINS
| SPATIAL_CROSSES
| SPATIAL_DISJOINT
| SPATIAL_DWITHIN
| SPATIAL_EQUALS
| SPATIAL_INTERSECT
| SPATIAL_OVERLAPS
| SPATIAL_TOUCHES
| SPATIAL_WITHIN);
}
/**
* Translates a String into an object that represents the operation
*
* @param name String, operation name
* @return one of the {@link FilterCapabilities} constants
*/
public static FilterCapabilities findOperation(String name) {
return FilterNameTypeMapping.findOperation(name);
}
/**
* Translates a String into an object that represents function expression
*
* @param name String, expression name
* @return one of the {@link FilterCapabilities} constants
*/
public static FilterCapabilities findFunction(String name) {
return FilterNameTypeMapping.findFunction(name);
}
/**
* Convert filter to a constant for use in switch statements. This is an alternative to
* performing instanceof checks.
*
* <p>This utility method for those upgrading to a newer version of GeoTools, instance of checks
* are preferred as they will take into account new kinds of filters (example temporal filters
* added for Filter 2.0 specification). Example:
*
* <pre>
* <code>
* BEFORE: filter.getFilterType() == FilterType.GEOMETRY_CONTAINS
* QUICK: Filters.getFilterType( filter ) == FilterType.GEOMETRY_CONTAINS
* AFTER: filter instanceof Contains
* </code>
* </pre>
*/
private static short getFilterType(org.geotools.api.filter.Filter filter) {
if (filter == null) return 0;
if (filter == org.geotools.api.filter.Filter.EXCLUDE) return FilterType.ALL;
if (filter == org.geotools.api.filter.Filter.INCLUDE) return FilterType.NONE;
if (filter instanceof PropertyIsBetween) return FilterType.BETWEEN;
if (filter instanceof PropertyIsEqualTo) return FilterType.COMPARE_EQUALS;
if (filter instanceof PropertyIsGreaterThan) return FilterType.COMPARE_GREATER_THAN;
if (filter instanceof PropertyIsGreaterThanOrEqualTo)
return FilterType.COMPARE_GREATER_THAN_EQUAL;
if (filter instanceof PropertyIsLessThan) return FilterType.COMPARE_LESS_THAN;
if (filter instanceof PropertyIsLessThanOrEqualTo)
return FilterType.COMPARE_LESS_THAN_EQUAL;
if (filter instanceof PropertyIsNotEqualTo) return FilterType.COMPARE_NOT_EQUALS;
if (filter instanceof Id) return FilterType.FID;
if (filter instanceof BBOX) return FilterType.GEOMETRY_BBOX;
if (filter instanceof Beyond) return FilterType.GEOMETRY_BEYOND;
if (filter instanceof Contains) return FilterType.GEOMETRY_CONTAINS;
if (filter instanceof Crosses) return FilterType.GEOMETRY_CROSSES;
if (filter instanceof Disjoint) return FilterType.GEOMETRY_DISJOINT;
if (filter instanceof DWithin) return FilterType.GEOMETRY_DWITHIN;
if (filter instanceof Equals) return FilterType.GEOMETRY_EQUALS;
if (filter instanceof Intersects) return FilterType.GEOMETRY_INTERSECTS;
if (filter instanceof Overlaps) return FilterType.GEOMETRY_OVERLAPS;
if (filter instanceof Touches) return FilterType.GEOMETRY_TOUCHES;
if (filter instanceof Within) return FilterType.GEOMETRY_WITHIN;
if (filter instanceof PropertyIsLike) return FilterType.LIKE;
if (filter instanceof And) return FilterType.LOGIC_AND;
if (filter instanceof Not) return FilterType.LOGIC_NOT;
if (filter instanceof Or) return FilterType.LOGIC_OR;
if (filter instanceof PropertyIsNull) return FilterType.NULL;
if (filter instanceof Filter) {
return 0;
}
return 0;
}
}