/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2007-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.ogr;
import java.io.IOException;
import org.gdal.gdal.gdal;
import org.gdal.ogr.Layer;
import org.geotools.data.DataSourceException;
import org.geotools.data.DataUtilities;
import org.geotools.data.FeatureWriter;
import org.geotools.data.jdbc.MutableFIDFeature;
import org.geotools.feature.DefaultFeatureType;
import org.geotools.feature.Feature;
import org.geotools.feature.FeatureType;
import org.geotools.feature.IllegalAttributeException;
import com.vividsolutions.jts.geom.GeometryFactory;
/**
* OGR feature writer leveraging OGR capabilities to rewrite a file using random
* access and in place deletes
*
* @author aaime
*
* @source $URL$
*/
public class OGRDirectFeatureWriter implements FeatureWriter {
private OGRFeatureReader reader;
private FeatureType featureType;
private Feature original;
private MutableFIDFeature live;
private Layer layer;
private FeatureMapper mapper;
private boolean deletedFeatures;
/**
* Creates a new direct OGR feature writer, with the specified
* OGRFeatureReader and destination layer (it may be a different layer from
* the one the reader is working against)
*
* @param reader
* @param featureType
* @param layer
*/
public OGRDirectFeatureWriter(OGRFeatureReader reader) {
this.reader = reader;
this.featureType = reader.getFeatureType();
this.layer = reader.layer;
this.mapper = new FeatureMapper(new GeometryFactory());
this.deletedFeatures = false;
}
public void close() throws IOException {
if (reader != null) {
original = null;
live = null;
if("ESRI Shapefile".equals(reader.ds.GetDriver().getName()) && deletedFeatures)
reader.ds.ExecuteSQL("REPACK " + reader.layer.GetName(), null, null);
reader.layer.SyncToDisk();
reader.close();
}
}
public FeatureType getFeatureType() {
return featureType;
}
public boolean hasNext() throws IOException {
return reader.hasNext();
}
public Feature next() throws IOException {
if (live != null) {
write();
}
try {
if(reader.hasNext()) {
original = reader.next();
live = new MutableFIDFeature((DefaultFeatureType) original.getFeatureType(), original
.getAttributes(new Object[original.getFeatureType().getAttributeCount()]),
original.getID());
} else {
original = null;
live = new MutableFIDFeature((DefaultFeatureType) featureType,
DataUtilities.defaultValues(featureType), null);
}
return live;
} catch (IllegalAttributeException e) {
throw new DataSourceException("Could not build next feature", e);
}
}
public void remove() throws IOException {
int ogrId = mapper.convertGTFID(original);
if(layer.DeleteFeature(ogrId) != 0) {
throw new IOException(gdal.GetLastErrorMsg());
}
deletedFeatures = true;
}
public void write() throws IOException {
if (live == null)
throw new IOException("No current feature to write");
// this will return true only in update mode, otherwise original is null
boolean changed = live.equals(original);
if (!changed && original != null && layer == reader.layer) {
// nothing to do, just skip
} else if (changed && original != null && layer == reader.layer) {
// not equals, we're updating an existing one
layer.SetFeature(mapper.convertGTFeature(layer.GetLayerDefn(), live));
} else {
org.gdal.ogr.Feature ogrFeature = mapper.convertGTFeature(layer.GetLayerDefn(),
original != null ? original : live);
layer.CreateFeature(ogrFeature);
live.setID(mapper.convertOGRFID(featureType, ogrFeature));
ogrFeature.delete();
}
// reset state
live = null;
original = null;
}
}