org.geotools.data.DiffFeatureReader Maven / Gradle / Ivy
Show all versions of gt-main Show documentation
/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2003-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;
import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.geom.Geometry;
import org.opengis.feature.Feature;
import org.opengis.feature.IllegalAttributeException;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.type.FeatureType;
import org.opengis.filter.Filter;
import org.opengis.filter.Id;
import org.opengis.filter.expression.PropertyName;
import org.opengis.filter.identity.Identifier;
import org.opengis.filter.spatial.BBOX;
import org.opengis.filter.spatial.BinarySpatialOperator;
import org.opengis.filter.spatial.Contains;
import org.opengis.filter.spatial.Crosses;
import org.opengis.filter.spatial.Overlaps;
import org.opengis.filter.spatial.Touches;
import org.opengis.filter.spatial.Within;
/**
* A FeatureReader that considers differences.
*
* Used to implement In-Process Transaction support. This implementation will need to peek ahead
* in order to check for deletetions.
*
* @author Jody Garnett, Refractions Research
*/
public class DiffFeatureReader
implements FeatureReader {
FeatureReader reader;
Diff diff;
/** Next value as peeked by hasNext() */
F next = null;
private Filter filter;
private Set encounteredFids;
private Iterator addedIterator;
private Iterator modifiedIterator;
private Iterator fids;
private Iterator spatialIndexIterator;
private boolean indexedGeometryFilter = false;
private boolean fidFilter = false;
/**
* This constructor grabs a "copy" of the current diff.
*
* This reader is not "live" to changes over the course of the Transaction. (Iterators are
* not always stable of the course of modifications)
*
* @param diff2 Differences of Feature by FID
*/
public DiffFeatureReader(FeatureReader reader, Diff diff2) {
this(reader, diff2, Filter.INCLUDE);
}
/**
* This constructor grabs a "copy" of the current diff.
*
* This reader is not "live" to changes over the course of the Transaction. (Iterators are
* not always stable of the course of modifications)
*
* @param diff2 Differences of Feature by FID
*/
public DiffFeatureReader(FeatureReader reader, Diff diff2, Filter filter) {
this.reader = reader;
this.diff = diff2;
this.filter = filter;
encounteredFids = new HashSet();
if (filter instanceof Id) {
fidFilter = true;
} else if (isSubsetOfBboxFilter(filter)) {
indexedGeometryFilter = true;
}
synchronized (diff) {
if (indexedGeometryFilter) {
spatialIndexIterator = getIndexedFeatures().iterator();
}
addedIterator = (Iterator) diff.getAdded().values().iterator();
modifiedIterator = (Iterator) diff.getModified().values().iterator();
}
}
/** @see org.geotools.data.FeatureReader#getFeatureType() */
public T getFeatureType() {
return reader.getFeatureType();
}
/** @see org.geotools.data.FeatureReader#next() */
public F next() throws IOException, IllegalAttributeException, NoSuchElementException {
if (hasNext()) {
F live = next;
next = null;
return live;
}
throw new NoSuchElementException("No more Feature exists");
}
/** @see org.geotools.data.FeatureReader#hasNext() */
public boolean hasNext() throws IOException {
if (next != null) {
// We found it already
return true;
}
F peek;
if (filter == Filter.EXCLUDE) return false;
while ((reader != null) && reader.hasNext()) {
try {
peek = reader.next();
} catch (NoSuchElementException e) {
throw new DataSourceException("Could not aquire the next Feature", e);
} catch (IllegalAttributeException e) {
throw new DataSourceException("Could not aquire the next Feature", e);
}
String fid = peek.getIdentifier().getID();
encounteredFids.add(fid);
Map modified = diff.getModified();
if (modified.containsKey(fid)) {
F changed = (F) modified.get(fid);
if (changed == Diff.NULL || !filter.evaluate(changed)) {
continue;
} else {
next = changed;
return true;
}
} else {
next = peek; // found feature
return true;
}
}
queryDiff();
return next != null;
}
/** @see org.geotools.data.FeatureReader#close() */
public void close() throws IOException {
if (reader != null) {
reader.close();
reader = null;
}
if (diff != null) {
diff = null;
addedIterator = null;
}
}
protected void queryDiff() {
if (fidFilter) {
queryFidFilter();
} else if (indexedGeometryFilter) {
querySpatialIndex();
} else {
queryAdded();
queryModified();
}
}
protected void querySpatialIndex() {
while (spatialIndexIterator.hasNext() && next == null) {
F f = (F) spatialIndexIterator.next();
if (encounteredFids.contains(f.getIdentifier().getID()) || !filter.evaluate(f)) {
continue;
}
next = f;
}
}
protected void queryAdded() {
while (addedIterator.hasNext() && next == null) {
next = (F) addedIterator.next();
if (encounteredFids.contains(next.getIdentifier().getID()) || !filter.evaluate(next)) {
next = null;
}
}
}
protected void queryModified() {
while (modifiedIterator.hasNext() && next == null) {
next = (F) modifiedIterator.next();
if (next == Diff.NULL
|| encounteredFids.contains(next.getIdentifier().getID())
|| !filter.evaluate(next)) {
next = null;
}
}
}
protected void queryFidFilter() {
Id fidFilter = (Id) filter;
if (fids == null) {
fids = fidFilter.getIdentifiers().iterator();
}
while (fids.hasNext() && next == null) {
String fid = fids.next().toString();
if (!encounteredFids.contains(fid)) {
next = (F) diff.getModified().get(fid);
if (next == null) {
next = (F) diff.getAdded().get(fid);
}
}
}
}
protected List getIndexedFeatures() {
// TODO: check geom is default geom.
Envelope env = null;
env = extractBboxForSpatialIndexQuery((BinarySpatialOperator) filter);
return diff.queryIndex(env);
}
protected Envelope extractBboxForSpatialIndexQuery(BinarySpatialOperator filter) {
org.opengis.filter.expression.Expression leftGeom = filter.getExpression1();
org.opengis.filter.expression.Expression rightGeom = filter.getExpression2();
Object g;
if (leftGeom instanceof org.opengis.filter.expression.Literal) {
g = ((org.opengis.filter.expression.Literal) leftGeom).getValue();
} else {
g = ((org.opengis.filter.expression.Literal) rightGeom).getValue();
}
Envelope envelope = null;
if (g instanceof Geometry) {
envelope = ((Geometry) g).getEnvelopeInternal();
} else if (g instanceof Envelope) {
envelope = (Envelope) g;
}
return envelope;
}
protected boolean isDefaultGeometry(PropertyName ae) {
return reader.getFeatureType()
.getGeometryDescriptor()
.getLocalName()
.equals(ae.getPropertyName());
}
protected boolean isSubsetOfBboxFilter(Filter f) {
return filter instanceof Contains
|| filter instanceof Crosses
|| filter instanceof Overlaps
|| filter instanceof Touches
|| filter instanceof Within
|| filter instanceof BBOX;
}
}