/* * 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.data.postgis; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import org.geotools.data.postgis.fidmapper.VersionedFIDMapper; import org.geotools.filter.visitor.DuplicatingFilterVisitor; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.filter.Filter; import org.opengis.filter.FilterFactory2; import org.opengis.filter.Id; import org.opengis.filter.PropertyIsEqualTo; /** * Takes a filter that eventually contains a fid filter and builds a new filter that does not have * it, and relies on attributes instead. This assumes pk attributes are part of the feature type. * <br> * This cloning is necessary because public FID do not contain the revision attribute, that will be * handled by including new filters. * * @author aaime * @since 2.4 * */ class FidTransformeVisitor extends DuplicatingFilterVisitor { /** The logger for the postgis module. */ protected static final Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geotools.data.postgis"); private VersionedFIDMapper mapper; private Object featureType; public FidTransformeVisitor(FilterFactory2 factory, SimpleFeatureType featureType, VersionedFIDMapper mapper) { super(factory); this.mapper = mapper; this.featureType = featureType; } public Object visit(Id filter, Object extraData) { Set ids = filter.getIDs(); if (ids.isEmpty()) { throw new IllegalArgumentException( "Invalid fid filter provides, has no fids inside"); } Filter result = null; List<Filter> transformedIdFilters = new ArrayList<Filter>(); for (Iterator it = ids.iterator(); it.hasNext();) { String id = (String) it.next(); Object[] attributes; try { attributes = mapper.getUnversionedPKAttributes(id); } catch(IOException e) { // assume the fid provided is not in the format the mapper can handle, so // it's not really a real datastore fid but has been provided by the user. // No harm dome, we just need to skip it if(LOGGER.isLoggable(Level.FINE)) LOGGER.fine("Skipping fid " + id + " since it's not in the " + "proper format for this datastore" + e.getMessage()); continue; } Filter idf = null; for (int i = 0, j = 0; i < attributes.length; j++) { String colName = mapper.getColumnName(j); if ("revision".equals(colName)) continue; transformedIdFilters.add(ff.equals(ff.property(colName), ff.literal(attributes[i]))); i++; } } // build the or of all the property is equals equivalent to each id filter if(transformedIdFilters.size() > 1) { result = ff.or(transformedIdFilters); } else if (transformedIdFilters.size() == 1) { result = transformedIdFilters.get(0); } // if all the fids are in an improper format, the fid filter is equivalent to // a Filter that excludes everything... Since I cannot use Filter.EXCLUDE (it breaks // the filter splitter with a class cast exception) I'm falling back on the old // "1 = 0" filter (ugly, but works...) if(result == null) { PropertyIsEqualTo equal = ff.equals(ff.literal(0),ff.literal(1)); return equal; } else return result; } }