/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2002-2008, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.filter;
// Geotools dependencies
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Logger;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.filter.expression.PropertyAccessor;
import org.geotools.filter.expression.PropertyAccessors;
import org.geotools.filter.expression.SimpleFeaturePropertyAccessorFactory;
import org.opengis.filter.FilterVisitor;
import org.opengis.filter.identity.Identifier;
/**
* Defines a ID filter, which holds a list of IDs ( usually feature id;s ). This
* filter stores a series of IDs, which are used to distinguish features
* uniquely.
*
* Please note that addAllFids( Collection ) may be a performance hog; uDig
* makes use of its own implementation of FidFilter in order to reuse the
* internal set of fids between uses.
*
*
* @author Rob Hranac, TOPP
* @author Justin Deoliveira, TOPP
*
* TODO: this class shoul be renamed to IdFilterImpl
*
* @source $URL:
* http://svn.geotools.org/geotools/trunk/gt/modules/library/main/src/main/java/org/geotools/filter/FidFilterImpl.java $
* @version $Id$
*/
public class FidFilterImpl extends AbstractFilterImpl implements FidFilter {
/** Logger for the default core module. */
private static final Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geotools.core");
/** List of the Identifer. */
private Set fids = new HashSet();
/**
* Empty constructor.
*
* @deprecated use {@link #FidFilterImpl(Set)}
*/
protected FidFilterImpl() {
super(CommonFactoryFinder.getFilterFactory(null));
filterType = AbstractFilter.FID;
}
/**
* Constructor with first fid set
*
* @param initialFid
* The type of comparison.
* @deprecated use {@link #FidFilterImpl(Set)}
*/
protected FidFilterImpl(String initialFid) {
super(CommonFactoryFinder.getFilterFactory(null));
filterType = AbstractFilter.FID;
addFid(initialFid);
}
/**
* Constructor which takes {@link org.opengis.filter.identity.Identifier},
* not String.
*
*/
protected FidFilterImpl(Set/* */fids) {
super(CommonFactoryFinder.getFilterFactory(null));
filterType = AbstractFilter.FID;
// check these are really identifiers
for (Iterator it = fids.iterator(); it.hasNext();) {
Object next = it.next();
if (!(next instanceof Identifier))
throw new ClassCastException("Fids must implement Identifier, "
+ next.getClass() + " does not");
}
this.fids = fids;
}
/**
* Returns all the fids in this filter.
*
* @return An array of all the fids in this filter.
*
* @deprecated use {@link #getIDs()}
*/
public final String[] getFids() {
return (String[]) fids().toArray(new String[0]);
}
/**
* @see org.opengis.filter.Id#getIDs()
*/
public Set getIDs() {
return getFidsSet();
}
/**
* @see org.opengis.filter.Id#getIdentifiers()
*/
public Set getIdentifiers() {
return fids;
}
/**
* @see org.opengis.filter.identity.FeatureId#setIDs(Set)
*/
public void setIDs(Set ids) {
fids = new HashSet();
addAllFids(ids);
}
/**
* Accessor method for fid set as Strings.
*
* @return the internally stored fids.
*/
public Set getFidsSet() {
return fids();
}
/**
* Helper method to pull out strings from featureId set.
*
* @return
*/
private Set fids() {
Set set = new TreeSet();
for (Iterator i = fids.iterator(); i.hasNext();) {
Identifier id = (Identifier) i.next();
set.add(id.toString());
}
return set;
}
/**
* Adds a feature ID to the filter.
*
* @param fid
* A single feature ID.
* @deprecated
*/
public final void addFid(String fid) {
LOGGER.finest("got fid: " + fid);
fids.add(factory.featureId(fid));
}
/**
* Adds a collection of feature IDs to the filter.
*
* @param fidsToAdd
* A collection of feature IDs as strings.
*/
public void addAllFids(Collection fidsToAdd) {
if (fidsToAdd == null)
return;
for (Iterator i = fidsToAdd.iterator(); i.hasNext();) {
String fid = (String) i.next();
addFid(fid);
}
}
/**
* Removes a feature ID from the filter.
*
* @param fid
* A single feature ID.
*/
public final void removeFid(String fid) {
if (fid == null) {
return;
}
for (Iterator f = fids.iterator(); f.hasNext();) {
Identifier featureId = (Identifier) f.next();
if (fid.equals(featureId.toString())) {
f.remove();
}
}
}
/**
* Removes a collection of feature IDs from the filter.
*
* @param fidsToRemove
* A collection of feature IDs.
*/
public void removeAllFids(Collection fidsToRemove) {
if (fidsToRemove == null)
return;
for (Iterator f = fidsToRemove.iterator(); f.hasNext();) {
String fid = (String) f.next();
removeFid(fid);
}
}
/**
* Determines whether or not the given feature's ID matches this filter.
*
* In order to get the object's ID, the {@link PropertyAccessor} capable of
* dealing with feature
has to support the request of the
* expression "@id"
*
*
* @param feature
* Specified feature to examine.
*
* @return true if the feature's ID matches an fid held by this
* filter, false otherwise.
* @see SimpleFeaturePropertyAccessorFactory
*/
public boolean evaluate(Object feature) {
if (feature == null) {
return false;
}
final Set fids = fids();
final String attPath = "@id";
PropertyAccessor accessor = PropertyAccessors.findPropertyAccessor(feature, attPath, null, null);
if (accessor == null) {
return false;
}
Object id = accessor.get(feature, attPath, null);
return fids.contains(id);
}
/**
* Returns a string representation of this filter.
*
* @return String representation of the compare filter.
*/
public String toString() {
StringBuffer fidFilter = new StringBuffer();
Iterator fidIterator = fids.iterator();
while (fidIterator.hasNext()) {
fidFilter.append(fidIterator.next().toString());
if (fidIterator.hasNext()) {
fidFilter.append(", ");
}
}
return "[ " + fidFilter.toString() + " ]";
}
/**
* Used by FilterVisitors to perform some action on this filter instance.
* Typicaly used by Filter decoders, but may also be used by any thing which
* needs infomration from filter structure. Implementations should always
* call: visitor.visit(this); It is importatant that this is not left to a
* parent class unless the parents API is identical.
*
* @param visitor
* The visitor which requires access to this filter, the method
* must call visitor.visit(this);
*/
public Object accept(FilterVisitor visitor, Object extraData) {
return visitor.visit(this, extraData);
}
/**
* Returns a flag indicating object equality.
*
* @param filter
* the filter to test equality on.
*
* @return String representation of the compare filter.
*/
public boolean equals(Object filter) {
LOGGER.finest("condition: " + filter);
if ((filter != null) && (filter.getClass() == this.getClass())) {
LOGGER.finest("condition: " + ((FidFilterImpl) filter).filterType);
if (((FidFilterImpl) filter).filterType == AbstractFilter.FID) {
return fids.equals(((FidFilterImpl) filter).fids);
} else {
return false;
}
} else {
return false;
}
}
/**
* Override of hashCode method.
*
* @return a hash code value for this fid filter object.
*/
public int hashCode() {
return fids.hashCode();
}
}