/*
* 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 static org.bridj.Pointer.*;
import static org.geotools.data.ogr.OGRUtils.*;
import static org.geotools.data.ogr.bridj.CplErrorLibrary.*;
import static org.geotools.data.ogr.bridj.OgrLibrary.*;
import java.io.IOException;
import org.bridj.Pointer;
import org.geotools.data.FeatureReader;
import org.geotools.data.FeatureWriter;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.filter.identity.FeatureIdImpl;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import com.vividsolutions.jts.geom.GeometryFactory;
/**
* OGR feature writer leveraging OGR capabilities to rewrite a file using random access and in place
* deletes
*
* @author Andrea Aime - GeoSolutions
*/
class OGRDirectFeatureWriter implements FeatureWriter<SimpleFeatureType, SimpleFeature> {
private FeatureReader<SimpleFeatureType, SimpleFeature> reader;
private SimpleFeatureType featureType;
private SimpleFeature original;
private SimpleFeature live;
private Pointer layer;
private Pointer dataSource;
private FeatureMapper mapper;
private boolean deletedFeatures;
private Pointer layerDefinition;
/**
* Creates a new direct OGR feature writer
*
* @param reader
* @param featureType
* @param layer
*/
public OGRDirectFeatureWriter(Pointer<?> dataSource, Pointer<?> layer,
FeatureReader<SimpleFeatureType, SimpleFeature> reader,
SimpleFeatureType originalSchema, GeometryFactory gf) {
this.reader = reader;
this.featureType = reader.getFeatureType();
this.dataSource = dataSource;
this.layer = layer;
this.layerDefinition = OGR_L_GetLayerDefn(layer);
this.mapper = new FeatureMapper(featureType, layer, gf);
this.deletedFeatures = false;
}
public void close() throws IOException {
if (reader != null) {
original = null;
live = null;
Pointer<?> driver = OGR_DS_GetDriver(dataSource);
Pointer<Byte> driverName = OGR_Dr_GetName(driver);
if ("ESRI Shapefile".equals(getCString(driverName)) && deletedFeatures) {
String layerName = getLayerName(layer);
OGR_DS_ExecuteSQL(dataSource, pointerToCString("REPACK " + layerName), null, null);
}
OGR_L_SyncToDisk(layer);
reader.close();
}
}
public SimpleFeatureType getFeatureType() {
return featureType;
}
public boolean hasNext() throws IOException {
return reader.hasNext();
}
public SimpleFeature next() throws IOException {
if (live != null) {
write();
}
if (reader.hasNext()) {
original = reader.next();
live = SimpleFeatureBuilder.copy(original);
} else {
original = null;
live = SimpleFeatureBuilder.template(featureType, null);
}
return live;
}
public void remove() throws IOException {
long ogrId = mapper.convertGTFID(original);
if (OGR_L_DeleteFeature(layer, ogrId) != 0) {
throw new IOException(getCString(CPLGetLastErrorMsg()));
}
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) {
// nothing to do, just skip
} else if (original != null) {
// not equals, we're updating an existing one
Pointer ogrFeature = mapper.convertGTFeature(layerDefinition, live);
checkError(OGR_L_SetFeature(layer, ogrFeature));
} else {
Pointer ogrFeature = mapper.convertGTFeature(layerDefinition, live);
checkError(OGR_L_CreateFeature(layer, ogrFeature));
String geotoolsId = mapper.convertOGRFID(featureType, ogrFeature);
((FeatureIdImpl) live.getIdentifier()).setID(geotoolsId);
OGR_F_Destroy(ogrFeature);
}
// reset state
live = null;
original = null;
}
}