package com.vividsolutions.jump.datastore.postgis; import java.sql.*; import java.io.*; import com.vividsolutions.jump.feature.*; import com.vividsolutions.jts.geom.*; import com.vividsolutions.jts.io.*; import org.postgresql.*; import com.vividsolutions.jump.datastore.*; import com.vividsolutions.jump.datastore.jdbc.*; /** * */ public class PostgisValueConverterFactory { // should lazily init these private final ValueConverter WKT_GEOMETRY_MAPPER = new WKTGeometryValueConverter(); private final ValueConverter WKB_GEOMETRY_MAPPER = new WKBGeometryValueConverter(); private final Connection conn; private final WKBReader wkbReader = new WKBReader(); private final WKTReader wktReader = new WKTReader(); public PostgisValueConverterFactory(Connection conn) { this.conn = conn; } public ValueConverter getConverter(ResultSetMetaData rsm, int columnIndex) throws SQLException { String classname = rsm.getColumnClassName(columnIndex); String dbTypeName = rsm.getColumnTypeName(columnIndex); // MD - this is slow - is there a better way? if (dbTypeName.equalsIgnoreCase("geometry")) // WKB is now the normal way to store geometry in PostGIS [mmichaud 2007-05-13] return WKB_GEOMETRY_MAPPER; if (dbTypeName.equalsIgnoreCase("bytea")) return WKB_GEOMETRY_MAPPER; // handle the standard types ValueConverter stdConverter = ValueConverterFactory.getConverter(rsm, columnIndex); if (stdConverter != null) return stdConverter; // default - can always show it as a string! return ValueConverterFactory.STRING_MAPPER; } class WKTGeometryValueConverter implements ValueConverter { public AttributeType getType() { return AttributeType.GEOMETRY; } public Object getValue(ResultSet rs, int columnIndex) throws IOException, SQLException, ParseException { Object valObj = rs.getObject(columnIndex); if (valObj == null) return wktReader.read("GEOMETRYCOLLECTION EMPTY"); else return wktReader.read(valObj.toString()); } } class WKBGeometryValueConverter implements ValueConverter { public AttributeType getType() { return AttributeType.GEOMETRY; } public Object getValue(ResultSet rs, int columnIndex) throws IOException, SQLException, ParseException { byte[] bytes = rs.getBytes(columnIndex); //so rs.getBytes will be one of two things: //1. The actual bytes of the WKB if someone did ST_AsBinary //2. The bytes of hex representation of the WKB. //in the case of #1, according to the WKB spec, the byte value //can only be 0 or 1. //in the case of #2, it's a hex string, so values range from ascii 0-F //use this logic to determine how to process the bytes. Geometry geometry = null; if(bytes == null || bytes.length <= 0) { geometry = wktReader.read("GEOMETRYCOLLECTION EMPTY"); } else { //assume it's the actual bytes (from ST_AsBinary) byte[] realWkbBytes = bytes; if(bytes[0] >= '0') { //ok, it's hex, convert hex string to actual bytes String hexString = new String(bytes); realWkbBytes = WKBReader.hexToBytes(hexString); } geometry = wkbReader.read(realWkbBytes); } return geometry; } } }