001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2002-2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.data.postgis.attributeio;
017:
018: import java.io.IOException;
019: import java.sql.PreparedStatement;
020: import java.sql.ResultSet;
021: import java.sql.SQLException;
022: import java.sql.Types;
023:
024: import org.geotools.data.DataSourceException;
025: import org.geotools.data.jdbc.attributeio.AttributeIO;
026: import org.geotools.factory.Hints;
027: import org.geotools.geometry.jts.LiteCoordinateSequenceFactory;
028:
029: import com.vividsolutions.jts.geom.CoordinateSequenceFactory;
030: import com.vividsolutions.jts.geom.DefaultCoordinateSequenceFactory;
031: import com.vividsolutions.jts.geom.Geometry;
032: import com.vividsolutions.jts.geom.GeometryFactory;
033: import com.vividsolutions.jts.geom.PrecisionModel;
034: import com.vividsolutions.jts.geom.impl.CoordinateArraySequenceFactory;
035: import com.vividsolutions.jts.io.WKBReader;
036: import com.vividsolutions.jts.io.WKBWriter;
037:
038: /**
039: * An attribute IO implementation that can manage the WKB
040: *
041: * @author Andrea Aime
042: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/plugin/postgis/src/main/java/org/geotools/data/postgis/attributeio/PgWKBAttributeIO.java $
043: */
044: public class PgWKBAttributeIO implements AttributeIO {
045: private boolean useByteArray;
046: private GeometryFactory gf;
047:
048: public PgWKBAttributeIO(boolean useByteArray) {
049: this .useByteArray = useByteArray;
050: }
051:
052: public PgWKBAttributeIO(boolean useByteArray, Hints hints) {
053: this .useByteArray = useByteArray;
054: // setup the geometry factory according to the hints
055: gf = (GeometryFactory) hints.get(Hints.JTS_GEOMETRY_FACTORY);
056: if (gf == null) {
057: PrecisionModel pm = (PrecisionModel) hints
058: .get(Hints.JTS_PRECISION_MODEL);
059: if (pm == null)
060: pm = new PrecisionModel();
061: Integer SRID = (Integer) hints.get(Hints.JTS_SRID);
062: int srid = SRID == null ? 0 : SRID.intValue();
063: CoordinateSequenceFactory csFactory = (CoordinateSequenceFactory) hints
064: .get(Hints.JTS_COORDINATE_SEQUENCE_FACTORY);
065: if (csFactory == null)
066: csFactory = CoordinateArraySequenceFactory.instance();
067: gf = new GeometryFactory(pm, srid, csFactory);
068: }
069: }
070:
071: /**
072: * Turns a char that encodes four bits in hexadecimal notation into a byte
073: *
074: * @param c
075: *
076: */
077: public static byte getFromChar(char c) {
078: if (c <= '9') {
079: return (byte) (c - '0');
080: } else if (c <= 'F') {
081: return (byte) (c - 'A' + 10);
082: } else {
083: return (byte) (c - 'a' + 10);
084: }
085: }
086:
087: /**
088: * This method will convert a String of hex characters that represent the
089: * hexadecimal form of a Geometry in Well Known Binary representation to a
090: * JTS Geometry object.
091: *
092: * @param wkb a String of hex characters where each character represents a
093: * hex value. In particular, each character is a value of 0-9, A, B
094: * ,C, D, E, or F.
095: *
096: * @return a JTS Geometry object that is equivalent to the WTB
097: * representation passed in by param wkb
098: *
099: * @throws IOException if more than one geometry object was found in the
100: * WTB representation, or if the parser could not parse the WKB
101: * representation.
102: */
103: private Geometry WKB2Geometry(byte[] wkbBytes) throws IOException {
104: // convert the byte[] to a JTS Geometry object
105:
106: if (wkbBytes == null) //DJB: null value from database --> null geometry (the same behavior as WKT). NOTE: sending back a GEOMETRYCOLLECTION(EMPTY) is also a possibility, but this is not the same as NULL
107: return null;
108: try {
109: WKBReader wkbr = new WKBReader(gf);
110: return wkbr.read(wkbBytes);
111: } catch (Exception e) {
112: throw new DataSourceException(
113: "An exception occurred while parsing WKB data", e);
114: }
115:
116: // JTSFactory factory = new JTSFactory();
117: // WKBParser parser = new WKBParser(factory);
118: // try {
119: // parser.parseData(wkbBytes, 42102);
120: // } catch (Exception e) {
121: // throw new DataSourceException("An exception occurred while parsing WKB data", e);
122: // }
123:
124: // ArrayList geoms = factory.getGeometries();
125: //
126: // if (geoms.size() > 0) {
127: // return (Geometry) geoms.get(0);
128: // } else if (geoms.size() > 1) {
129: // throw new IOException(
130: // "Found more than one Geometry in WKB representation ");
131: // } else {
132: // throw new IOException(
133: // "Could not parse WKB representations - found no Geometries ");
134: // }
135: }
136:
137: private byte[] hexToBytes(String wkb) {
138: // convert the String of hex values to a byte[]
139: byte[] wkbBytes = new byte[wkb.length() / 2];
140:
141: for (int i = 0; i < wkbBytes.length; i++) {
142: byte b1 = getFromChar(wkb.charAt(i * 2));
143: byte b2 = getFromChar(wkb.charAt((i * 2) + 1));
144: wkbBytes[i] = (byte) ((b1 << 4) | b2);
145: }
146:
147: return wkbBytes;
148: }
149:
150: /*
151: private byte[] byteaToBytes(byte[] bytes) {
152: for(int i = 0; i < bytes.length; i++) {
153: if(bytes[i] >= 'A')
154: bytes[i] -= ('A' + 10);
155: else
156: bytes[i] -= '0';
157: }
158: return bytes;
159: }
160: */
161: public void compare(byte[] b1, byte[] b2) {
162: int len = b2.length;
163: for (int t = 0; t < len; t++) {
164: if (b1[t] != b2[t])
165: System.out.println("differ at position " + t + "("
166: + b1[t] + " vs " + b2[t] + ")");
167: }
168: }
169:
170: /**
171: * @see org.geotools.data.jdbc.attributeio.AttributeIO#read(java.sql.ResultSet,
172: * int)
173: */
174: public Object read(ResultSet rs, int position) throws IOException {
175: try {
176: if (useByteArray) {
177: byte bytes[] = rs.getBytes(position);
178: // byte b[] = Base64.decode(bytes);
179: // byte b2[] = Base64.decode(bytes,0,bytes.length);
180: // compare(b,b2);
181: if (bytes == null) // ie. its a null column -> return a null geometry!
182: return null;
183: return WKB2Geometry(Base64.decode(bytes));
184: // return WKB2Geometry(bytes);
185: } else {
186: return WKB2Geometry(hexToBytes(rs.getString(position)));
187: }
188: } catch (SQLException e) {
189: throw new DataSourceException(
190: "SQL exception occurred while reading the geometry.",
191: e);
192: }
193: }
194:
195: /**
196: * @param metaData
197: * @throws SQLException
198: *
199: private void printMetadata(ResultSetMetaData md) throws SQLException {
200: for (int i = 1; i <= md.getColumnCount(); i++) {
201: System.out.println(i + " " + md.getColumnName(i) + " " + md.getColumnTypeName(i));
202: }
203:
204: }*/
205:
206: /**
207: * Unsupported, will throw an UnsupportedOperationException
208: * @see org.geotools.data.jdbc.attributeio.AttributeIO#write(java.sql.ResultSet,
209: * int, java.lang.Object)
210: */
211: public void write(ResultSet rs, int position, Object value)
212: throws IOException {
213: try {
214: if (value == null) {
215: rs.updateNull(position);
216: } else {
217: //rs.updateString(position, WKBEncoder.encodeGeometryHex((Geometry) value));
218: rs.updateBytes(position, new WKBWriter()
219: .write((Geometry) value));
220: }
221: } catch (SQLException e) {
222: throw new DataSourceException(
223: "SQL exception occurred while reading the geometry.",
224: e);
225: }
226: }
227:
228: /**
229: * @see org.geotools.data.jdbc.attributeio.AttributeIO#write(java.sql.PreparedStatement, int, java.lang.Object)
230: */
231: public void write(PreparedStatement ps, int position, Object value)
232: throws IOException {
233: try {
234: if (value == null) {
235: ps.setNull(position, Types.OTHER);
236: } else {
237: //ps.setString(position, WKBEncoder.encodeGeometryHex((Geometry) value));
238: ps.setBytes(position, new WKBWriter()
239: .write((Geometry) value));
240: }
241: } catch (SQLException e) {
242: throw new DataSourceException(
243: "SQL exception occurred while reading the geometry.",
244: e);
245: }
246:
247: }
248: }
|