001: //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/trunk/src/org/deegree/model/filterencoding/PropertyIsBetweenOperation.java $
002: /*---------------- FILE HEADER ------------------------------------------
003:
004: This file is part of deegree.
005: Copyright (C) 2001-2008 by:
006: EXSE, Department of Geography, University of Bonn
007: http://www.giub.uni-bonn.de/deegree/
008: lat/lon GmbH
009: http://www.lat-lon.de
010:
011: This library is free software; you can redistribute it and/or
012: modify it under the terms of the GNU Lesser General Public
013: License as published by the Free Software Foundation; either
014: version 2.1 of the License, or (at your option) any later version.
015:
016: This library is distributed in the hope that it will be useful,
017: but WITHOUT ANY WARRANTY; without even the implied warranty of
018: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
019: Lesser General Public License for more details.
020:
021: You should have received a copy of the GNU Lesser General Public
022: License along with this library; if not, write to the Free Software
023: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
024:
025: Contact:
026:
027: Andreas Poth
028: lat/lon GmbH
029: Aennchenstr. 19
030: 53177 Bonn
031: Germany
032: E-Mail: poth@lat-lon.de
033:
034: Prof. Dr. Klaus Greve
035: Department of Geography
036: University of Bonn
037: Meckenheimer Allee 166
038: 53115 Bonn
039: Germany
040: E-Mail: greve@giub.uni-bonn.de
041:
042:
043: ---------------------------------------------------------------------------*/
044: package org.deegree.model.filterencoding;
045:
046: import org.deegree.framework.log.ILogger;
047: import org.deegree.framework.log.LoggerFactory;
048: import org.deegree.framework.xml.ElementList;
049: import org.deegree.framework.xml.XMLTools;
050: import org.deegree.model.feature.Feature;
051: import org.w3c.dom.Element;
052:
053: /**
054: * Encapsulates the information of a <PropertyIsBetween>-element (as defined in Filter DTD).
055: *
056: * @author Markus Schneider
057: * @author last edited by: $Author: apoth $
058: *
059: * @version $Revision: 9343 $, $Date: 2007-12-27 05:30:32 -0800 (Thu, 27 Dec 2007) $
060: */
061: public class PropertyIsBetweenOperation extends ComparisonOperation {
062:
063: private static ILogger LOG = LoggerFactory
064: .getLogger(PropertyIsBetweenOperation.class);
065:
066: private PropertyName propertyName;
067:
068: private Expression lowerBoundary;
069:
070: private Expression upperBoundary;
071:
072: /**
073: * @param propertyName
074: * to check against
075: * @param lowerBoundary
076: * of the property
077: * @param upperBoundary
078: * of the property
079: */
080: public PropertyIsBetweenOperation(PropertyName propertyName,
081: Expression lowerBoundary, Expression upperBoundary) {
082: super (OperationDefines.PROPERTYISBETWEEN);
083: this .propertyName = propertyName;
084: this .lowerBoundary = lowerBoundary;
085: this .upperBoundary = upperBoundary;
086: }
087:
088: /**
089: * Given a DOM-fragment, a corresponding Operation-object is built. This method recursively
090: * calls other buildFromDOM () - methods to validate the structure of the DOM-fragment.
091: *
092: * @param element
093: * @return the propertyIsBetween operation
094: *
095: * @throws FilterConstructionException
096: * if the structure of the DOM-fragment is invalid
097: */
098: public static Operation buildFromDOM(Element element)
099: throws FilterConstructionException {
100:
101: // check if root element's name equals 'PropertyIsBetween'
102: if (!element.getLocalName().equals("PropertyIsBetween"))
103: throw new FilterConstructionException(
104: "Name of element does not equal 'PropertyIsBetween'!");
105:
106: ElementList children = XMLTools.getChildElements(element);
107: if (children.getLength() != 3)
108: throw new FilterConstructionException(
109: "'PropertyIsBetween' requires exactly 3 elements!");
110:
111: PropertyName propertyName = (PropertyName) PropertyName
112: .buildFromDOM(children.item(0));
113: Expression lowerBoundary = buildLowerBoundaryFromDOM(children
114: .item(1));
115: Expression upperBoundary = buildUpperBoundaryFromDOM(children
116: .item(2));
117:
118: return new PropertyIsBetweenOperation(propertyName,
119: lowerBoundary, upperBoundary);
120: }
121:
122: /**
123: * Given a DOM-fragment, a corresponding Expression-object (for the LowerBoundary-element) is
124: * built. This method recursively calls other buildFromDOM () - methods to validate the
125: * structure of the DOM-fragment.
126: *
127: * @throws FilterConstructionException
128: * if the structure of the DOM-fragment is invalid
129: */
130: private static Expression buildLowerBoundaryFromDOM(Element element)
131: throws FilterConstructionException {
132:
133: // check if root element's name equals 'LowerBoundary'
134: if (!element.getLocalName().equals("LowerBoundary"))
135: throw new FilterConstructionException(
136: "Name of element does not equal 'LowerBoundary'!");
137:
138: ElementList children = XMLTools.getChildElements(element);
139: if (children.getLength() != 1)
140: throw new FilterConstructionException(
141: "'LowerBoundary' requires exactly 1 element!");
142:
143: return Expression.buildFromDOM(children.item(0));
144: }
145:
146: /**
147: * Given a DOM-fragment, a corresponding Expression-object (for the UpperBoundary-element) is
148: * built. This method recursively calls other buildFromDOM () - methods to validate the
149: * structure of the DOM-fragment.
150: *
151: * @throws FilterConstructionException
152: * if the structure of the DOM-fragment is invalid
153: */
154: private static Expression buildUpperBoundaryFromDOM(Element element)
155: throws FilterConstructionException {
156:
157: // check if root element's name equals 'UpperBoundary'
158: if (!element.getLocalName().equals("UpperBoundary"))
159: throw new FilterConstructionException(
160: "Name of element does not equal 'UpperBoundary'!");
161:
162: ElementList children = XMLTools.getChildElements(element);
163: if (children.getLength() != 1)
164: throw new FilterConstructionException(
165: "'UpperBoundary' requires exactly 1 element!");
166:
167: return Expression.buildFromDOM(children.item(0));
168: }
169:
170: /**
171: * @return the name of the property that shall be compared to the boundaries
172: *
173: */
174: public PropertyName getPropertyName() {
175: return propertyName;
176: }
177:
178: /**
179: * @return the lower boundary of the operation as an <tt>Expression</tt>
180: *
181: */
182: public Expression getLowerBoundary() {
183: return lowerBoundary;
184: }
185:
186: /**
187: * @return the upper boundary of the operation as an <tt>Expression</tt>
188: *
189: */
190: public Expression getUpperBoundary() {
191: return upperBoundary;
192: }
193:
194: /** Produces an indented XML representation of this object. */
195: public StringBuffer toXML() {
196: StringBuffer sb = new StringBuffer(500);
197: sb.append("<ogc:").append(getOperatorName()).append(">");
198: sb.append(propertyName.toXML());
199: sb.append("<ogc:LowerBoundary>");
200: sb.append(lowerBoundary.toXML());
201: sb.append("</ogc:LowerBoundary>");
202: sb.append("<ogc:UpperBoundary>");
203: sb.append(upperBoundary.toXML());
204: sb.append("</ogc:UpperBoundary>");
205: sb.append("</ogc:").append(getOperatorName()).append(">");
206: return sb;
207: }
208:
209: /**
210: * Calculates the <tt>PropertyIsBetween</tt> -Operation's logical value based on the certain
211: * property values of the given <tt>Feature</tt>. TODO: Improve datatype handling.
212: *
213: * @param feature
214: * that determines the property values
215: * @return true, if the <tt>Operation</tt> evaluates to true, else false
216: * @throws FilterEvaluationException
217: * if the evaluation fails
218: */
219: public boolean evaluate(Feature feature)
220: throws FilterEvaluationException {
221:
222: Object lowerValue = lowerBoundary.evaluate(feature);
223: if (lowerValue instanceof String) {
224: lowerValue = new Double((String) lowerValue);
225: }
226: Object upperValue = upperBoundary.evaluate(feature);
227: if (upperValue instanceof String) {
228: upperValue = new Double((String) lowerValue);
229: }
230:
231: if (lowerValue == null || upperValue == null) {
232: // this is because datasource may contain null values for properties
233: // that shall be applied to a 'is between' operation. This shall not
234: // be treated as an exception.
235: return false;
236: }
237:
238: Object this Value = propertyName.evaluate(feature);
239: if (this Value instanceof String) {
240: this Value = new Double((String) lowerValue);
241: }
242:
243: if (!(lowerValue instanceof Number
244: && upperValue instanceof Number && this Value instanceof Number)) {
245: if (this Value == null) {
246: LOG.logInfo("thisValue == null");
247: } else {
248: LOG.logInfo("thisValue > "
249: + this Value.getClass().getName());
250: }
251: throw new FilterEvaluationException(
252: "PropertyIsBetweenOperation can only be "
253: + "applied to numerical expressions!");
254: }
255:
256: double d1 = ((Number) lowerValue).doubleValue();
257: double d2 = ((Number) upperValue).doubleValue();
258: double d3 = ((Number) thisValue).doubleValue();
259: return d1 <= d3 && d3 <= d2;
260: }
261: }
|