root / branches / Mobile_Compatible_Hito_1 / libFMap_data / src / org / gvsig / data / vectorial / filter / FilterUtils.java @ 21563
History | View | Annotate | Download (12.6 KB)
1 |
/*
|
---|---|
2 |
* GeoTools - OpenSource mapping toolkit
|
3 |
* http://geotools.org
|
4 |
* (C) 2005-2006, GeoTools Project Managment Committee (PMC)
|
5 |
*
|
6 |
* This library is free software; you can redistribute it and/or
|
7 |
* modify it under the terms of the GNU Lesser General Public
|
8 |
* License as published by the Free Software Foundation;
|
9 |
* version 2.1 of the License.
|
10 |
*
|
11 |
* This library 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 GNU
|
14 |
* Lesser General Public License for more details.
|
15 |
*/
|
16 |
package org.gvsig.data.vectorial.filter; |
17 |
|
18 |
import java.awt.Color; |
19 |
import java.lang.reflect.Constructor; |
20 |
import java.lang.reflect.InvocationTargetException; |
21 |
import java.util.List; |
22 |
|
23 |
import org.opengis.filter.expression.Expression; |
24 |
import org.opengis.filter.expression.Function; |
25 |
import org.opengis.filter.expression.Literal; |
26 |
|
27 |
/**
|
28 |
* Utility class for working with Filters & Expression.
|
29 |
* <p>
|
30 |
* To get the full benifit you will need to create an instanceof
|
31 |
* this Object (supports your own custom FilterFactory!). Additional
|
32 |
* methods to help create expressions are available.
|
33 |
* </p>
|
34 |
* <p>
|
35 |
* Example use:
|
36 |
* <pre><code>
|
37 |
* Filters filters = new Filters( factory );
|
38 |
* filters.duplicate( origional );
|
39 |
* </code></pre>
|
40 |
* The above example creates a copy of the provided Filter,
|
41 |
* the factory provided will be used when creating the duplicated
|
42 |
* content.
|
43 |
* </p>
|
44 |
* <h3>Expression</h3>
|
45 |
* <p>
|
46 |
* Expressions form an interesting little semi scripting languge,
|
47 |
* intended for queries. A interesting Feature of Filter as a language
|
48 |
* is that it is not strongly typed. This utility class many helper
|
49 |
* methods that ease the transition from Strongly typed Java to the more
|
50 |
* relaxed setting of Expression where most everything can be a string.
|
51 |
* </p>
|
52 |
* <pre><code>
|
53 |
* double sum = Filters.number( Object ) + Filters.number( Object );
|
54 |
* </code></pre>
|
55 |
* The above example will support the conversion of many things into a format
|
56 |
* suitable for addition - the complete list is something like:
|
57 |
* <ul>
|
58 |
* <li>Any instance of Number
|
59 |
* <li>"1234" - aka Integer
|
60 |
* <li>"#FFF" - aka Integer
|
61 |
* <li>"123.0" - aka Double
|
62 |
* </ul>
|
63 |
* A few things (like Geometry and "ABC") will not be considered addative.
|
64 |
* </p>
|
65 |
* In general the scope of these functions should be similar to that
|
66 |
* allowed by the XML Atomic Types, aka those that can be seperated by
|
67 |
* whitespace to form a list.
|
68 |
* </p>
|
69 |
* <p>
|
70 |
* We do our best to be forgiving, any Java class which takes a String as
|
71 |
* a constructor can be tried, and toString() assumed to be the inverse. This
|
72 |
* lets many things (like URL and Date) function without modification.
|
73 |
* </p>
|
74 |
*
|
75 |
* @author Jody Garnett, Refractions Research
|
76 |
* @since GeoTools 2.2.M3
|
77 |
* @source $URL: http://svn.geotools.org/geotools/tags/2.4.2/modules/library/main/src/main/java/org/geotools/filter/Filters.java $
|
78 |
*/
|
79 |
public class FilterUtils { |
80 |
/** <code>NOTFOUND</code> indicates int value was unavailable */
|
81 |
public static final int NOTFOUND = -1; |
82 |
|
83 |
//
|
84 |
// /**
|
85 |
// * Deep copy the filter.
|
86 |
// * <p>
|
87 |
// * Filter objects are mutable, when copying a rich
|
88 |
// * data structure (like SLD) you will need to duplicate
|
89 |
// * the Filters referenced therein.
|
90 |
// * </p>
|
91 |
// */
|
92 |
// public Filter duplicate( Filter filter ){
|
93 |
// DuplicatorFilterVisitor xerox = new DuplicatorFilterVisitor( ff );
|
94 |
// FilterUtils.accept( filter, xerox );
|
95 |
// return (Filter) xerox.getCopy();
|
96 |
//
|
97 |
// }
|
98 |
|
99 |
|
100 |
/**
|
101 |
* Uses number( expr ), will turn result into an interger, or NOTFOUND
|
102 |
*
|
103 |
* @param expr
|
104 |
*
|
105 |
* @return int value of first Number, or NOTFOUND
|
106 |
*/
|
107 |
public static int asInt( Expression expr ) { |
108 |
Number number = (Number) asType(expr, Number.class); |
109 |
|
110 |
if (number != null) { |
111 |
return number.intValue();
|
112 |
} |
113 |
|
114 |
//look for a string
|
115 |
String string = (String) asType(expr,String.class); |
116 |
if (string != null) { |
117 |
//try parsing into a integer
|
118 |
try {
|
119 |
return Integer.parseInt(string); |
120 |
} |
121 |
catch(NumberFormatException e) {} |
122 |
} |
123 |
|
124 |
//no dice
|
125 |
return NOTFOUND;
|
126 |
} |
127 |
|
128 |
/**
|
129 |
* Uses string( expr ), will turn result into a String
|
130 |
*
|
131 |
* @param expr
|
132 |
*
|
133 |
* @return value of first String
|
134 |
*/
|
135 |
public static String asString(Expression expr) { |
136 |
String string = (String) asType(expr, String.class); |
137 |
|
138 |
return string;
|
139 |
} |
140 |
|
141 |
/**
|
142 |
* Uses number( expr ), will turn result into an interger, or NaN.
|
143 |
*
|
144 |
* @param expr
|
145 |
*
|
146 |
* @return int value of first Number, or Double.NaN
|
147 |
*/
|
148 |
public static double asDouble(Expression expr) { |
149 |
Number number = (Number) asType(expr, Number.class); |
150 |
|
151 |
if (number != null) { |
152 |
return number.doubleValue();
|
153 |
} |
154 |
|
155 |
//try for a string
|
156 |
String string = (String) asType(expr,String.class); |
157 |
if (string != null) { |
158 |
//try parsing into a double
|
159 |
try {
|
160 |
return Double.parseDouble(string); |
161 |
} |
162 |
catch(NumberFormatException e) {} |
163 |
} |
164 |
|
165 |
//too bad
|
166 |
return Double.NaN; |
167 |
} |
168 |
|
169 |
/**
|
170 |
* Navigate through the expression seaching for TYPE.
|
171 |
*
|
172 |
* <p>
|
173 |
* This will work even with dynamic expression that would normall require a
|
174 |
* feature. It works especially well when the Expression is a Literal
|
175 |
* literal (which is usually the case).
|
176 |
* </p>
|
177 |
*
|
178 |
* <p>
|
179 |
* If you have a specific Feature, please do this:
|
180 |
* <pre><code>
|
181 |
* Object value = expr.getValue( feature );
|
182 |
* return value instanceof Color ? (Color) value : null;
|
183 |
* </code></pre>
|
184 |
* </p>
|
185 |
*
|
186 |
* @param expr This only really works for downcasting literals to a value
|
187 |
* @param Target type
|
188 |
*
|
189 |
* @return expr smunched into indicated type
|
190 |
*/
|
191 |
public static Object asType(Expression expr, Class TYPE) { |
192 |
// TODO use the new converters stuff
|
193 |
if (expr == null) { |
194 |
return null; |
195 |
} |
196 |
else if (expr instanceof Literal) { |
197 |
Literal literal = (Literal) expr; |
198 |
Object value = literal.getValue();
|
199 |
|
200 |
if (TYPE.isInstance(value)) {
|
201 |
return value;
|
202 |
} |
203 |
} |
204 |
else if (expr instanceof Function) { |
205 |
Function function = (Function) expr; |
206 |
List params = function.getParameters();
|
207 |
// JG - fix me this looks really wrong?
|
208 |
// taking the first parameter that matches?
|
209 |
if ( params != null && params.size() != 0 ) { |
210 |
for (int i = 0; i < params.size(); i++) { |
211 |
Expression e = (Expression) params.get(i); |
212 |
Object value = asType(e, TYPE);
|
213 |
|
214 |
if (value != null) { |
215 |
return value;
|
216 |
} |
217 |
} |
218 |
} |
219 |
} |
220 |
else {
|
221 |
try { // this is a bad idea, not expected to work much |
222 |
Object value = expr.evaluate(null, TYPE ); |
223 |
|
224 |
if (TYPE.isInstance(value)) {
|
225 |
return value;
|
226 |
} |
227 |
} catch (NullPointerException expected) { |
228 |
return null; // well that was not unexpected |
229 |
} catch (Throwable ignore) { // I did say that was a bad idea |
230 |
} |
231 |
} |
232 |
return null; // really need a Feature to acomplish this one |
233 |
} |
234 |
|
235 |
/**
|
236 |
* Treat provided value as a Number, used for math opperations.
|
237 |
* <p>
|
238 |
* This function allows for the non stongly typed Math Opperations
|
239 |
* favoured by the Expression standard.
|
240 |
* </p>
|
241 |
* <p>
|
242 |
* Able to hanle:
|
243 |
* <ul>
|
244 |
* <li>null - to NaN
|
245 |
* <li>Number
|
246 |
* <li>String - valid Integer and Double encodings
|
247 |
* </ul>
|
248 |
*
|
249 |
* </p>
|
250 |
* @param value
|
251 |
* @return double or Double.NaN;
|
252 |
* @throws IllegalArgumentException For non numerical among us -- like Geometry
|
253 |
*/
|
254 |
public static double number(Object value) { |
255 |
if( value == null ) return Double.NaN; |
256 |
if( value instanceof Number ){ |
257 |
Number number = (Number) value; |
258 |
return number.doubleValue();
|
259 |
} |
260 |
if( value instanceof String ){ |
261 |
String text = (String) value; |
262 |
try {
|
263 |
Number number = (Number) gets( text, Number.class ); |
264 |
return number.doubleValue();
|
265 |
} catch (Throwable e) { |
266 |
throw new IllegalArgumentException("Unable to decode '"+text+"' as a number" ); |
267 |
} |
268 |
} |
269 |
if( value instanceof Expression ){ |
270 |
throw new IllegalArgumentException("Cannot deal with un evaulated Expression"); |
271 |
} |
272 |
throw new IllegalArgumentException("Unable to evaulate "+value.getClass()+" in a numeric context"); |
273 |
} |
274 |
|
275 |
/**
|
276 |
* Used to upcovnert a "Text Value" into the provided TYPE.
|
277 |
* <p>
|
278 |
* Used to tread softly on the Java typing system, because
|
279 |
* Filter/Expression is not strongly typed. Values in in
|
280 |
* Expression land are often not the the real Java Objects
|
281 |
* we wish they were - it is reall a small, lax, query
|
282 |
* language and Java objects need a but of help getting
|
283 |
* through.
|
284 |
* <p>
|
285 |
* </p>
|
286 |
* A couple notes:
|
287 |
* <ul>
|
288 |
* <li>Usual trick of reflection for a Constructors that
|
289 |
* supports a String parameter is used as a last ditch effort.
|
290 |
* </li>
|
291 |
* <li>will do its best to turn Object into the indicated Class
|
292 |
* <li>will be used for ordering literals against attribute values
|
293 |
* are calculated at runtime (like Date.)
|
294 |
* </ul>
|
295 |
* Remember Strong typing is for whimps who know what they are
|
296 |
* doing ahead of time. Real programmers let their program
|
297 |
* learn at runtime... :-)
|
298 |
* </p>
|
299 |
*
|
300 |
* @param text
|
301 |
* @param TYPE
|
302 |
* @throws open set of Throwable reflection for TYPE( String )
|
303 |
*/
|
304 |
public static Object gets( String text, Class TYPE ) throws Throwable { |
305 |
if( text == null ) return null; |
306 |
if( TYPE == String.class ) return text; |
307 |
if( TYPE == Integer.class ) { |
308 |
return Integer.decode( text ); |
309 |
} |
310 |
if( TYPE == Double.class ){ |
311 |
return Double.valueOf( text ); |
312 |
} |
313 |
if( TYPE == Number.class ){ |
314 |
try {
|
315 |
return Double.valueOf( text ); |
316 |
} |
317 |
catch( NumberFormatException ignore ){ |
318 |
} |
319 |
return Integer.decode( text ); |
320 |
} |
321 |
if( TYPE == Color.class ){ |
322 |
return new Color( Integer.decode( text ).intValue() ); |
323 |
} |
324 |
try {
|
325 |
Constructor create = TYPE.getConstructor( new Class[]{String.class}); |
326 |
return create.newInstance( new Object[]{ text } ); |
327 |
} catch (SecurityException e) { |
328 |
// hates you
|
329 |
} catch (NoSuchMethodException e) { |
330 |
// nope
|
331 |
} catch (IllegalArgumentException e) { |
332 |
// should not occur
|
333 |
} catch (InstantiationException e) { |
334 |
// should not occur, perhaps the class was abstract?
|
335 |
// eg. Number.class is a bad idea
|
336 |
} catch (IllegalAccessException e) { |
337 |
// hates you
|
338 |
} catch (InvocationTargetException e) { |
339 |
// should of worked but we got a real problem,
|
340 |
// an actual problem
|
341 |
throw e.getCause();
|
342 |
} |
343 |
return null; |
344 |
} |
345 |
|
346 |
public static String puts( double number ){ |
347 |
if( Math.rint(number) == number ){ |
348 |
return Integer.toString( (int) number ); |
349 |
} |
350 |
return Double.toString( number ); |
351 |
} |
352 |
/**
|
353 |
* Inverse of eval, used to softly type supported
|
354 |
* types into Text for use as literals.
|
355 |
*/
|
356 |
public static String puts( Object obj ){ |
357 |
if( obj == null ) return null; |
358 |
if( obj instanceof String) return (String) obj; |
359 |
if( obj instanceof Color ){ |
360 |
Color color = (Color) obj; |
361 |
return puts( color );
|
362 |
} |
363 |
if( obj instanceof Number ){ |
364 |
Number number = (Number) obj; |
365 |
return puts( number.doubleValue() );
|
366 |
} |
367 |
return obj.toString();
|
368 |
} |
369 |
|
370 |
public static String puts( Color color ){ |
371 |
String redCode = Integer.toHexString(color.getRed()); |
372 |
String greenCode = Integer.toHexString(color.getGreen()); |
373 |
String blueCode = Integer.toHexString(color.getBlue()); |
374 |
|
375 |
if (redCode.length() == 1) redCode = "0" + redCode; |
376 |
if (greenCode.length() == 1) greenCode = "0" + greenCode; |
377 |
if (blueCode.length() == 1) blueCode = "0" + blueCode; |
378 |
|
379 |
return "#" + redCode + greenCode + blueCode; |
380 |
} |
381 |
} |
382 |
|