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.util.logging.Level;
019: import java.util.logging.Logger;
020:
021: import org.geotools.factory.Hints;
022: import org.geotools.feature.Feature;
023: import org.geotools.feature.FeatureType;
024: import org.geotools.filter.expression.PropertyAccessor;
025: import org.geotools.filter.expression.PropertyAccessorFactory;
026: import org.geotools.filter.expression.PropertyAccessors;
027: import org.geotools.filter.expression.Value;
028: import org.opengis.filter.expression.ExpressionVisitor;
029:
030: /**
031: * Defines a complex filter (could also be called logical filter). This filter
032: * holds one or more filters together and relates them logically in an
033: * internally defined manner.
034: *
035: * @author Rob Hranac, TOPP
036: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/main/src/main/java/org/geotools/filter/AttributeExpressionImpl.java $
037: * @version $Id: AttributeExpressionImpl.java 27862 2007-11-12 19:51:19Z desruisseaux $
038: */
039: public class AttributeExpressionImpl extends DefaultExpression
040: implements AttributeExpression {
041: /** The logger for the default core module. */
042: private static final Logger LOGGER = org.geotools.util.logging.Logging
043: .getLogger("org.geotools.core");
044:
045: /** Holds all sub filters of this filter. */
046: protected String attPath;
047:
048: /** Holds all sub filters of this filter. */
049: protected FeatureType schema = null;
050:
051: /** Holds hints for the property accessor factory */
052: private Hints hints;
053:
054: /**
055: * Constructor with the schema for this attribute.
056: *
057: * @param schema The schema for this attribute.
058: */
059: protected AttributeExpressionImpl(FeatureType schema) {
060: this .schema = schema;
061: this .expressionType = ATTRIBUTE;
062: }
063:
064: /**
065: * Constructor with schema and path to the attribute.
066: *
067: * @param xpath the String xpath to the attribute.
068: */
069: public AttributeExpressionImpl(String xpath) {
070: this (xpath, null);
071: }
072:
073: /**
074: * Constructor with schema and path to the attribute.
075: *
076: * @param xpath the String xpath to the attribute.
077: * @param propertyAccessorHints hints to be passed to
078: * {@link PropertyAccessorFactory#createPropertyAccessor(Class, String, Class, Hints)}
079: * at evaluation time.
080: */
081: public AttributeExpressionImpl(String xpath,
082: Hints propertyAccessorHints) {
083: attPath = xpath;
084: schema = null;
085: hints = propertyAccessorHints;
086: this .expressionType = ATTRIBUTE;
087: }
088:
089: /**
090: * Constructor with schema and path to the attribute.
091: *
092: * @param schema The initial (required) sub filter.
093: * @param attPath the xpath to the attribute.
094: *
095: * @throws IllegalFilterException If the attribute path is not in the
096: * schema.
097: */
098: protected AttributeExpressionImpl(FeatureType schema, String attPath)
099: throws IllegalFilterException {
100: this .schema = schema;
101: this .expressionType = ATTRIBUTE;
102: setAttributePath(attPath);
103: }
104:
105: /**
106: * Constructor with minimum dataset for a valid expression.
107: *
108: * @param attPath The initial (required) sub filter.
109: *
110: * @throws IllegalFilterException If the attribute path is not in the
111: * schema.
112: *
113: * @deprecated use {@link #setPropertyName(String)}
114: */
115: public final void setAttributePath(String attPath)
116: throws IllegalFilterException {
117: setPropertyName(attPath);
118: }
119:
120: /**
121: * This method calls {@link #getPropertyName()}.
122: *
123: * @deprecated use {@link #getPropertyName()}
124: */
125: public final String getAttributePath() {
126: return getPropertyName();
127: }
128:
129: /**
130: * Gets the path to the attribute to be evaluated by this expression.
131: *
132: * {@link org.opengis.filter.expression.PropertyName#getPropertyName()}
133: */
134: public String getPropertyName() {
135: return attPath;
136: }
137:
138: public void setPropertyName(String attPath) {
139: LOGGER.entering("ExpressionAttribute", "setAttributePath",
140: attPath);
141: if (LOGGER.isLoggable(Level.FINEST))
142: LOGGER.finest("schema: " + schema + "\n\nattribute: "
143: + attPath);
144:
145: if (schema != null) {
146: if (schema.hasAttributeType(attPath)) {
147: this .attPath = attPath;
148: } else {
149:
150: throw new IllegalFilterException("Attribute: "
151: + attPath + " is not in stated schema "
152: + schema.getTypeName() + ".");
153:
154: }
155: } else {
156: this .attPath = attPath;
157: }
158: }
159:
160: /**
161: * Gets the value of this attribute from the passed feature.
162: *
163: * @param feature Feature from which to extract attribute value.
164: */
165: public Object evaluate(Feature feature) {
166: PropertyAccessor accessor = PropertyAccessors
167: .findPropertyAccessor(feature, attPath, null, null);
168: if (accessor == null) {
169: //JD:not throwing exception to remain backwards compatabile, just returnign null
170: return null;
171: // throw new IllegalArgumentException(
172: // "Could not find property accessor for: (" + feature + "," + attPath + ")"
173: // );
174: }
175:
176: return accessor.get(feature, attPath, null);
177: //return feature.getAttribute(attPath);
178: }
179:
180: /**
181: * Gets the value of this property from the passed object.
182: *
183: * @param obj Object from which we need to extract a property value.
184: */
185: public Object evaluate(Object obj) {
186: return evaluate(obj, null);
187: }
188:
189: public Object evaluate(Object obj, Class target) {
190: PropertyAccessor accessor = getPropertyAccessor(obj, target);
191:
192: if (accessor == null) {
193: return null; //JD:not throwing exception to remain backwards compatabile, just returnign null
194: }
195: Object propertyValue = accessor.get(obj, attPath, target);
196: if (target == null)
197: return propertyValue;
198:
199: Value value = new Value(propertyValue);
200: return value.value(target); // pull into the requested shape
201:
202: }
203:
204: private PropertyAccessor lastAccessor;
205:
206: private PropertyAccessor getPropertyAccessor(Object obj,
207: Class target) {
208: if (lastAccessor == null)
209: lastAccessor = PropertyAccessors.findPropertyAccessor(obj,
210: attPath, target, hints);
211: else if (!lastAccessor.canHandle(obj, attPath, target))
212: lastAccessor = PropertyAccessors.findPropertyAccessor(obj,
213: attPath, target, hints);
214:
215: return lastAccessor;
216: }
217:
218: /**
219: * Return this expression as a string.
220: *
221: * @return String representation of this attribute expression.
222: */
223: public String toString() {
224: return attPath;
225: }
226:
227: /**
228: * Compares this filter to the specified object. Returns true if the
229: * passed in object is the same as this expression. Checks to make sure
230: * the expression types are the same as well as the attribute paths and
231: * schemas.
232: *
233: * @param obj - the object to compare this ExpressionAttribute against.
234: *
235: * @return true if specified object is equal to this filter; else false
236: */
237: public boolean equals(Object obj) {
238: if (obj.getClass() == this .getClass()) {
239: AttributeExpressionImpl expAttr = (AttributeExpressionImpl) obj;
240:
241: boolean isEqual = (expAttr.getType() == this .expressionType);
242: if (LOGGER.isLoggable(Level.FINEST))
243: LOGGER.finest("expression type match:" + isEqual
244: + "; in:" + expAttr.getType() + "; out:"
245: + this .expressionType);
246: isEqual = (expAttr.attPath != null) ? (isEqual && expAttr.attPath
247: .equals(this .attPath))
248: : (isEqual && (this .attPath == null));
249: if (LOGGER.isLoggable(Level.FINEST))
250: LOGGER.finest("attribute match:" + isEqual + "; in:"
251: + expAttr.getAttributePath() + "; out:"
252: + this .attPath);
253: isEqual = (expAttr.schema != null) ? (isEqual && expAttr.schema
254: .equals(this .schema))
255: : (isEqual && (this .schema == null));
256: if (LOGGER.isLoggable(Level.FINEST))
257: LOGGER.finest("schema match:" + isEqual + "; in:"
258: + expAttr.schema + "; out:" + this .schema);
259:
260: return isEqual;
261: } else {
262: return false;
263: }
264: }
265:
266: /**
267: * Override of hashCode method.
268: *
269: * @return a code to hash this object by.
270: */
271: public int hashCode() {
272: int result = 17;
273: result = (37 * result)
274: + (attPath == null ? 0 : attPath.hashCode());
275: result = (37 * result)
276: + (schema == null ? 0 : schema.hashCode());
277: return result;
278: }
279:
280: /**
281: * Used by FilterVisitors to perform some action on this filter instance.
282: * Typicaly used by Filter decoders, but may also be used by any thing
283: * which needs infomration from filter structure. Implementations should
284: * always call: visitor.visit(this); It is importatant that this is not
285: * left to a parent class unless the parents API is identical.
286: *
287: * @param visitor The visitor which requires access to this filter, the
288: * method must call visitor.visit(this);
289: */
290: public Object accept(ExpressionVisitor visitor, Object extraData) {
291: return visitor.visit(this, extraData);
292: }
293: }
|