|
From: <svn...@os...> - 2012-01-15 17:56:09
|
Author: aaime
Date: 2012-01-15 09:55:59 -0800 (Sun, 15 Jan 2012)
New Revision: 38480
Modified:
branches/2.7.x/modules/unsupported/ogr/pom.xml
branches/2.7.x/modules/unsupported/ogr/src/main/java/org/geotools/data/ogr/FeatureMapper.java
branches/2.7.x/modules/unsupported/ogr/src/main/java/org/geotools/data/ogr/GeometryMapper.java
branches/2.7.x/modules/unsupported/ogr/src/main/java/org/geotools/data/ogr/OGRDataStore.java
branches/2.7.x/modules/unsupported/ogr/src/main/java/org/geotools/data/ogr/OGRDataStoreFactory.java
branches/2.7.x/modules/unsupported/ogr/src/main/java/org/geotools/data/ogr/OGRDirectFeatureWriter.java
branches/2.7.x/modules/unsupported/ogr/src/main/java/org/geotools/data/ogr/OGRFeatureReader.java
branches/2.7.x/modules/unsupported/ogr/src/main/java/org/geotools/data/ogr/OGRFeatureSource.java
branches/2.7.x/modules/unsupported/ogr/src/test/java/org/geotools/data/ogr/OGRDataStoreTest.java
Log:
[GEOT-3982] ogr - backport from trunk to branch 2.7.x in order to support createSchema(SimpleFeatureCollection, ...)
Modified: branches/2.7.x/modules/unsupported/ogr/pom.xml
===================================================================
--- branches/2.7.x/modules/unsupported/ogr/pom.xml 2012-01-12 07:30:49 UTC (rev 38479)
+++ branches/2.7.x/modules/unsupported/ogr/pom.xml 2012-01-15 17:55:59 UTC (rev 38480)
@@ -15,7 +15,7 @@
<parent>
<groupId>org.geotools</groupId>
- <artifactId>plugin</artifactId>
+ <artifactId>unsupported</artifactId>
<version>2.7-SNAPSHOT</version>
</parent>
@@ -48,6 +48,13 @@
</license>
</licenses>
+ <repositories>
+ <repository>
+ <id>nativelibs4java-repo</id>
+ <name>NativeLibs4Java Maven Repository</name>
+ <url>http://nativelibs4java.sourceforge.net/maven</url>
+ </repository>
+ </repositories>
<!-- =========================================================== -->
<!-- Developers and Contributors -->
@@ -72,9 +79,24 @@
<dependencies>
<dependency>
<groupId>org.geotools</groupId>
- <artifactId>gt-main</artifactId>
+ <artifactId>gt-data</artifactId>
<version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.nativelibs4java</groupId>
+ <artifactId>bridj</artifactId>
+ <classifier>c-only</classifier>
+ <version>0.6</version>
+
+ <exclusions>
+ <exclusion>
+ <groupId>com.nativelibs4java.thirdparty.com.google.android</groupId>
+ <artifactId>dx</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
+
<!-- Test dependencies -->
<dependency>
@@ -95,6 +117,30 @@
<version>${project.version}</version>
<scope>test</scope>
</dependency>
+
+ <dependency>
+ <groupId>org.geotools</groupId>
+ <artifactId>gt-jdbc</artifactId>
+ <version>2.7-SNAPSHOT</version>
+ </dependency>
</dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <systemProperties>
+ <property>
+ <name>java.library.path</name>
+ <value>${java.library.path}</value>
+ </property>
+ </systemProperties>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
</project>
Modified: branches/2.7.x/modules/unsupported/ogr/src/main/java/org/geotools/data/ogr/FeatureMapper.java
===================================================================
--- branches/2.7.x/modules/unsupported/ogr/src/main/java/org/geotools/data/ogr/FeatureMapper.java 2012-01-12 07:30:49 UTC (rev 38479)
+++ branches/2.7.x/modules/unsupported/ogr/src/main/java/org/geotools/data/ogr/FeatureMapper.java 2012-01-15 17:55:59 UTC (rev 38480)
@@ -16,15 +16,27 @@
*/
package org.geotools.data.ogr;
+import static org.bridj.Pointer.*;
+import static org.geotools.data.ogr.bridj.OgrLibrary.*;
+
import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
import java.text.DateFormat;
+import java.text.DecimalFormatSymbols;
import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.TimeZone;
-import org.gdal.ogr.FeatureDefn;
-import org.gdal.ogr.FieldDefn;
-import org.gdal.ogr.ogr;
+import org.bridj.Pointer;
import org.geotools.data.DataSourceException;
+import org.geotools.data.ogr.bridj.OgrLibrary.OGRFieldType;
import org.geotools.feature.simple.SimpleFeatureBuilder;
+import org.geotools.util.Converters;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
@@ -64,11 +76,31 @@
DateFormat timeFormat = new SimpleDateFormat("hh:mm:ss");
- public FeatureMapper(SimpleFeatureType schema, GeometryFactory geomFactory) {
- this.schema = schema;
+ HashMap<String, Integer> attributeIndexes;
+
+ /**
+ * TODO: this is subscepitble to changes to the Locale in Java that might not affect
+ * the C code... we should probably figure out a way to get the OS level locale?
+ */
+ static final DecimalFormatSymbols DECIMAL_SYMBOLS = new DecimalFormatSymbols();
+
+ public FeatureMapper(SimpleFeatureType targetSchema, Pointer layer, GeometryFactory geomFactory) {
+ this.schema = targetSchema;
this.builder = new SimpleFeatureBuilder(schema);
- this.geomMapper = new GeometryMapper(geomFactory);
+ this.geomMapper = new GeometryMapper.WKB(geomFactory);
this.geomFactory = geomFactory;
+
+ attributeIndexes = new HashMap<String, Integer>();
+ Pointer layerDefinition = OGR_L_GetLayerDefn(layer);
+ int size = OGR_FD_GetFieldCount(layerDefinition);
+ for(int i = 0; i < size; i++) {
+ Pointer field = OGR_FD_GetFieldDefn(layerDefinition, i);
+ Pointer<Byte> namePtr = OGR_Fld_GetNameRef(field);
+ String name = namePtr.getCString();
+ if(targetSchema.getDescriptor(name) != null) {
+ attributeIndexes.put(name, i);
+ }
+ }
}
/**
@@ -79,7 +111,7 @@
* @return
* @throws IOException
*/
- SimpleFeature convertOgrFeature(org.gdal.ogr.Feature ogrFeature)
+ SimpleFeature convertOgrFeature(Pointer<?> ogrFeature)
throws IOException {
// Extract all attributes (do not assume any specific order, the feature
// type may have been re-ordered by the Query)
@@ -89,16 +121,7 @@
// which extraction method to call
for (int i = 0; i < attributes.length; i++) {
AttributeDescriptor at = schema.getDescriptor(i);
- if (at instanceof GeometryDescriptor) {
- org.gdal.ogr.Geometry ogrGeometry = ogrFeature.GetGeometryRef();
- try {
- builder.add(fixGeometryType(geomMapper.parseOgrGeometry(ogrGeometry), at));
- } finally {
- ogrGeometry.delete();
- }
- } else {
- builder.add(getOgrField(at, ogrFeature));
- }
+ builder.add(getOgrField(at, ogrFeature));
}
// .. gather the FID
@@ -115,46 +138,73 @@
* @return
* @throws DataSourceException
*/
- org.gdal.ogr.Feature convertGTFeature(FeatureDefn ogrSchema, SimpleFeature feature)
+ Pointer convertGTFeature(Pointer featureDefinition, SimpleFeature feature)
throws IOException {
// create a new empty OGR feature
- org.gdal.ogr.Feature result = new org.gdal.ogr.Feature(ogrSchema);
+ Pointer ogrFeature = OGR_F_Create(featureDefinition);
// go thru GeoTools feature attributes, and convert
SimpleFeatureType schema = feature.getFeatureType();
for (int i = 0, j = 0; i < schema.getAttributeCount(); i++) {
- AttributeDescriptor at = schema.getDescriptor(i);
Object attribute = feature.getAttribute(i);
- if (at instanceof GeometryDescriptor) {
+ if (attribute instanceof Geometry) {
// using setGeoemtryDirectly the feature becomes the owner of the generated
// OGR geometry and we don't have to .delete() it (it's faster, too)
- result.SetGeometryDirectly(geomMapper.parseGTGeometry((Geometry) attribute));
- continue;
+ Pointer geometry = geomMapper.parseGTGeometry((Geometry) attribute);
+ OGR_F_SetGeometryDirectly(ogrFeature, geometry);
+ } else {
+ setFieldValue(featureDefinition, ogrFeature, j, attribute);
+ j++;
}
+ }
- if (attribute == null) {
- result.UnsetField(j);
+ return ogrFeature;
+ }
+
+ static void setFieldValue(Pointer featureDefinition, Pointer ogrFeature, int fieldIdx,
+ Object value) throws IOException {
+ if (value == null) {
+ OGR_F_UnsetField(ogrFeature, fieldIdx);
+ } else {
+ Pointer fieldDefinition = OGR_FD_GetFieldDefn(featureDefinition, fieldIdx);
+ long ogrType = OGR_Fld_GetType(fieldDefinition).value();
+ if (ogrType == OGRFieldType.OFTInteger.value()) {
+ OGR_F_SetFieldInteger(ogrFeature, fieldIdx, ((Number) value).intValue());
+ } else if (ogrType == OGRFieldType.OFTReal.value()) {
+ OGR_F_SetFieldDouble(ogrFeature, fieldIdx, ((Number) value).doubleValue());
+ } else if (ogrType == OGRFieldType.OFTBinary.value()) {
+ byte[] attValue = (byte[]) value;
+ OGR_F_SetFieldBinary(ogrFeature, fieldIdx, attValue.length, pointerToBytes(attValue));
+ } else if (ogrType == OGRFieldType.OFTDate.value()) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime((Date) value);
+ int year = cal.get(Calendar.YEAR);
+ int month = cal.get(Calendar.MONTH);
+ int day = cal.get(Calendar.DAY_OF_MONTH);
+ OGR_F_SetFieldDateTime(ogrFeature, fieldIdx, year, month, day, 0, 0, 0, 0);
+ } else if (ogrType == OGRFieldType.OFTTime.value()) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime((Date) value);
+ int hour = cal.get(Calendar.HOUR_OF_DAY);
+ int minute = cal.get(Calendar.MINUTE);
+ int second = cal.get(Calendar.SECOND);
+ OGR_F_SetFieldDateTime(ogrFeature, fieldIdx, 0, 0, 0, hour, minute, second, 0);
+ } else if (ogrType == OGRFieldType.OFTDateTime.value()) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime((Date) value);
+ int year = cal.get(Calendar.YEAR);
+ int month = cal.get(Calendar.MONTH);
+ int day = cal.get(Calendar.DAY_OF_MONTH);
+ int hour = cal.get(Calendar.HOUR_OF_DAY);
+ int minute = cal.get(Calendar.MINUTE);
+ int second = cal.get(Calendar.SECOND);
+ OGR_F_SetFieldDateTime(ogrFeature, fieldIdx, year, month, day, hour, minute, second, 0);
} else {
- final FieldDefn ogrField = ogrSchema.GetFieldDefn(j);
- final int ogrType = ogrField.GetFieldType();
- ogrField.delete();
- if (ogrType == ogr.OFTInteger)
- result.SetField(j, ((Number) attribute).intValue());
- else if (ogrType == ogr.OFTReal)
- result.SetField(j, ((Number) attribute).doubleValue());
- else if (ogrType == ogr.OFTDateTime)
- result.SetField(j, dateTimeFormat.format((java.util.Date) attribute));
- else if (ogrType == ogr.OFTDate)
- result.SetField(j, dateFormat.format((java.util.Date) attribute));
- else if (ogrType == ogr.OFTTime)
- result.SetField(j, timeFormat.format((java.util.Date) attribute));
- else
- result.SetField(j, attribute.toString());
+ // anything else we treat as a string
+ String str = Converters.convert(value, String.class);
+ OGR_F_SetFieldString(ogrFeature, fieldIdx, pointerToCString(str));
}
- j++;
}
-
- return result;
}
/**
@@ -191,41 +241,65 @@
* @param ad
* @return
*/
- Object getOgrField(AttributeDescriptor ad, org.gdal.ogr.Feature ogrFeature) throws IOException {
- String name = ad.getLocalName();
- Class clazz = ad.getType().getBinding();
+ Object getOgrField(AttributeDescriptor ad, Pointer<?> ogrFeature) throws IOException {
+ if(ad instanceof GeometryDescriptor) {
+ // gets the geometry as a reference, we don't own it, we should not deallocate it
+ Pointer<?> ogrGeometry = OGR_F_GetGeometryRef(ogrFeature);
+ return fixGeometryType(geomMapper.parseOgrGeometry(ogrGeometry), ad);
+ }
+
+ Integer idx = attributeIndexes.get(ad.getLocalName());
// check for null fields
- if (!ogrFeature.IsFieldSet(name))
+ if (idx == null || OGR_F_IsFieldSet(ogrFeature, idx) == 0) {
return null;
+ }
// hum, ok try and parse it
+ Class clazz = ad.getType().getBinding();
if (clazz.equals(String.class)) {
- return ogrFeature.GetFieldAsString(name);
+ return OGR_F_GetFieldAsString(ogrFeature, idx).getCString();
+ } else if (clazz.equals(Byte.class)) {
+ return (byte) OGR_F_GetFieldAsInteger(ogrFeature, idx);
+ } else if (clazz.equals(Short.class)) {
+ return (short) OGR_F_GetFieldAsInteger(ogrFeature, idx);
} else if (clazz.equals(Integer.class)) {
- return new Integer(ogrFeature.GetFieldAsInteger(name));
+ return OGR_F_GetFieldAsInteger(ogrFeature, idx);
+ } else if (clazz.equals(Long.class)) {
+ String value = OGR_F_GetFieldAsString(ogrFeature, idx).getCString();
+ return new Long(value);
+ } else if (clazz.equals(BigInteger.class)) {
+ String value = OGR_F_GetFieldAsString(ogrFeature, idx).getCString();
+ return new BigInteger(value);
} else if (clazz.equals(Double.class)) {
- return new Double(ogrFeature.GetFieldAsDouble(name));
+ return OGR_F_GetFieldAsDouble(ogrFeature, idx);
} else if (clazz.equals(Float.class)) {
- return new Float(ogrFeature.GetFieldAsDouble(name));
- } else if (clazz.equals(Integer.class)) {
- return new Integer(ogrFeature.GetFieldAsInteger(name));
+ return (float) OGR_F_GetFieldAsDouble(ogrFeature, idx);
+ } else if (clazz.equals(BigDecimal.class)) {
+ String value = OGR_F_GetFieldAsString(ogrFeature, idx).getCString().trim();
+ char separator = DECIMAL_SYMBOLS.getDecimalSeparator();
+ if(separator != '.') {
+ value = value.replace(separator, '.');
+ }
+ return new BigDecimal(value);
+ } else if (clazz.equals(java.sql.Date.class)) {
+ Calendar cal = getDateField(ogrFeature, idx);
+ cal.clear(Calendar.HOUR_OF_DAY);
+ cal.clear(Calendar.MINUTE);
+ cal.clear(Calendar.SECOND);
+ return new java.sql.Date(cal.getTimeInMillis());
+ } else if (clazz.equals(java.sql.Time.class)) {
+ Calendar cal = getDateField(ogrFeature, idx);
+ cal.clear(Calendar.YEAR);
+ cal.clear(Calendar.MONTH);
+ cal.clear(Calendar.DAY_OF_MONTH);
+ return new java.sql.Time(cal.getTimeInMillis());
+ } else if (clazz.equals(java.sql.Timestamp.class)) {
+ Calendar cal = getDateField(ogrFeature, idx);
+ return new java.sql.Time(cal.getTimeInMillis());
} else if (clazz.equals(java.util.Date.class)) {
- String date = ogrFeature.GetFieldAsString(name);
- if (date == null || date.trim().equals(""))
- return null;
- int ogrType = ogrFeature.GetFieldType(name);
- try {
- if (ogrType == ogr.OFTDateTime)
- return dateTimeFormat.parse(date);
- else if (ogrType == ogr.OFTDate)
- return dateFormat.parse(date);
- else if (ogrType == ogr.OFTTime)
- return timeFormat.parse(date);
- } catch (java.text.ParseException e) {
- throw new DataSourceException("Could not parse date value", e);
- }
- throw new IOException("Date attribute, but field type is not compatible: " + ogrType);
+ Calendar cal = getDateField(ogrFeature, idx);
+ return cal.getTime();
} else {
throw new IllegalArgumentException("Don't know how to read " + clazz.getName()
+ " fields");
@@ -233,14 +307,56 @@
}
/**
+ * Reads a date field from the OGR api
+ * @param ogrFeature
+ * @param idx
+ * @return
+ */
+ private Calendar getDateField(Pointer<?> ogrFeature, Integer idx) {
+ Pointer<Integer> year = allocateInt();
+ Pointer<Integer> month = allocateInt();
+ Pointer<Integer> day = allocateInt();
+ Pointer<Integer> hour = allocateInt();
+ Pointer<Integer> minute = allocateInt();
+ Pointer<Integer> second = allocateInt();
+ Pointer<Integer> timeZone = allocateInt();
+
+ OGR_F_GetFieldAsDateTime(ogrFeature, idx, year, month, day, hour, minute, second, timeZone);
+
+ Calendar cal = Calendar.getInstance();
+ // from ogr_core.h
+ // 0=unknown, 1=localtime(ambiguous), 100=GMT, 104=GMT+1, 80=GMT-5, etc
+ int tz = timeZone.getInt();
+ if(tz != 0 && tz != 1) {
+ int offset = tz - 100 / 4;
+ if(offset < 0) {
+ cal.setTimeZone(TimeZone.getTimeZone("GMT" + offset));
+ } else if(offset == 0) {
+ cal.setTimeZone(TimeZone.getTimeZone("GMT"));
+ } else {
+ cal.setTimeZone(TimeZone.getTimeZone("GMT+" + offset));
+ }
+ }
+ cal.clear();
+ cal.set(Calendar.YEAR, year.getInt());
+ cal.set(Calendar.MONTH, month.getInt());
+ cal.set(Calendar.DAY_OF_MONTH, day.getInt());
+ cal.set(Calendar.HOUR_OF_DAY, hour.getInt());
+ cal.set(Calendar.MINUTE, minute.getInt());
+ cal.set(Calendar.SECOND, second.getInt());
+ return cal;
+ }
+
+ /**
* Generates a GT2 feature id given its feature type and an OGR feature
*
* @param schema
* @param ogrFeature
* @return
*/
- String convertOGRFID(SimpleFeatureType schema, org.gdal.ogr.Feature ogrFeature) {
- return schema.getTypeName() + "." + ogrFeature.GetFID();
+ String convertOGRFID(SimpleFeatureType schema, Pointer<?> ogrFeature) {
+ long id = OGR_F_GetFID(ogrFeature);
+ return schema.getTypeName() + "." + id;
}
/**
@@ -249,9 +365,9 @@
* @param feature
* @return
*/
- int convertGTFID(SimpleFeature feature) {
+ long convertGTFID(SimpleFeature feature) {
String id = feature.getID();
- return Integer.parseInt(id.substring(id.indexOf(".") + 1));
+ return Long.parseLong(id.substring(id.indexOf(".") + 1));
}
}
Modified: branches/2.7.x/modules/unsupported/ogr/src/main/java/org/geotools/data/ogr/GeometryMapper.java
===================================================================
--- branches/2.7.x/modules/unsupported/ogr/src/main/java/org/geotools/data/ogr/GeometryMapper.java 2012-01-12 07:30:49 UTC (rev 38479)
+++ branches/2.7.x/modules/unsupported/ogr/src/main/java/org/geotools/data/ogr/GeometryMapper.java 2012-01-15 17:55:59 UTC (rev 38480)
@@ -16,10 +16,14 @@
*/
package org.geotools.data.ogr;
+import static org.bridj.Pointer.*;
+import static org.geotools.data.ogr.OGRUtils.*;
+import static org.geotools.data.ogr.bridj.OgrLibrary.*;
+
import java.io.IOException;
-import org.gdal.ogr.ogr;
-import org.geotools.data.DataSourceException;
+import org.bridj.Pointer;
+import org.geotools.data.ogr.bridj.OgrLibrary.OGRwkbByteOrder;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
@@ -31,99 +35,99 @@
/**
* Converts between JTS and OGR geometries
- * @author Andrea Aime - OpenGeo
- *
- * @source $URL: http://svn.osgeo.org/geotools/branches/2.7.x/build/maven/javadoc/../../../modules/unsupported/ogr/src/main/java/org/geotools/data/ogr/GeometryMapper.java $
+ *
+ * @author Andrea Aime - GeoSolutions
+ *
+ *
+ * @source $URL:
+ * http://svn.osgeo.org/geotools/trunk/modules/unsupported/ogr/src/main/java/org/geotools
+ * /data/ogr/GeometryMapper.java $
*/
-public class GeometryMapper {
- /**
- * From ogr_core.h, the byte order constants
- */
- static final int WKB_XDR = 1;
+@SuppressWarnings("rawtypes")
+abstract class GeometryMapper {
- /**
- * Enables usage of WKB encoding for OGR/Java Geometry conversion. At the time of writing, it
- * cannot be used because it'll bring the virtual machine down (yes, a real crash...)
- */
- static final boolean USE_WKB = true;
+ abstract Geometry parseOgrGeometry(Pointer geom) throws IOException;
- GeometryFactory geomFactory;
+ abstract Pointer parseGTGeometry(Geometry geometry) throws IOException;
- WKBReader wkbReader;
+ static class WKB extends GeometryMapper {
+ GeometryFactory geomFactory;
- WKTReader wktReader;
+ WKBReader wkbReader;
- WKBWriter wkbWriter;
+ WKBWriter wkbWriter;
- WKTWriter wktWriter;
-
- public GeometryMapper(GeometryFactory geomFactory) {
- this.geomFactory = geomFactory;
- if (USE_WKB) {
+ public WKB(GeometryFactory geomFactory) {
+ this.geomFactory = geomFactory;
this.wkbReader = new WKBReader(geomFactory);
this.wkbWriter = new WKBWriter();
- } else {
- this.wktReader = new WKTReader(geomFactory);
- this.wktWriter = new WKTWriter();
}
- }
-
- /**
- * Reads the current feature's geometry using wkb encoding. A wkbReader should be provided since
- * it's not thread safe by design.
- *
- * @throws IOException
- */
- Geometry parseOgrGeometry(org.gdal.ogr.Geometry geom) throws IOException {
- // Extract the geometry using either WKT or WKB. Rationale: the SWIG
- // bindings do not provide subclasses. Even if they did, going thru the
- // JNI barrier often is expensive, so it's better to gather the geometry
- // is a single call
- if (USE_WKB) {
- int wkbSize = geom.WkbSize();
- // the gdal interface uses a char* type, maybe because in C it's
- // unsigned and has
- // the same size as a byte, unfortunately this means we have to
- // unpack it
- // to byte format by doing bit masking and shifting
- byte[] byteBuffer = new byte[wkbSize];
- geom.ExportToWkb(byteBuffer, WKB_XDR);
+ /**
+ * Reads the current feature's geometry using wkb encoding. A wkbReader should be provided
+ * since it's not thread safe by design.
+ *
+ * @throws IOException
+ */
+ Geometry parseOgrGeometry(Pointer geom) throws IOException {
+ int wkbSize = OGR_G_WkbSize(geom);
+ Pointer<Byte> ptrBytes = pointerToBytes(new byte[wkbSize]);
+ checkError(OGR_G_ExportToWkb(geom, OGRwkbByteOrder.wkbXDR, ptrBytes));
try {
- Geometry g = wkbReader.read(byteBuffer);
+ byte[] wkb = ptrBytes.getBytes();
+ Geometry g = wkbReader.read(wkb);
return g;
} catch (ParseException pe) {
- throw new RuntimeException(
- "Could not parse the current Geometry in WKB format.", pe);
+ throw (IOException) new IOException("Could not parse the current Geometry in WKB format.").initCause(pe);
}
- } else {
- String[] stringArray = new String[1];
- geom.ExportToWkt(stringArray);
+ }
+
+ Pointer parseGTGeometry(Geometry geometry) throws IOException {
+ byte[] wkb = wkbWriter.write(geometry);
+ Pointer<Pointer<?>> ptr = allocatePointer();
+ checkError(OGR_G_CreateFromWkb(pointerToBytes(wkb), null, ptr, wkb.length));
+ return ptr.getPointer(Pointer.class);
+ }
+
+ }
+
+ static class WKT extends GeometryMapper {
+ GeometryFactory geomFactory;
+
+ WKTReader wktReader;
+
+ WKTWriter wktWriter;
+
+ public WKT(GeometryFactory geomFactory) {
+ this.geomFactory = geomFactory;
+ this.wktReader = new WKTReader(geomFactory);
+ this.wktWriter = new WKTWriter();
+ }
+
+ /**
+ * Reads the current feature's geometry using wkb encoding. A wkbReader should be provided
+ * since it's not thread safe by design.
+ *
+ * @throws IOException
+ */
+ Geometry parseOgrGeometry(Pointer geom) throws IOException {
+ Pointer<Pointer<Byte>> wktPtr = allocatePointer(Byte.class);
+ checkError(OGR_G_ExportToWkt(geom, wktPtr));
try {
- return wktReader.read(stringArray[0]);
+ String wkt = wktPtr.getPointer(Byte.class).getCString();
+ return wktReader.read(wkt);
} catch (ParseException pe) {
- throw new RuntimeException(
- "Could not parse the current Geometry in WKB format.", pe);
+ throw (IOException) new IOException("Could not parse the current Geometry in WKT format.").initCause(pe);
}
}
- }
- org.gdal.ogr.Geometry parseGTGeometry(Geometry geometry) throws RuntimeException {
- final org.gdal.ogr.Geometry ogrGeom;
- if (USE_WKB) {
- byte[] wkb = wkbWriter.write(geometry);
- ogrGeom = ogr.CreateGeometryFromWkb(wkb, null);
- if (ogrGeom == null)
- throw new RuntimeException(
- "Could not turn JTS geometry into an OGR one thought WKB");
- } else {
+ Pointer parseGTGeometry(Geometry geometry) throws IOException {
String wkt = wktWriter.write(geometry);
- ogrGeom = ogr.CreateGeometryFromWkt(wkt, null);
- if (ogrGeom == null)
- throw new RuntimeException(
- "Could not turn JTS geometry into an OGR one thought WKT");
+ Pointer<Pointer<Byte>> ptr = pointerToPointer(pointerToCString(wkt));
+ Pointer<Pointer<?>> geom = allocatePointer();
+ checkError(OGR_G_CreateFromWkt(ptr, null, geom));
+ return geom.getPointer(Pointer.class);
}
- return ogrGeom;
+
}
-
}
Modified: branches/2.7.x/modules/unsupported/ogr/src/main/java/org/geotools/data/ogr/OGRDataStore.java
===================================================================
--- branches/2.7.x/modules/unsupported/ogr/src/main/java/org/geotools/data/ogr/OGRDataStore.java 2012-01-12 07:30:49 UTC (rev 38479)
+++ branches/2.7.x/modules/unsupported/ogr/src/main/java/org/geotools/data/ogr/OGRDataStore.java 2012-01-15 17:55:59 UTC (rev 38480)
@@ -16,428 +16,156 @@
*/
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 java.io.StringWriter;
-import java.math.BigDecimal;
-import java.math.BigInteger;
import java.net.URI;
-import java.util.Arrays;
-import java.util.Vector;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
-import org.gdal.gdal.gdal;
-import org.gdal.ogr.DataSource;
-import org.gdal.ogr.Driver;
-import org.gdal.ogr.FeatureDefn;
-import org.gdal.ogr.FieldDefn;
-import org.gdal.ogr.Layer;
-import org.gdal.ogr.ogr;
-import org.gdal.osr.SpatialReference;
-import org.geotools.data.AbstractDataStore;
+import org.bridj.Pointer;
+import org.bridj.ValuedEnum;
import org.geotools.data.DataSourceException;
-import org.geotools.data.FeatureReader;
-import org.geotools.data.FeatureWriter;
import org.geotools.data.Query;
-import org.geotools.data.Transaction;
-import org.geotools.data.jdbc.FilterToSQL;
-import org.geotools.factory.FactoryRegistryException;
-import org.geotools.feature.AttributeTypeBuilder;
-import org.geotools.feature.FeatureTypes;
-import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
-import org.geotools.feature.type.BasicFeatureTypes;
-import org.geotools.filter.FilterCapabilities;
-import org.geotools.filter.visitor.PostPreProcessFilterSplittingVisitor;
-import org.geotools.geometry.jts.ReferencedEnvelope;
-import org.geotools.referencing.CRS;
-import org.geotools.resources.Classes;
+import org.geotools.data.ogr.bridj.OgrLibrary.OGRwkbGeometryType;
+import org.geotools.data.simple.SimpleFeatureCollection;
+import org.geotools.data.simple.SimpleFeatureIterator;
+import org.geotools.data.store.ContentDataStore;
+import org.geotools.data.store.ContentEntry;
+import org.geotools.data.store.ContentFeatureSource;
+import org.geotools.feature.NameImpl;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.feature.type.GeometryDescriptor;
-import org.opengis.feature.type.GeometryType;
-import org.opengis.filter.And;
-import org.opengis.filter.Filter;
-import org.opengis.filter.Or;
-import org.opengis.filter.PropertyIsEqualTo;
-import org.opengis.filter.PropertyIsGreaterThan;
-import org.opengis.filter.PropertyIsGreaterThanOrEqualTo;
-import org.opengis.filter.PropertyIsLessThan;
-import org.opengis.filter.PropertyIsLessThanOrEqualTo;
-import org.opengis.filter.PropertyIsNotEqualTo;
-import org.opengis.filter.expression.Expression;
-import org.opengis.filter.expression.Literal;
-import org.opengis.filter.expression.PropertyName;
-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.Equals;
-import org.opengis.filter.spatial.Intersects;
-import org.opengis.filter.spatial.Overlaps;
-import org.opengis.filter.spatial.Touches;
-import org.opengis.filter.spatial.Within;
-import org.opengis.referencing.FactoryException;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.feature.type.Name;
import com.vividsolutions.jts.geom.Geometry;
-import com.vividsolutions.jts.geom.GeometryCollection;
-import com.vividsolutions.jts.geom.LineString;
-import com.vividsolutions.jts.geom.MultiLineString;
-import com.vividsolutions.jts.geom.MultiPoint;
-import com.vividsolutions.jts.geom.MultiPolygon;
-import com.vividsolutions.jts.geom.Point;
-import com.vividsolutions.jts.geom.Polygon;
+import com.vividsolutions.jts.geom.GeometryFactory;
/**
- * A datastore based on the the <a href="http://www.gdal.org/ogr">OGR</a> spatial data abstraction
- * library
+ * A data store based on the OGR native library, bound to it via <a
+ * href="http://code.google.com/p/bridj/">BridJ</a>
*
- * @author Andrea Aime - OpenGeo
- *
- *
- * @source $URL$
- * http://svn.osgeo.org/geotools/trunk/modules/unsupported/ogr/src/main/java/org/geotools
- * /data/ogr/OGRDataStore.java $
+ * @author Andrea Aime - GeoSolutions
*/
-public class OGRDataStore extends AbstractDataStore {
- /** C compatible FALSE */
- static final int FALSE = 0;
+@SuppressWarnings("rawtypes")
+public class OGRDataStore extends ContentDataStore {
- /** C compatible TRUE */
- static final int TRUE = 1;
-
- static final FilterCapabilities ATTRIBUTE_FILTER_CAPABILITIES;
-
- static final FilterCapabilities GEOMETRY_FILTER_CAPABILITIES;
-
static {
- ATTRIBUTE_FILTER_CAPABILITIES = new FilterCapabilities();
- ATTRIBUTE_FILTER_CAPABILITIES.addType(PropertyIsEqualTo.class);
- ATTRIBUTE_FILTER_CAPABILITIES.addType(PropertyIsNotEqualTo.class);
- ATTRIBUTE_FILTER_CAPABILITIES.addType(PropertyIsGreaterThan.class);
- ATTRIBUTE_FILTER_CAPABILITIES.addType(PropertyIsLessThan.class);
- ATTRIBUTE_FILTER_CAPABILITIES.addType(PropertyIsGreaterThanOrEqualTo.class);
- ATTRIBUTE_FILTER_CAPABILITIES.addType(PropertyIsLessThanOrEqualTo.class);
- ATTRIBUTE_FILTER_CAPABILITIES.addType(Or.class);
- ATTRIBUTE_FILTER_CAPABILITIES.addType(And.class);
+ GdalInit.init();
- // have the capabilities extract any filter that can use geometric intersection
- // as its base
- GEOMETRY_FILTER_CAPABILITIES = new FilterCapabilities();
- GEOMETRY_FILTER_CAPABILITIES.addType(BBOX.class);
- GEOMETRY_FILTER_CAPABILITIES.addType(Contains.class);
- GEOMETRY_FILTER_CAPABILITIES.addType(Crosses.class);
- GEOMETRY_FILTER_CAPABILITIES.addType(Equals.class);
- GEOMETRY_FILTER_CAPABILITIES.addType(Intersects.class);
- GEOMETRY_FILTER_CAPABILITIES.addType(Overlaps.class);
- GEOMETRY_FILTER_CAPABILITIES.addType(Touches.class);
- GEOMETRY_FILTER_CAPABILITIES.addType(Within.class);
- }
-
- /**
- * The OGRwkbGeometryType enum from ogr_core.h, reduced to represent only 2D classes (I hope the
- * 2.5D will be handled transparently by JTS)
- */
- static final Class[] OGR_GEOM_TYPES = new Class[] { //
- Geometry.class, // wkbUnknown = 0
- Point.class, // wkbPoint = 1
- MultiLineString.class, // wkbLineString = 2,
- MultiPolygon.class, // wkbPolygon = 3,
- MultiPoint.class, // wkbMultiPoint = 4,
- MultiLineString.class, // wkbMultiLineString = 5,
- MultiPolygon.class, // wkbMultiPolygon = 6,
- GeometryCollection.class, // wkbGeometryCollection = 7
- };
-
- /**
- * The source name that OGR should open and handle
- */
- private String ogrSourceName;
-
- /**
- * Datastore namespace
- */
- private URI namespace;
-
- /**
- * OGR driver to be used for the creation of new data sources
- */
- private String ogrDriverName;
-
- static {
// perform OGR format registration once
- if (ogr.GetDriverCount() == 0)
- ogr.RegisterAll();
+ if (OGRGetDriverCount() == 0) {
+ OGRRegisterAll();
+ }
}
- /**
- * Creates a new OGRDataStore
- *
- * @param ogrSourceName
- * a references to the source that needs to be opened. May be a file system path, or
- * a database reference. See the OGR driver documentation for valid formats of this
- * string.
- */
+ String ogrSourceName;
- public OGRDataStore(String ogrSourceName, String ogrDriverName, URI namespace)
- throws IOException {
- this.ogrSourceName = ogrSourceName;
- this.ogrDriverName = ogrDriverName;
- this.namespace = (namespace != null) ? namespace : FeatureTypes.DEFAULT_NAMESPACE;
- int update = FALSE;
- if (ogrDriverName == null) {
- DataSource ds = getOGRDataSource(update);
- ds.delete();
+ String ogrDriver;
+
+ public OGRDataStore(String ogrName, String ogrDriver, URI namespace) {
+ if (namespace != null) {
+ setNamespaceURI(namespace.toString());
}
+ this.ogrSourceName = ogrName;
+ this.ogrDriver = ogrDriver;
}
-
+
@Override
- protected FeatureReader<SimpleFeatureType, SimpleFeature> getFeatureReader(String typeName)
- throws IOException {
- return getFeatureReader(typeName, Query.ALL, false);
- }
+ protected List<Name> createTypeNames() throws IOException {
+ Pointer dataSource = null;
+ Pointer layer = null;
+ try {
+ dataSource = openOGRDataSource(false);
- protected FeatureReader<SimpleFeatureType, SimpleFeature> getFeatureReader(String typeName,
- Query query) throws IOException {
- return getFeatureReader(typeName, query, false);
- }
-
- protected FeatureReader<SimpleFeatureType, SimpleFeature> getFeatureReader(String typeName,
- Query query, boolean openForUpdate)
- throws IOException {
- DataSource ds = getOGRDataSource(openForUpdate ? TRUE : FALSE);
- Layer layer = getOGRLayer(ds, typeName);
-
- // handle filtering if possible
- SimpleFeatureType schema = getSchema(typeName);
- Filter filter = query.getFilter();
- org.gdal.ogr.Geometry spatialFilter = getSpatialFilter(schema, filter);
- if(spatialFilter != null)
- layer.SetSpatialFilter(spatialFilter);
- String attributeFilter = getAttributeFilter(schema, filter);
- if(attributeFilter != null)
- layer.SetAttributeFilter(attributeFilter);
-
- return new OGRFeatureReader(ds, layer, schema);
- }
-
- /**
- * Parses the Geotools filter and tries to extract an intersecting geometry that
- * can be used as the OGR spatial filter
- * @param schema
- * @param filter
- * @return
- */
- protected org.gdal.ogr.Geometry getSpatialFilter(SimpleFeatureType schema, Filter filter) {
- // TODO: switch to the non deprecated splitter (that no one seems to be using)
- PostPreProcessFilterSplittingVisitor visitor = new PostPreProcessFilterSplittingVisitor(GEOMETRY_FILTER_CAPABILITIES, schema, null);
- filter.accept(visitor, null);
- Filter preFilter = visitor.getFilterPre();
- if(preFilter instanceof BinarySpatialOperator) {
- BinarySpatialOperator bso = ((BinarySpatialOperator) preFilter);
- Expression geomExpression = null;
- if(bso.getExpression1() instanceof PropertyName && bso.getExpression2() instanceof Literal) {
- geomExpression = bso.getExpression2();
- } else if(bso.getExpression1() instanceof Literal && bso.getExpression2() instanceof PropertyName) {
- geomExpression = bso.getExpression1();
+ List<Name> result = new ArrayList<Name>();
+ int count = OGR_DS_GetLayerCount(dataSource);
+ for (int i = 0; i < count; i++) {
+ layer = OGR_DS_GetLayer(dataSource, i);
+ String name = getLayerName(layer);
+ if (name != null) {
+ result.add(new NameImpl(getNamespaceURI(), name));
+ }
+ OGRUtils.releaseLayer(layer);
}
- if(geomExpression != null) {
- Geometry geom = geomExpression.evaluate(null, Geometry.class);
- if(geom != null)
- return new GeometryMapper(geom.getFactory()).parseGTGeometry(geom);
- }
+ return result;
+ } catch (IOException e) {
+ return Collections.emptyList();
+ } finally {
+ OGRUtils.releaseDataSource(dataSource);
+ OGRUtils.releaseLayer(layer);
}
- return null;
}
-
- /**
- * Parses the GeoTools filter and tries to extract an SQL expression that can
- * be used as the OGR attribute filter
- * @param schema
- * @param filter
- * @return
- */
- protected String getAttributeFilter(SimpleFeatureType schema, Filter filter) {
- // TODO: switch to the non deprecated splitter (that no one seems to be using)
- PostPreProcessFilterSplittingVisitor visitor = new PostPreProcessFilterSplittingVisitor(ATTRIBUTE_FILTER_CAPABILITIES, schema, null);
- filter.accept(visitor, null);
- Filter preFilter = visitor.getFilterPre();
- if(preFilter != Filter.EXCLUDE && preFilter != Filter.INCLUDE) {
- StringWriter writer = new StringWriter();
- FilterToSQL sqlConverter = new FilterToSQL(writer);
- preFilter.accept(sqlConverter, null);
- return writer.getBuffer().toString();
- }
- return null;
- }
- public SimpleFeatureType getSchema(String typeName) throws IOException {
- DataSource ds = getOGRDataSource(FALSE);
- Layer layer = getOGRLayer(ds, typeName);
- if (layer == null) {
- ds.delete();
- throw new IOException("No such type : " + typeName);
- }
- FeatureDefn featureDef = null;
- try {
- featureDef = layer.GetLayerDefn();
-
- SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
- AttributeTypeBuilder abuilder = new AttributeTypeBuilder();
- builder.setName(typeName);
- builder.setNamespaceURI(namespace);
-
- // handle the geometry
- CoordinateReferenceSystem crs = getCRS(layer);
- Class geomClass = getGeometryClass(featureDef.GetGeomType());
- abuilder.setName(Classes.getShortName( geomClass ));
- abuilder.setNillable(true);
- abuilder.setCRS(crs);
- abuilder.setBinding(geomClass);
- GeometryType geometryType = abuilder.buildGeometryType();
- builder.add(abuilder.buildDescriptor(
- BasicFeatureTypes.GEOMETRY_ATTRIBUTE_NAME, geometryType));
-
-// builder.add("the_geom", geomClass, crs);
-
- // compute a default parent feature type
- if ((geomClass == Point.class) || (geomClass == MultiPoint.class)) {
- builder.setSuperType(BasicFeatureTypes.POINT);
- } else if ((geomClass == Polygon.class) || (geomClass == MultiPolygon.class)) {
- builder.setSuperType(BasicFeatureTypes.POLYGON);
- } else if ((geomClass == LineString.class) || (geomClass == MultiLineString.class)) {
- builder.setSuperType(BasicFeatureTypes.LINE);
+ Pointer openOGRDataSource(boolean update) throws IOException {
+ Pointer ds = null;
+ Pointer<Byte> sourcePtr = pointerToCString(ogrSourceName);
+ int mode = update ? 1 : 0;
+ if (ogrDriver != null) {
+ Pointer driver = OGRGetDriverByName(pointerToCString(ogrDriver));
+ if (driver == null) {
+ throw new IOException("Could not find a driver named " + driver);
}
-
- // handle the other fields
- for (int i = 1; i < featureDef.GetFieldCount() + 1; i++) {
- FieldDefn fd = featureDef.GetFieldDefn(i - 1);
- builder.length(fd.GetWidth());
- builder.add(fd.GetNameRef(), getFieldClass(fd));
- fd.delete();
+ ds = OGR_Dr_Open(driver, sourcePtr, mode);
+ if (ds == null) {
+ throw new IOException("OGR could not open '" + ogrSourceName + "' in "
+ + (update ? "read-write" : "read-only") + " mode with driver " + ogrDriver);
}
-
- // finally build the geometry type
- return builder.buildFeatureType();
- } catch (FactoryException e) {
- throw new DataSourceException("Could not determine geometry SRS", e);
- } catch (FactoryRegistryException e) {
- throw new DataSourceException("Could not create feature type", e);
- } finally {
- if (featureDef != null)
- featureDef.delete();
- if (layer != null)
- layer.delete();
- if (ds != null)
- ds.delete();
+ } else {
+ ds = OGROpenShared(sourcePtr, mode, null);
+ if (ds == null) {
+ throw new IOException("OGR could not open '" + ogrSourceName + "' in "
+ + (update ? "read-write" : "read-only") + " mode");
+ }
}
+ return ds;
}
- public String[] getTypeNames() throws IOException {
- DataSource ds;
- try {
- ds = getOGRDataSource(FALSE);
- } catch (IOException e) {
- return new String[0];
+ Pointer openOGRLayer(Pointer dataSource, String layerName) throws IOException {
+ Pointer layer = OGR_DS_GetLayerByName(dataSource, pointerToCString(layerName));
+ if (layer == null) {
+ throw new IOException("OGR could not find layer '" + layerName + "'");
}
- String[] typeNames = new String[ds.GetLayerCount()];
- for (int i = 0; i < typeNames.length; i++) {
- Layer l = ds.GetLayerByIndex(i);
- typeNames[i] = l.GetName();
- l.delete();
- }
- ds.delete();
- return typeNames;
+ return layer;
}
- protected int getCount(Query query) throws IOException {
- if (!Filter.INCLUDE.equals(query.getFilter()))
- return -1;
-
- DataSource ds = getOGRDataSource(FALSE);
- Layer l = getOGRLayer(ds, query.getTypeName());
- if (l == null)
- throw new IOException("Unknown feature type: " + query.getTypeName());
-
- // go for the quick computation, return -1 otherwise
- int count = l.GetFeatureCount(FALSE);
- l.delete();
- ds.delete();
- return count;
- }
-
- protected FeatureWriter createFeatureWriter(String typeName, Transaction transaction)
- throws IOException {
- if (supportsInPlaceWrite(typeName)) {
- OGRFeatureReader reader = (OGRFeatureReader) getFeatureReader(typeName, Query.ALL, true);
- return new OGRDirectFeatureWriter(reader);
+ @Override
+ protected ContentFeatureSource createFeatureSource(ContentEntry entry) throws IOException {
+ if (supportsInPlaceWrite(entry.getTypeName())) {
+ return new OGRFeatureStore(entry, Query.ALL);
} else {
- throw new UnsupportedOperationException(
- "This file format does not support in place write, "
- + "can't perform updates/deletes");
+ return new OGRFeatureSource(entry, Query.ALL);
}
}
public boolean supportsInPlaceWrite(String typeName) throws IOException {
- // if it's not able to open the datasource in update mode, there's no
- // change it'll be able to support in place write (no need to throw an
- // exception in
- // this case, thus the direct call instead of getOGRDataSource())
- DataSource ds = ogr.OpenShared(ogrSourceName, TRUE);
- if (ds == null)
- return false;
- Layer l = getOGRLayer(ds, typeName);
- boolean retval = l.TestCapability(ogr.OLCDeleteFeature)
- && l.TestCapability(ogr.OLCRandomWrite) && l.TestCapability(ogr.OLCSequentialWrite);
- l.delete();
- ds.delete();
- return retval;
- }
-
- // given up on this one. Some drivers tell you that you can write on a layer
- // only if you opened in update mode. We could try to create a new data
- // source,
- // but unfortunately there is no way to have a generic ogr name that works
- // for every data store. Finally, not all drivers that do write do support
- // datastore deletion. So, in the end, either we can update directly an OGR
- // datasource content, or we have to create a new one and roll our own
- // mechanism to have it replace the old one (this includes moving and
- // deleting
- // the elements that make up a data store).
- public boolean supportsWriteNewLayer(String typeName) throws IOException {
- DataSource ds = getOGRDataSource(FALSE);
- Layer l = getOGRLayer(ds, typeName);
- boolean retval = ds.TestCapability(ogr.ODsCCreateLayer)
- && l.TestCapability(ogr.OLCSequentialWrite);
- l.delete();
- ds.delete();
- return retval;
- }
-
- public ReferencedEnvelope getBounds(Query q) throws IOException {
- if (!q.getFilter().equals(Filter.INCLUDE))
- return null;
-
- DataSource ds = getOGRDataSource(OGRDataStore.FALSE);
- Layer l = getOGRLayer(ds, q.getTypeName());
+ Pointer ds = null;
+ Pointer l = null;
try {
- if (l.TestCapability(ogr.OLCFastGetExtent)) {
- double[] bbox = new double[4];
- // TODO: hum... going thru this forcing the computation is anyways
- // faster than loading all the features just for the sake of
- // getting out the bbox.... but we don't have this
- // explicit middle ground in Geotools
- l.GetExtent(bbox, OGRDataStore.FALSE);
- CoordinateReferenceSystem crs = getSchema(q.getTypeName()).getCoordinateReferenceSystem();
- return new ReferencedEnvelope(bbox[0], bbox[1], bbox[2], bbox[3], crs);
- } else {
- return null;
+ // try opening in update mode
+ ds = OGROpen(pointerToCString(ogrSourceName), 1, null);
+ if (ds == null) {
+ return false;
}
+ l = openOGRLayer(ds, typeName);
+ // for the moment we support working only with random writers
+ boolean canDelete = OGR_L_TestCapability(l, pointerToCString(OLCDeleteFeature)) != 0;
+ boolean canWriteRandom = OGR_L_TestCapability(l, pointerToCString(OLCRandomWrite)) != 0;
+ boolean canWriteSequential = OGR_L_TestCapability(l,
+ pointerToCString(OLCSequentialWrite)) != 0;
+ return canDelete && canWriteRandom && canWriteSequential;
} finally {
- if(l != null)
- l.delete();
- if(ds != null)
- ds.delete();
+ OGRUtils.releaseLayer(l);
+ OGRUtils.releaseDataSource(ds);
}
}
@@ -449,60 +177,33 @@
/**
* Creates a new OGR layer with provided schema and options
*
- * @param schema
- * the geotools schema
- * @param approximateFields
- * if true, OGR will try to create fields that are approximations of the required
- * ones when an exact match cannt be provided
- * @param options
- * OGR data source/layer creation options
+ * @param schema the geotools schema
+ * @param approximateFields if true, OGR will try to create fields that are approximations of
+ * the required ones when an exact match cannt be provided
+ * @param options OGR data source/layer creation options
* @throws IOException
*/
public void createSchema(SimpleFeatureType schema, boolean approximateFields, String[] options)
throws IOException {
- DataSource ds = null;
- Layer l = null;
+ Pointer dataSource = null;
+ Pointer layer = null;
try {
// either open datasource, or try creating one
- Vector optVector = options != null ? new Vector(Arrays.asList(options)) : null;
- try {
- ds = getOGRDataSource(TRUE);
- } catch (IOException e) {
- if (ogrDriverName != null) {
- Driver d = ogr.GetDriverByName(ogrDriverName);
- ds = d.CreateDataSource(ogrSourceName, optVector);
- d.delete();
-
- if (ds == null)
- throw new IOException("Could not create OGR data source with driver "
- + ogrDriverName + " and options " + optVector);
- } else {
- throw new DataSourceException("Driver not provided, and could not "
- + "open data source neither");
- }
+ Pointer<Pointer<Byte>> optionsPointer = null;
+ if (options != null && options.length > 0) {
+ optionsPointer = pointerToCStrings(options);
}
+ dataSource = openOrCreateDataSource(options, dataSource, optionsPointer);
- // get the spatial reference corresponding to the default geometry
- GeometryDescriptor geomType = schema.getGeometryDescriptor();
- int ogrGeomType = getOGRGeometryType(geomType);
- SpatialReference sr = null;
- if (geomType.getCoordinateReferenceSystem() != null) {
- // use tostring to get a lenient wkt translation
- String wkt = geomType.getCoordinateReferenceSystem().toString();
- sr = new SpatialReference(null);
- if (sr.ImportFromWkt(wkt) != 0) {
- sr = null;
- LOGGER.warning("OGR could not parse the geometry WKT," + " detailed error is: "
- + gdal.GetLastErrorMsg() + "\n" + "WKT was: " + wkt);
- }
- }
+ FeatureTypeMapper mapper = new FeatureTypeMapper();
- // create the layer
- l = ds.CreateLayer(schema.getTypeName(), sr, ogrGeomType, optVector);
- if (l == null) {
- throw new DataSourceException("Could not create the OGR layer: "
- + gdal.GetLastErrorMsg());
+ layer = createNewLayer(schema, dataSource, optionsPointer, mapper);
+
+ // check the ability to create fields
+ if (OGR_L_TestCapability(layer, pointerToCString(OLCCreateField)) == 0) {
+ throw new DataSourceException(
+ "OGR reports it's not possible to create fields on this layer");
}
// create fields
@@ -511,211 +212,166 @@
if (ad == schema.getGeometryDescriptor())
continue;
- FieldDefn definition = getOGRFieldDefinition(ad);
- l.CreateField(definition, approximateFields ? TRUE : FALSE);
+ Pointer fieldDefinition = mapper.getOGRFieldDefinition(ad);
+ OGR_L_CreateField(layer, fieldDefinition, approximateFields ? 1 : 0);
}
+
+ OGR_L_SyncToDisk(layer);
} finally {
- if (l != null) {
- l.delete();
- }
- if (ds != null)
- ds.delete();
+ OGRUtils.releaseLayer(layer);
+ OGRUtils.releaseDataSource(dataSource);
}
}
- // ---------------------------------------------------------------------------------------
- // PRIVATE SUPPORT METHODS
- // ---------------------------------------------------------------------------------------
-
- private FieldDefn getOGRFieldDefinition(AttributeDescriptor at) throws IOException {
- final Class type = at.getType().getBinding();
- final FieldDefn def;
- // set type, width, precision and justification where:
- // * width is the number of chars needed to format the strings
- // equivalent of
- // the number
- // * precision is the number of chars after decimal pont
- // * justification: right or left (in outputs)
- // TODO: steal code from Shapefile data store to guess eventual size
- // limitations
- if (Boolean.class.equals(type)) {
- def = new FieldDefn(at.getLocalName(), ogr.OFTString);
- def.SetWidth(5);
- } else if (Byte.class.equals(type)) {
- def = new FieldDefn(at.getLocalName(), ogr.OFTInteger);
- def.SetWidth(3);
- def.SetJustify(ogr.OJRight);
- } else if (Short.class.equals(type)) {
- def = new FieldDefn(at.getLocalName(), ogr.OFTInteger);
- def.SetWidth(5);
- def.SetJustify(ogr.OJRight);
- } else if (Integer.class.equals(type)) {
- def = new FieldDefn(at.getLocalName(), ogr.OFTInteger);
- def.SetWidth(9);
- def.SetJustify(ogr.OJRight);
- } else if (Long.class.equals(type)) {
- def = new FieldDefn(at.getLocalName(), ogr.OFTInteger);
- def.SetWidth(19);
- def.SetJustify(ogr.OJRight);
- } else if (BigInteger.class.equals(type)) {
- def = new FieldDefn(at.getLocalName(), ogr.OFTInteger);
- def.SetWidth(32);
- def.SetJustify(ogr.OJRight);
- } else if (BigDecimal.class.equals(type)) {
- def = new FieldDefn(at.getLocalName(), ogr.OFTReal);
- def.SetWidth(32);
- def.SetPrecision(15);
- def.SetJustify(ogr.OJRight);
- } else if (Float.class.equals(type)) {
- def = new FieldDefn(at.getLocalName(), ogr.OFTReal);
- def.SetWidth(12);
- def.SetPrecision(7);
- def.SetJustify(ogr.OJRight);
- } else if (Double.class.equals(type) || Number.class.isAssignableFrom(type)) {
- def = new FieldDefn(at.getLocalName(), ogr.OFTReal);
- def.SetWidth(22);
- def.SetPrecision(16);
- def.SetJustify(ogr.OJRight);
- } else if (String.class.equals(type)) {
- def = new FieldDefn(at.getLocalName(), ogr.OFTString);
- def.SetWidth(255);
- // TODO: do a serious attempt to cover blob and clob too
- } else if (byte[].class.equals(type)) {
- def = new FieldDefn(at.getLocalName(), ogr.OFTBinary);
- // } else if (java.sql.Date.class.isAssignableFrom(type)) {
- // def = new FieldDefn(at.getLocalName(), ogr.OFTDate);
- // } else if (java.sql.Time.class.isAssignableFrom(type)) {
- // def = new FieldDefn(at.getLocalName(), ogr.OFTTime);
- } else if (java.util.Date.class.isAssignableFrom(type)) {
- def = new FieldDefn(at.getLocalName(), ogr.OFTDateTime);
- } else {
- throw new IOException("Cannot map " + type + " to an OGR type");
- }
-
- return def;
- }
-
/**
- * Tries to open the specified source in either read only or read/write mode
+ * Creates a new OGR layer with provided data and options. This call is specifically made
+ * available for the OGC store since for some data source types, such as GML or KML, it is not
+ * possible to call createSchema() independently from a write, as the result will not contain
+ * the schema definition without having data too. Also, in those formats, the output is writable
+ * only so as long as it's empty, it's not possible to write against an existing GML file for
+ * example.
*
- * @param update
- * open read/write if TRUE, otherwise open read only
- *
- * @return
+ * @param schema the geotools schema
+ * @param approximateFields if true, OGR will try to create fields that are approximations of
+ * the required ones when an exact match cannt be provided
+ * @param options OGR data source/layer creation options
* @throws IOException
*/
- DataSource getOGRDataSource(int update) throws IOException {
- DataSource ds = ogr.OpenShared(ogrSourceName, update);
- if (ds == null)
- throw new IOException("OGR could not open '" + ogrSourceName + "'");
- return ds;
- }
+ public void createSchema(SimpleFeatureCollection data, boolean approximateFields,
+ String[] options) throws IOException {
+ Pointer dataSource = null;
+ Pointer layer = null;
+ SimpleFeatureType schema = data.getSchema();
+ SimpleFeatureIterator features;
+ try {
+ // either open datasource, or try creating one
+ Pointer<Pointer<Byte>> optionsPointer = null;
+ if (options != null && options.length > 0) {
+ optionsPointer = pointer...
[truncated message content] |