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: // Geotools dependencies
019: import java.util.ArrayList;
020: import java.util.Iterator;
021: import java.util.List;
022: import java.util.logging.Logger;
023:
024: import org.opengis.filter.And;
025: import org.opengis.filter.FilterVisitor;
026: import org.opengis.filter.Or;
027:
028: /**
029: * Defines a logic filter (the only filter type that contains other filters).
030: * This filter holds one or more filters together and relates them logically
031: * with an internally defined type (AND, OR, NOT).
032: *
033: * @author Rob Hranac, TOPP
034: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/main/src/main/java/org/geotools/filter/LogicFilterImpl.java $
035: * @version $Id: LogicFilterImpl.java 27862 2007-11-12 19:51:19Z desruisseaux $
036: */
037: public abstract class LogicFilterImpl extends BinaryLogicAbstract
038: implements LogicFilter {
039: /** The logger for the default core module. */
040: private static final Logger LOGGER = org.geotools.util.logging.Logging
041: .getLogger("org.geotools.core");
042:
043: protected LogicFilterImpl(FilterFactory factory) {
044: this (factory, new ArrayList());
045: }
046:
047: protected LogicFilterImpl(FilterFactory factory, List children) {
048: super (factory, children);
049: }
050:
051: /**
052: * Constructor with type (must be valid).
053: *
054: * @param filterType The final relation between all sub filters.
055: *
056: * @throws IllegalFilterException If the filtertype is not a logic type.
057: * @deprecated Consructing with type constants should be replaced with
058: * an actual java type.
059: */
060: protected LogicFilterImpl(short filterType)
061: throws IllegalFilterException {
062: super (FilterFactoryFinder.createFilterFactory(),
063: new ArrayList());
064: LOGGER.finest("filtertype " + filterType);
065:
066: if (isLogicFilter(filterType)) {
067: this .filterType = filterType;
068: } else {
069: throw new IllegalFilterException(
070: "Attempted to create logic filter with non-logic type.");
071: }
072: }
073:
074: /**
075: * Convenience constructor to create a NOT logic filter.
076: *
077: * @param filter The initial sub filter.
078: * @param filterType The final relation between all sub filters.
079: *
080: * @throws IllegalFilterException Does not conform to logic filter
081: * structure
082: */
083: protected LogicFilterImpl(Filter filter, short filterType)
084: throws IllegalFilterException {
085:
086: super (FilterFactoryFinder.createFilterFactory(),
087: new ArrayList());
088: if (isLogicFilter(filterType)) {
089: this .filterType = filterType;
090: } else {
091: throw new IllegalFilterException(
092: "Attempted to create logic filter with non-logic type.");
093: }
094:
095: children.add(filter);
096: }
097:
098: /**
099: * Convenience constructor to create an AND/OR logic filter.
100: *
101: * @param filter1 An initial sub filter.
102: * @param filter2 An initial sub filter.
103: * @param filterType The final relation between all sub filters.
104: *
105: * @throws IllegalFilterException Does not conform to logic filter
106: * structure
107: */
108: protected LogicFilterImpl(Filter filter1, Filter filter2,
109: short filterType) throws IllegalFilterException {
110: super (FilterFactoryFinder.createFilterFactory(),
111: new ArrayList());
112:
113: if (isLogicFilter(filterType)) {
114: this .filterType = filterType;
115: } else {
116: throw new IllegalFilterException(
117: "Attempted to create logic filter with non-logic type.");
118: }
119:
120: // Push the initial filter on the stack
121: children.add(filter1);
122:
123: // Add the second filter via internal method to check for illegal NOT
124: this .addFilter(filter2);
125: }
126:
127: /**
128: * Adds a sub filter to this filter.
129: *
130: * @param filter Specified filter to add to the sub filter list.
131: *
132: * @throws IllegalFilterException Does not conform to logic filter
133: * structure
134: *
135: * @task REVISIT: make all filters immutable. This should return a new
136: * filter.
137: */
138: public final void addFilter(org.opengis.filter.Filter filter)
139: throws IllegalFilterException {
140: if ((filterType != LOGIC_NOT) || (children.size() == 0)) {
141: children.add(filter);
142: } else {
143: throw new IllegalFilterException(
144: "Attempted to add an more than one filter to a NOT filter.");
145: }
146: }
147:
148: /**
149: * Gets an iterator for the filters held by this logic filter.
150: *
151: * @return the iterator of the filters.
152: */
153: public Iterator getFilterIterator() {
154: return children.iterator();
155: }
156:
157: /**
158: * Implements a logical OR with this filter and returns the merged filter.
159: *
160: * @param filter Parent of the filter: must implement GMLHandlerGeometry.
161: *
162: * @return ORed filter.
163: *
164: * @task REVISIT: make immutable, should not modify the subfilters of the
165: * filter being ored.
166: */
167: public Filter or(org.opengis.filter.Filter filter) {
168: // Just makes sure that we are not creating unnecessary new filters
169: // by popping onto stack if current filter is OR
170: //HACK: not sure what should be returned by this method
171: //HACK: assuming it is the result of each method
172: //REVISIT: should return a new copy, must implement cloneable to do so.
173: if (filterType == super .LOGIC_OR) {
174: if (filter instanceof Or) {
175: Or more = (Or) filter;
176: children.addAll(more.getChildren());
177: } else {
178: children.add(filter);
179: }
180: return this ;
181: } else {
182: return super .or(filter);
183: }
184: }
185:
186: /**
187: * Implements a logical AND with this filter and returns the merged filter.
188: *
189: * @param filter Parent of the filter: must implement GMLHandlerGeometry.
190: *
191: * @return ANDed filter.
192: *
193: * @task REVISIT: make immutable, should not modify the subfilters of the
194: * filter being anded.
195: */
196: public Filter and(org.opengis.filter.Filter filter) {
197: // Just makes sure that we are not creating unnecessary new filters
198: // by popping onto stack if current filter is AND
199: //HACK: not sure what should be returned by this method
200: //HACK: assuming it is the result of each method
201: if (filterType == super .LOGIC_AND) {
202: if (filter instanceof And) {
203: And more = (And) filter;
204: children.addAll(more.getChildren());
205: } else {
206: children.add(filter);
207: }
208: return this ;
209: } else {
210: return super .and(filter);
211: }
212: }
213:
214: /**
215: * Implements a logical NOT with this filter and returns the merged filter.
216: *
217: * @return NOTed filter.
218: */
219: public Filter not() {
220: // Just makes sure that we are not creating unnecessary new filters
221: // by popping off sub filter if current filter is NOT
222: //HACK: not sure what should be returned by this method
223: //HACK: assuming it is the result of each method
224: if (filterType == super .LOGIC_NOT) {
225: return (Filter) children.get(0);
226: } else {
227: return super .not();
228: }
229: }
230:
231: /**
232: * package private method to get the internal storage of filters.
233: *
234: * @return the internal sub filter list.
235: *
236: * @deprecated use {@link #getChildren()}
237: */
238: List getSubFilters() {
239: return children;
240: }
241:
242: /**
243: * Returns a string representation of this filter.
244: *
245: * @return String representation of the logic filter.
246: */
247: public String toString() {
248: String returnString = "[";
249: String operator = "";
250: Iterator iterator = children.iterator();
251:
252: if (filterType == LOGIC_OR) {
253: operator = " OR ";
254: } else if (filterType == LOGIC_AND) {
255: operator = " AND ";
256: } else if (filterType == LOGIC_NOT) {
257: return "NOT " + iterator.next().toString();
258: }
259:
260: while (iterator.hasNext()) {
261: returnString = returnString + iterator.next().toString();
262:
263: if (iterator.hasNext()) {
264: returnString = returnString + operator;
265: }
266: }
267:
268: return returnString + "]";
269: }
270:
271: /**
272: * Compares this filter to the specified object. Returns true if the
273: * passed in object is the same as this filter. Checks to make sure the
274: * filter types are the same, and then checks that the subFilters lists
275: * are the same size and that one list contains the other. This means
276: * that logic filters with different internal orders of subfilters are
277: * equal.
278: *
279: * @param obj - the object to compare this LogicFilter against.
280: *
281: * @return true if specified object is equal to this filter; false
282: * otherwise.
283: */
284: public boolean equals(Object obj) {
285: if (obj == this )
286: return true;
287: if ((obj != null) && (obj.getClass() == this .getClass())) {
288: LogicFilterImpl logFilter = (LogicFilterImpl) obj;
289: LOGGER.finest("filter type match:"
290: + (logFilter.getFilterType() == this .filterType));
291: LOGGER
292: .finest("same size:"
293: + (logFilter.getSubFilters().size() == this .children
294: .size()) + "; inner size: "
295: + logFilter.getSubFilters().size()
296: + "; outer size: " + this .children.size());
297: LOGGER.finest("contains:"
298: + logFilter.getSubFilters().containsAll(
299: this .children));
300:
301: return ((logFilter.getFilterType() == this .filterType)
302: && (logFilter.getSubFilters().size() == this .children
303: .size()) && logFilter.getSubFilters()
304: .containsAll(this .children));
305: } else {
306: return false;
307: }
308: }
309:
310: /**
311: * Override of hashCode method.
312: *
313: * @return a code to hash this object by.
314: */
315: public int hashCode() {
316: int result = 17;
317: result = (37 * result) + filterType;
318: result = (37 * result) + children.hashCode();
319:
320: return result;
321: }
322:
323: /**
324: * Used by FilterVisitors to perform some action on this filter instance.
325: * Typicaly used by Filter decoders, but may also be used by any thing
326: * which needs infomration from filter structure. Implementations should
327: * always call: visitor.visit(this); It is importatant that this is not
328: * left to a parent class unless the parents API is identical.
329: *
330: * @param visitor The visitor which requires access to this filter, the
331: * method must call visitor.visit(this);
332: */
333: public abstract Object accept(FilterVisitor visitor,
334: Object extraData);
335: }
|