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 | 21563 | jcarrasco | /*
|
---|---|---|---|
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 | } |