001 //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.4_testing/src/org/deegree/model/filterencoding/FilterTools.java $
002 /*----------------------------------------------------------------------------
003 This file is part of deegree, http://deegree.org/
004 Copyright (C) 2001-2009 by:
005 Department of Geography, University of Bonn
006 and
007 lat/lon GmbH
008
009 This library is free software; you can redistribute it and/or modify it under
010 the terms of the GNU Lesser General Public License as published by the Free
011 Software Foundation; either version 2.1 of the License, or (at your option)
012 any later version.
013 This library is distributed in the hope that it will be useful, but WITHOUT
014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
015 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
016 details.
017 You should have received a copy of the GNU Lesser General Public License
018 along with this library; if not, write to the Free Software Foundation, Inc.,
019 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020
021 Contact information:
022
023 lat/lon GmbH
024 Aennchenstr. 19, 53177 Bonn
025 Germany
026 http://lat-lon.de/
027
028 Department of Geography, University of Bonn
029 Prof. Dr. Klaus Greve
030 Postfach 1147, 53001 Bonn
031 Germany
032 http://www.geographie.uni-bonn.de/deegree/
033
034 e-mail: info@deegree.org
035 ----------------------------------------------------------------------------*/
036 package org.deegree.model.filterencoding;
037
038 import java.util.ArrayList;
039 import java.util.Iterator;
040 import java.util.List;
041 import java.util.Stack;
042
043 import org.deegree.io.datastore.PropertyPathResolvingException;
044 import org.deegree.model.spatialschema.Envelope;
045 import org.deegree.ogcbase.PropertyPath;
046
047 /**
048 *
049 *
050 *
051 * @version $Revision: 18195 $
052 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
053 * @author last edited by: $Author: mschneider $
054 *
055 * @version 1.0. $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
056 *
057 * @since 2.0
058 */
059 public class FilterTools {
060
061 /**
062 * Traverses the <tt>Filter</tt> -tree and returns the first BBOX-Operation that is found and
063 * a <tt>Filter</tt> that is equal to the given one minus the BBOX-Operation.
064 * <p>
065 *
066 * @param filter
067 * search starts here
068 * @return [0]: <tt>Envelope</tt> (BBOX), [1]: <tt>Filter</tt>
069 * @throws Exception
070 */
071 public static Object[] extractFirstBBOX( ComplexFilter filter )
072 throws Exception {
073
074 // [0]: Envelope, [1]: Filter
075 Object[] objects = new Object[2];
076 objects[1] = filter;
077
078 // sanity check (Filter empty)
079 if ( filter == null ) {
080 return objects;
081 }
082
083 // used as LIFO-queue
084 Stack<Operation> operations = new Stack<Operation>();
085 operations.push( filter.getOperation() );
086
087 while ( !operations.isEmpty() ) {
088 // get the first element of the queue
089 Operation operation = operations.pop();
090
091 switch ( operation.getOperatorId() ) {
092 case OperationDefines.BBOX: {
093 // found BBOX
094 objects[0] = ( (SpatialOperation) operation ).getGeometry().getEnvelope();
095 break;
096 }
097 case OperationDefines.AND: {
098 List<Operation> arguments = ( (LogicalOperation) operation ).getArguments();
099
100 for ( int i = 0; i < arguments.size(); i++ ) {
101 operations.push( arguments.get( i ) );
102 }
103
104 break;
105 }
106 }
107
108 // BBOX found?
109 if ( objects[0] != null ) {
110 break;
111 }
112 }
113
114 // special case: Filter contains only the BBOX-Operation
115 if ( filter.getOperation().getOperatorId() == OperationDefines.BBOX ) {
116 // objects[1] = null;
117 }
118
119 return objects;
120 }
121
122 /**
123 * Traverses the <tt>Filter</tt> -tree and returns the first BBOX-Operation that is found. Be
124 * aware of some limitations, using a shape datastore, only very simple filters are supported,
125 * joins with or, and not are not supported.
126 * <p>
127 *
128 * @param filter
129 * search starts here
130 * @return the first found bbox or <code>null</code> if no bbox was found.
131 */
132 public static Envelope firstBBOX( ComplexFilter filter ) {
133
134 Envelope result = null;
135 if ( filter == null ) {
136 return result;
137 }
138
139 // special case: Filter contains only the BBOX-Operation
140 if ( filter.getOperation().getOperatorId() != OperationDefines.BBOX ) {
141 Stack<Operation> operations = new Stack<Operation>();
142 operations.push( filter.getOperation() );
143 while ( !operations.isEmpty() && result == null ) {
144 Operation operation = operations.pop();
145 switch ( operation.getOperatorId() ) {
146 case OperationDefines.BBOX:
147 // found BBOX
148 result = ( (SpatialOperation) operation ).getGeometry().getEnvelope();
149 break;
150 case OperationDefines.AND:
151 List<Operation> arguments = ( (LogicalOperation) operation ).getArguments();
152 for ( Operation arg : arguments ) {
153 operations.push( arg );
154 }
155 break;
156 }
157 }
158 } else {
159 result = ( (SpatialOperation) filter.getOperation() ).getGeometry().getEnvelope();
160 }
161 return result;
162 }
163
164 /**
165 * Traverses the <tt>Filter</tt> -tree and returns all spatial filter operations. Their
166 * logical relationships are ignored, because within the intended target context, only AND
167 * operations are possible.
168 *
169 * @param filter
170 * search starts here
171 * @return <tt>Filter</tt>-array
172 */
173 public static SpatialOperation[] extractSpatialFilter( ComplexFilter filter ) {
174
175 ArrayList<SpatialOperation> spatialOps = new ArrayList<SpatialOperation>();
176
177 // sanity check (Filter empty)
178 if ( filter == null ) {
179 return ( new SpatialOperation[0] );
180 }
181
182 Stack<Operation> operations = new Stack<Operation>();
183 operations.push( filter.getOperation() );
184
185 while ( !operations.isEmpty() ) {
186 // get the top element from the stack
187 Operation operation = operations.pop();
188
189 switch ( OperationDefines.getTypeById( operation.getOperatorId() ) ) {
190 case OperationDefines.TYPE_SPATIAL: {
191 spatialOps.add( (SpatialOperation) operation );
192 break;
193 }
194 case OperationDefines.TYPE_LOGICAL: {
195 List<Operation> arguments = ( (LogicalOperation) operation ).getArguments();
196 for ( int i = 0; i < arguments.size(); i++ ) {
197 operations.push( arguments.get( i ) );
198 }
199 break;
200 }
201 default: {
202 break;
203 }
204 }
205
206 }
207
208 return spatialOps.toArray( ( new SpatialOperation[spatialOps.size()] ) );
209 }
210
211 /**
212 * returns all {@link PropertyPath} definitions from the passed {@link Filter}
213 *
214 * @see PropertyPath
215 * @see Filter
216 *
217 * @param filter
218 * @return all PropertyPath definitions from the passed Filter
219 * @throws PropertyPathResolvingException
220 */
221 public static List<PropertyPath> extractPropertyPaths( Filter filter )
222 throws PropertyPathResolvingException {
223
224 List<PropertyPath> pp = new ArrayList<PropertyPath>();
225
226 if ( filter instanceof ComplexFilter ) {
227 pp = extractPropertyNameMapFromOperation( ( (ComplexFilter) filter ).getOperation(), pp );
228 } else if ( filter instanceof FeatureFilter ) {
229 // TODO
230 // throw new PropertyPathResolvingException( "FeatureFilter not implemented yet." );
231 }
232
233 return pp;
234
235 }
236
237 private static List<PropertyPath> extractPropertyNameMapFromOperation( Operation operation, List<PropertyPath> list )
238 throws PropertyPathResolvingException {
239 switch ( OperationDefines.getTypeById( operation.getOperatorId() ) ) {
240 case OperationDefines.TYPE_SPATIAL: {
241 list.add( ( (SpatialOperation) operation ).getPropertyName().getValue() );
242 break;
243 }
244 case OperationDefines.TYPE_COMPARISON: {
245 extractPropertyPaths( (ComparisonOperation) operation, list );
246 break;
247 }
248 case OperationDefines.TYPE_LOGICAL: {
249 extractPropertyPaths( (LogicalOperation) operation, list );
250 break;
251 }
252 default: {
253 break;
254 }
255 }
256 return list;
257 }
258
259 private static List<PropertyPath> extractPropertyPaths( ComparisonOperation operation, List<PropertyPath> list )
260 throws PropertyPathResolvingException {
261 switch ( operation.getOperatorId() ) {
262 case OperationDefines.PROPERTYISEQUALTO:
263 case OperationDefines.PROPERTYISLESSTHAN:
264 case OperationDefines.PROPERTYISGREATERTHAN:
265 case OperationDefines.PROPERTYISLESSTHANOREQUALTO:
266 case OperationDefines.PROPERTYISGREATERTHANOREQUALTO: {
267 extractPropertyPaths( ( (PropertyIsCOMPOperation) operation ).getFirstExpression(), list );
268 extractPropertyPaths( ( (PropertyIsCOMPOperation) operation ).getSecondExpression(), list );
269 break;
270 }
271 case OperationDefines.PROPERTYISLIKE: {
272 list.add( ( (PropertyIsLikeOperation) operation ).getPropertyName().getValue() );
273 break;
274 }
275 case OperationDefines.PROPERTYISNULL: {
276 extractPropertyPaths( ( (PropertyIsNullOperation) operation ).getPropertyName(), list );
277 break;
278 }
279 case OperationDefines.PROPERTYISBETWEEN: {
280 extractPropertyPaths( ( (PropertyIsBetweenOperation) operation ).getLowerBoundary(), list );
281 extractPropertyPaths( ( (PropertyIsBetweenOperation) operation ).getUpperBoundary(), list );
282 list.add( ( (PropertyIsBetweenOperation) operation ).getPropertyName().getValue() );
283 break;
284 }
285 default: {
286 break;
287 }
288 }
289 return list;
290 }
291
292 private static List<PropertyPath> extractPropertyPaths( LogicalOperation operation, List<PropertyPath> list )
293 throws PropertyPathResolvingException {
294 List<Operation> operationList = operation.getArguments();
295 Iterator<Operation> it = operationList.iterator();
296 while ( it.hasNext() ) {
297 extractPropertyNameMapFromOperation( it.next(), list );
298 }
299 return list;
300 }
301
302 /**
303 * returns all {@link PropertyPath} definitions from the passed {@link Expression}
304 *
305 * @see PropertyPath
306 * @see Expression
307 *
308 * @param expression
309 * @param list
310 * @return all PropertyPath definitions from the passed Expression
311 * @throws PropertyPathResolvingException
312 */
313 public static List<PropertyPath> extractPropertyPaths( Expression expression, List<PropertyPath> list )
314 throws PropertyPathResolvingException {
315 switch ( expression.getExpressionId() ) {
316 case ExpressionDefines.PROPERTYNAME: {
317 list.add( ( (PropertyName) expression ).getValue() );
318 break;
319 }
320 case ExpressionDefines.ADD:
321 case ExpressionDefines.SUB:
322 case ExpressionDefines.MUL:
323 case ExpressionDefines.DIV: {
324 extractPropertyPaths( ( (ArithmeticExpression) expression ).getFirstExpression(), list );
325 extractPropertyPaths( ( (ArithmeticExpression) expression ).getSecondExpression(), list );
326 break;
327 }
328 case ExpressionDefines.FUNCTION: {
329 // TODO: What about PropertyNames used here?
330 break;
331 }
332 case ExpressionDefines.EXPRESSION:
333 case ExpressionDefines.LITERAL: {
334 break;
335 }
336 }
337 return list;
338 }
339
340 }