001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2002-2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.filter;
017:
018: import java.math.BigInteger;
019:
020: import org.geotools.feature.Feature;
021: import org.geotools.filter.expression.Value;
022: import org.opengis.filter.expression.ExpressionVisitor;
023:
024: import com.vividsolutions.jts.geom.Geometry;
025:
026: /**
027: * Defines an expression that holds a literal for return.
028: *
029: * @author Rob Hranac, Vision for New York
030: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/main/src/main/java/org/geotools/filter/LiteralExpressionImpl.java $
031: * @version $Id: LiteralExpressionImpl.java 29355 2008-02-18 10:47:10Z aaime $
032: */
033: public class LiteralExpressionImpl extends DefaultExpression implements
034: LiteralExpression {
035:
036: /** Holds a reference to the literal. */
037: private Object literal = null;
038:
039: /** The converted value guessed inside evaluate(Feature) **/
040: private Object parsedValue = null;
041:
042: /**
043: * Constructor with literal.
044: */
045: protected LiteralExpressionImpl() {
046: }
047:
048: /**
049: * Constructor with literal.
050: *
051: * @param literal The literal to store inside this expression.
052: *
053: * @throws IllegalFilterException This literal type is not in scope.
054: */
055: protected LiteralExpressionImpl(Object literal)
056: throws IllegalFilterException {
057: this .setLiteral(literal);
058: }
059:
060: /**
061: * Constructor with literal. This alternative constructor is a convinience
062: * one for integers an Integer object will be constructed, and no
063: * IllegalFilterException can ever be thrown.
064: *
065: * @param value The integer to store inside this expression.
066: */
067: protected LiteralExpressionImpl(int value) {
068: try {
069: this .setLiteral(new Integer(value));
070: } catch (IllegalFilterException ile) {
071: //this is imposible as this is only thrown for
072: //invalid types, and Integer is a valid type
073: throw new AssertionError(
074: "LiteralExpressionImpl is broken, it should accept Integers");
075: }
076: }
077:
078: protected LiteralExpressionImpl(long value) {
079: try {
080: this .setLiteral(new Long(value));
081: } catch (IllegalFilterException ile) {
082: //this is imposible as this is only thrown for
083: //invalid types, and Double is a valid type
084: throw new AssertionError(
085: "LiteralExpressionImpl is broken, it should accept Longs");
086: }
087: }
088:
089: /**
090: * Constructor with literal. This alternative constructor is a convinience
091: * one for doubles an Double object will be constructed, and no
092: * IllegalFilterException can ever be thrown.
093: *
094: * @param value The double to store inside this expression.
095: */
096: protected LiteralExpressionImpl(double value) {
097: try {
098: this .setLiteral(new Double(value));
099: } catch (IllegalFilterException ile) {
100: //this is imposible as this is only thrown for
101: //invalid types, and Double is a valid type
102: throw new AssertionError(
103: "LiteralExpressionImpl is broken, it should accept Doubles");
104: }
105: }
106:
107: /**
108: * Constructor with literal. This alternative constructor is a convinience
109: * one for doubles an Double object will be constructed, and no
110: * IllegalFilterException can ever be thrown.
111: *
112: * @param value The double to store inside this expression.
113: */
114: protected LiteralExpressionImpl(String value) {
115: try {
116: this .setLiteral(value);
117: } catch (IllegalFilterException ile) {
118: //this is imposible as this is only thrown for
119: //invalid types, and String is a valid type
120: throw new AssertionError(
121: "LiteralExpressionImpl is broken, it should accept Strings");
122: }
123: }
124:
125: /**
126: * Returns the literal type.
127: *
128: * @return the short representation of the expression type.
129: */
130: public short getType() {
131: return expressionType;
132: }
133:
134: /**
135: * This method calls {@link #setValue(Object)}.
136: *
137: * @deprecated use {@link #setValue(Object)}.
138: *
139: */
140: public final void setLiteral(Object literal)
141: throws IllegalFilterException {
142: setValue(literal);
143: }
144:
145: /**
146: * This method calls {@link #getValue()}.
147: *
148: * @deprecated use {@link #getValue()}.
149: *
150: */
151: public final Object getLiteral() {
152: return getValue();
153: }
154:
155: /**
156: * Retrieves the literal of this expression.
157: *
158: * @return the literal held by this expression.
159: *
160: */
161: public Object getValue() {
162: return literal;
163: }
164:
165: /**
166: * Sets the literal.
167: *
168: * @param literal The literal to store inside this expression.
169: *
170: * @throws IllegalFilterException This literal type is not in scope.
171: */
172: public final void setValue(Object literal) {
173: if (literal instanceof Double) {
174: expressionType = LITERAL_DOUBLE;
175: } else if (literal instanceof Integer) {
176: expressionType = LITERAL_INTEGER;
177: } else if (literal instanceof Long) {
178: expressionType = LITERAL_LONG;
179: } else if (literal instanceof String) {
180: expressionType = LITERAL_STRING;
181: } else if (literal instanceof Geometry) {
182: expressionType = LITERAL_GEOMETRY;
183: } else {
184: expressionType = LITERAL_UNDECLARED;
185: }
186:
187: this .literal = literal;
188: }
189:
190: /**
191: * Gets the value of this literal.
192: *
193: * @param feature Required by the interface but not used.
194: *
195: * @return the literal held by this expression. Ignores the passed in
196: * feature. The literal held by this expression is almost invariably
197: * a java.lang.String (so that no leading-zeros are lost during a string->
198: * Class conversion. This method will attempt to form the internal
199: * String into a Integer, Double or BigInteger, before failing and
200: * defaulting to a String. To speed things up significantly, use the
201: * evaluate(Object, Class) method so that we don't have to guess
202: * at what you expect back from this evaluate method!
203: *
204: * @throws IllegalArgumentException Feature does not match declared schema.
205: */
206: public Object evaluate(Feature feature)
207: throws IllegalArgumentException {
208: return evaluate((Object) feature);
209: }
210:
211: public Object evaluate(Object feature) {
212: //hrm. Well, now that' we're always storing the internals of
213: //Literals as strings, we need to be slightly smart about how we
214: //return what's inside. Some (err, lots) of code relies on this
215: //method to return an instance of the correct TYPE. I guess we should
216: //try and be somewhat smart about this.
217:
218: //ASSERTION: literal is always a string.
219: if (parsedValue != null)
220: return parsedValue;
221:
222: if (literal == null || !(literal instanceof String)) {
223: parsedValue = literal;
224: } else {
225: String s = (String) literal;
226: Value v = new Value(s);
227: Class[] contexts = new Class[] { Integer.class,
228: BigInteger.class, Double.class };
229: for (int i = 0; i < contexts.length && parsedValue == null; i++) {
230: parsedValue = v.value(contexts[i]);
231: }
232: if (parsedValue == null)
233: parsedValue = literal;
234: }
235: return parsedValue;
236: }
237:
238: public Object evaluate(Object feature, Class context) {
239:
240: Value v = new Value(literal);
241: return v.value(context);
242: }
243:
244: /**
245: * Return this filter as a string.
246: *
247: * @return String representation of this geometry filter.
248: */
249: public String toString() {
250: return literal == null ? "NULL" : literal.toString();
251: }
252:
253: /**
254: * Compares this filter to the specified object. Returns true if the
255: * passed in object is the same as this expression. Checks to make sure
256: * the expression types are the same as well as the literals.
257: *
258: * @param obj - the object to compare this ExpressionLiteral against.
259: *
260: * @return true if specified object is equal to this expression; false
261: * otherwise.
262: *
263: * @task REVISIT: missmatched types now considered not equal. This may be a
264: * problem when comparing Doubles and Integers
265: */
266: public boolean equals(Object obj) {
267: if (obj instanceof LiteralExpressionImpl) {
268: LiteralExpressionImpl expLit = (LiteralExpressionImpl) obj;
269: // This is a problem. The Expression with type String of "2.0"
270: // should be equals to the Expression with type Integer of "2.0"
271: // Same thing with doubles and integers (as noted in the javadocs)
272: /*boolean isEqual = (expLit.getType() == this.expressionType);
273:
274: if (!isEqual) {
275: return false;
276: }*/
277:
278: if ((expLit == null) && (this .literal == null)) {
279: return true;
280: }
281:
282: if (expressionType == LITERAL_GEOMETRY) {
283: return ((Geometry) this .literal)
284: .equals((Geometry) expLit.evaluate(null,
285: Geometry.class));
286: } else if (expressionType == LITERAL_INTEGER) {
287: return ((Integer) this .literal).equals((Integer) expLit
288: .evaluate(null, Integer.class));
289: } else if (expressionType == LITERAL_STRING) {
290: return ((String) this .literal).equals((String) expLit
291: .evaluate(null, String.class));
292: } else if (expressionType == LITERAL_DOUBLE) {
293: return ((Double) this .literal).equals((Double) expLit
294: .evaluate(null, Double.class));
295: } else {
296: return true;
297: }
298: } else {
299: return false;
300: }
301: }
302:
303: /**
304: * Override of hashCode method.
305: *
306: * @return the hash code for this literal expression
307: */
308: public int hashCode() {
309: int result = 17;
310:
311: result = (37 * result)
312: + ((literal == null) ? 0 : literal.hashCode());
313: result = (37 * result) + expressionType;
314:
315: return result;
316: }
317:
318: /**
319: * Used by FilterVisitors to perform some action on this filter instance.
320: * Typicaly used by Filter decoders, but may also be used by any thing
321: * which needs infomration from filter structure. Implementations should
322: * always call: visitor.visit(this); It is importatant that this is not
323: * left to a parent class unless the parents API is identical.
324: *
325: * @param visitor The visitor which requires access to this filter, the
326: * method must call visitor.visit(this);
327: */
328: public Object accept(ExpressionVisitor visitor, Object extraData) {
329: return visitor.visit(this, extraData);
330: }
331: }
|