From b31e88f14407d5321a7adb1dd62c9bbac24d0515 Mon Sep 17 00:00:00 2001 From: ?? ? <ulysseskao@ximple.com.tw> Date: Fri, 13 Jun 2008 15:46:03 +0800 Subject: [PATCH] update for EOFM-117 createSchemaTexts and createNewSchemaTexts --- xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsGeometry.java | 187 ++++ xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsWrapper.java | 180 ++++ xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsBinaryWriter.java | 469 +++++++++++ xdgnjobs/ximple-jobcarrier/src/main/resources/log4j.properties | 2 .gitattributes | 6 xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ComplexChainElement.java | 43 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JTSShape.java | 339 ++++++++ xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateLineStringStrategy.java | 2 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/IndexDgnConvertPostGISJobContext.java | 92 + xdgnjobs/ximple-jobcarrier/src/main/resources/quartz_jobs.xml | 4 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/GeneralDgnConvertMySQLJobContext.java | 16 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/AbstractOracleToPostGISJobContext.java | 23 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/FeatureTypeBuilderUtil.java | 68 + xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsGisWrapper.java | 173 ++++ xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsBinaryParser.java | 287 +++++++ xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/GeneralDgnConvertPostGISJobContext.java | 109 + xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateLineTextStrategy.java | 2 xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/AbstractDgnToPostGISJobContext.java | 352 ++++++++ 18 files changed, 2,197 insertions(+), 157 deletions(-) diff --git a/.gitattributes b/.gitattributes index 304111a..b80d943 100644 --- a/.gitattributes +++ b/.gitattributes @@ -122,6 +122,12 @@ xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TPCLIDConverter.java svneol=native#text/plain xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TWD97GeometryConverterDecorator.java svneol=native#text/plain xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/TWDDatumConverter.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JTSShape.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsBinaryParser.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsBinaryWriter.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsGeometry.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsGisWrapper.java svneol=native#text/plain +xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsWrapper.java svneol=native#text/plain xdgnjobs/ximple-spatialjob/src/main/resources/com/ximple/eofms/filter/ElementDispatcherRules.xml svneol=native#text/xml xdgnjobs/ximple-spatialjob/src/main/resources/com/ximple/eofms/filter/FeatureClassificationRules.xml svneol=native#text/xml xdgnjobs/ximple-spatialjob/src/main/resources/conf/ConvertShpFilterForLayer.xml svneol=native#text/xml diff --git a/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ComplexChainElement.java b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ComplexChainElement.java index 001f83a..363de3c 100644 --- a/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ComplexChainElement.java +++ b/xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/ComplexChainElement.java @@ -11,6 +11,8 @@ import com.vividsolutions.jts.geom.CoordinateList; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.MultiLineString; +import com.vividsolutions.jts.geom.LineString; /** * ComplexChainElement @@ -148,36 +150,8 @@ public Geometry toGeometry(GeometryFactory factory) { - if (size() == 1) - { - Element element = (Element) get(0); + ArrayList<LineString> lineStrings = new ArrayList<LineString>(); - if (element instanceof LineStringElement) - { - if (((LineStringElement) element).getVerticeSize() == 0 || ((LineStringElement) element).getVerticeSize() > 1) - { - return ((LineStringElement) element).toGeometry(factory); - } - - } else if (element instanceof LineElement) - { - if (((LineElement) element).getVertices().length == 0 || ((LineElement) element).getVertices().length > 1) - { - return ((LineElement) element).toGeometry(factory); - } - - } else - { - if (element instanceof GeometryConverter) - { - return ((GeometryConverter) element).toGeometry(factory); - } - - return null; - } - } - - CoordinateList pts = new CoordinateList(); for (ListIterator it = listIterator(); it.hasNext();) { Element element = (Element) it.next(); @@ -186,7 +160,7 @@ { if (((LineStringElement) element).getVerticeSize() == 0 || ((LineStringElement) element).getVerticeSize() > 1) { - pts.add(((LineStringElement) element).toGeometry(factory).getCoordinates(), true); + lineStrings.add((LineString) ((LineStringElement) element).toGeometry(factory)); } } else if (element instanceof LineElement) @@ -194,15 +168,18 @@ if (((LineElement) element).getVertices().length == 0 || ((LineElement) element).getVertices().length > 1) { - pts.add(((LineElement) element).toGeometry(factory).getCoordinates(), true); + lineStrings.add((LineString) ((LineElement) element).toGeometry(factory)); } } else if (element instanceof ArcElement) { - pts.add(((ArcElement) element).toGeometry(factory).getCoordinates(), true); + lineStrings.add((LineString) ((ArcElement) element).toGeometry(factory)); } } - return factory.createLineString(pts.toCoordinateArray()); + LineString[] lines = lineStrings.toArray(new LineString[lineStrings.size()]); + if ((lines == null) || (lines.length == 0)) + return null; + return factory.createMultiLineString(lines); } public double getElementSize() diff --git a/xdgnjobs/ximple-jobcarrier/src/main/resources/log4j.properties b/xdgnjobs/ximple-jobcarrier/src/main/resources/log4j.properties index e7c6650..2691982 100644 --- a/xdgnjobs/ximple-jobcarrier/src/main/resources/log4j.properties +++ b/xdgnjobs/ximple-jobcarrier/src/main/resources/log4j.properties @@ -25,4 +25,4 @@ # Print messages of level INFO or above for examples log4j.logger.org.cavaness.quartzbook=INFO -log4j.logger.com.ximple.eofms=DEBUG \ No newline at end of file +log4j.logger.com.ximple.eofms=INFO \ No newline at end of file diff --git a/xdgnjobs/ximple-jobcarrier/src/main/resources/quartz_jobs.xml b/xdgnjobs/ximple-jobcarrier/src/main/resources/quartz_jobs.xml index 1bd55fc..76ea5f6 100644 --- a/xdgnjobs/ximple-jobcarrier/src/main/resources/quartz_jobs.xml +++ b/xdgnjobs/ximple-jobcarrier/src/main/resources/quartz_jobs.xml @@ -76,7 +76,7 @@ </entry> <entry> <key>CONVERTDB</key> - <value>true</value> + <value>false</value> </entry> <entry> <key>CONVERTFILE</key> @@ -108,7 +108,7 @@ </entry> <entry> <key>COPYCONNECTIVITYMODE</key> - <value>true</value> + <value>false</value> </entry> </job-data-map> </job-detail> diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateLineStringStrategy.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateLineStringStrategy.java index ae666a3..881cfc0 100644 --- a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateLineStringStrategy.java +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateLineStringStrategy.java @@ -60,7 +60,7 @@ { if (!typeBuilders.containsKey(featureName)) { - FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createLineStringFeatureTypeBuilder(featureName); + FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createLineFeatureTypeBuilder(featureName); typeBuilders.put(featureName, typeBuilder); fireFeatureTypeEvent(new FeatureTypeEvent(this, typeBuilder.getFeatureType())); } diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateLineTextStrategy.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateLineTextStrategy.java index b8095bc..d4fae84 100644 --- a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateLineTextStrategy.java +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/filter/CreateLineTextStrategy.java @@ -63,7 +63,7 @@ { if (!typeBuilders.containsKey(featureName)) { - FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createLineStringFeatureTypeBuilder(featureName); + FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createLineFeatureTypeBuilder(featureName); typeBuilders.put(featureName, typeBuilder); fireFeatureTypeEvent(new FeatureTypeEvent(this, typeBuilder.getFeatureType())); } diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/GeneralDgnConvertMySQLJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/GeneralDgnConvertMySQLJobContext.java index 7e3e342..de90663 100644 --- a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/GeneralDgnConvertMySQLJobContext.java +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/mysql/GeneralDgnConvertMySQLJobContext.java @@ -417,7 +417,7 @@ String typeName; if (element instanceof TextElement) { - typeName = getFeatureBaseName() + "P"; + typeName = getFeatureBaseName() + "_P"; if (!featureTypes.containsKey(typeName)) { featureTypes.put(typeName, createPointFeatureElement(typeName)); @@ -425,7 +425,7 @@ return featureTypes.get(typeName); } else if (element instanceof TextNodeElement) { - typeName = getFeatureBaseName() + "P"; + typeName = getFeatureBaseName() + "_P"; if (!featureTypes.containsKey(typeName)) { featureTypes.put(typeName, createPointFeatureElement(typeName)); @@ -435,7 +435,7 @@ { if (element instanceof ShapeElement) { - typeName = getFeatureBaseName() + "R"; + typeName = getFeatureBaseName() + "_R"; if (!featureTypes.containsKey(typeName)) { featureTypes.put(typeName, createLineFeatureElement(typeName)); @@ -443,7 +443,7 @@ return featureTypes.get(typeName); } else { - typeName = getFeatureBaseName() + "L"; + typeName = getFeatureBaseName() + "_L"; if (!featureTypes.containsKey(typeName)) { featureTypes.put(typeName, createLineFeatureElement(typeName)); @@ -452,7 +452,7 @@ } } else if (element instanceof LineElement) { - typeName = getFeatureBaseName() + "L"; + typeName = getFeatureBaseName() + "_L"; if (!featureTypes.containsKey(typeName)) { featureTypes.put(typeName, createLineFeatureElement(typeName)); @@ -460,7 +460,7 @@ return featureTypes.get(typeName); } else if (element instanceof ComplexChainElement) { - typeName = getFeatureBaseName() + "L"; + typeName = getFeatureBaseName() + "_ML"; if (!featureTypes.containsKey(typeName)) { featureTypes.put(typeName, createLineFeatureElement(typeName)); @@ -468,7 +468,7 @@ return featureTypes.get(typeName); } else if (element instanceof ArcElement) { - typeName = getFeatureBaseName() + "A"; + typeName = getFeatureBaseName() + "_A"; if (!featureTypes.containsKey(typeName)) { featureTypes.put(typeName, createArcFeatureElement(typeName)); @@ -476,7 +476,7 @@ return featureTypes.get(typeName); } else if (element instanceof EllipseElement) { - typeName = getFeatureBaseName() + "R"; + typeName = getFeatureBaseName() + "_R"; if (!featureTypes.containsKey(typeName)) { featureTypes.put(typeName, createEllipseFeatureElement(typeName)); diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/AbstractDgnToPostGISJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/AbstractDgnToPostGISJobContext.java index 983a897..93a0b8b 100644 --- a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/AbstractDgnToPostGISJobContext.java +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/AbstractDgnToPostGISJobContext.java @@ -4,6 +4,7 @@ import java.math.BigDecimal; import java.sql.Connection; import java.sql.DatabaseMetaData; +import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; @@ -44,28 +45,31 @@ import com.vividsolutions.jts.io.WKTWriter; import com.ximple.eofms.jobs.context.AbstractDgnFileJobContext; +import com.ximple.eofms.util.postjts.JtsBinaryWriter; public abstract class AbstractDgnToPostGISJobContext extends AbstractDgnFileJobContext { private static Map<String, Class> GEOM_TYPE_MAP = new HashMap<String, Class>(); + private static Map<String, Class> GEOM3D_TYPE_MAP = new HashMap<String, Class>(); static { GEOM_TYPE_MAP.put("GEOMETRY", Geometry.class); GEOM_TYPE_MAP.put("POINT", Point.class); - GEOM_TYPE_MAP.put("POINTM", Point.class); GEOM_TYPE_MAP.put("LINESTRING", LineString.class); - GEOM_TYPE_MAP.put("LINESTRINGM", LineString.class); GEOM_TYPE_MAP.put("POLYGON", Polygon.class); - GEOM_TYPE_MAP.put("POLYGONM", Polygon.class); GEOM_TYPE_MAP.put("MULTIPOINT", MultiPoint.class); - GEOM_TYPE_MAP.put("MULTIPOINTM", MultiPoint.class); GEOM_TYPE_MAP.put("MULTILINESTRING", MultiLineString.class); - GEOM_TYPE_MAP.put("MULTILINESTRINGM", MultiLineString.class); GEOM_TYPE_MAP.put("MULTIPOLYGON", MultiPolygon.class); - GEOM_TYPE_MAP.put("MULTIPOLYGONM", MultiPolygon.class); GEOM_TYPE_MAP.put("GEOMETRYCOLLECTION", GeometryCollection.class); - GEOM_TYPE_MAP.put("GEOMETRYCOLLECTIONM", GeometryCollection.class); + + GEOM3D_TYPE_MAP.put("POINTM", Point.class); + GEOM3D_TYPE_MAP.put("LINESTRINGM", LineString.class); + GEOM3D_TYPE_MAP.put("POLYGONM", Polygon.class); + GEOM3D_TYPE_MAP.put("MULTIPOINTM", MultiPoint.class); + GEOM3D_TYPE_MAP.put("MULTILINESTRINGM", MultiLineString.class); + GEOM3D_TYPE_MAP.put("MULTIPOLYGONM", MultiPolygon.class); + GEOM3D_TYPE_MAP.put("GEOMETRYCOLLECTIONM", GeometryCollection.class); } private static Map<Class, String> CLASS_MAPPINGS = new HashMap<Class, String>(); @@ -112,12 +116,14 @@ */ private static final int MAX_ALLOWED_VALUE = 10485760; - protected static final int BATCHSIZE = 25; + // protected static final int BATCHSIZE = 2048; + protected static final int BATCHSIZE = 256; /** * Well Known Text writer (from JTS). */ protected static WKTWriter geometryWriter = new WKTWriter(); + protected static JtsBinaryWriter binaryWriter = new JtsBinaryWriter(); protected PostgisDataStore targetDataStore; private Connection connection; @@ -228,6 +234,46 @@ conn.commit(); } + protected String dropGeometryColumn(String dbSchema, String tableName, String geomField) + { + StringBuilder sb = new StringBuilder(); + sb.append("SELECT DropGeometryColumn('"); + sb.append(dbSchema); + sb.append("','"); + sb.append(tableName); + sb.append("','"); + sb.append(geomField); + sb.append("')"); + getLogger().info("Execute-" + sb.toString()); + return sb.toString(); + } + + private String addGeometryColumn(String dbSchema, String tableName, GeometryAttributeType geometryAttribute, int srid) + { + StringBuilder sql; + String typeName = getGeometrySQLTypeName(geometryAttribute.getBinding()); + if (typeName == null) + { + getLogger().warn("Error: " + geometryAttribute.getLocalName() + " unknown type!!!"); + throw new RuntimeException("Error: " + geometryAttribute.getLocalName() + " unknown type!!!"); + } + + sql = new StringBuilder("SELECT AddGeometryColumn('"); + sql.append(dbSchema); + sql.append("','"); + sql.append(tableName); + sql.append("','"); + sql.append(geometryAttribute.getLocalName()); + sql.append("','"); + sql.append(srid); + sql.append("','"); + sql.append(typeName); + sql.append("', 2);"); + + //prints statement for later reuse + return sql.toString(); + } + public ArrayList<String> createSchemaTexts(FeatureType featureType) throws IOException { String tableName = featureType.getTypeName(); @@ -246,7 +292,7 @@ { StringBuffer sql = new StringBuffer("CREATE TABLE "); sql.append(encodeSchemaTableName(tableName)); - sql.append(" ("); + sql.append(" ( gid serial PRIMARY KEY, "); sql.append(makeSqlCreate(attributeType)); sql.append(");"); @@ -406,6 +452,7 @@ result.add(sqlStr); } + /* if (!typeName.equals("GEOMETRY")) { sql = new StringBuffer("ALTER TABLE "); @@ -426,7 +473,7 @@ result.add(sqlStr); } } - + */ } else { getLogger().warn("Error: " + geomAttribute.getLocalName() + " unknown type!!!"); @@ -476,6 +523,103 @@ if (!shouldExecute) { throw new IOException("The table " + tableName + " already exists."); + } + + return result; + } + + public ArrayList<String> createNewSchemaTexts(FeatureType featureType) throws IOException + { + String origintableName = featureType.getTypeName(); + String tableName = origintableName.toLowerCase(); + + ArrayList<String> result = new ArrayList<String>(); + + AttributeType[] attributeType = featureType.getAttributeTypes(); + // String dbSchema = targetDataStore.getDatabaseSchemaName(); + + Connection con = getConnection(); + + boolean shouldDrop = tablePresent(tableName, con); + if (shouldDrop) + { + String sqlStr = "DROP TABLE " + encodeSchemaTableName(tableName) + ";"; + getLogger().info(sqlStr); + result.add(sqlStr); + } + + StringBuffer sql = new StringBuffer("CREATE TABLE "); + sql.append(encodeSchemaTableName(tableName)); + sql.append(" ( gid serial PRIMARY KEY, "); + sql.append(makeNonGeomSqlCreate(attributeType)); + sql.append(");"); + + String sqlStr = sql.toString(); + getLogger().info(sqlStr); + result.add(sqlStr); + + for (AttributeType anAttributeType : attributeType) + { + if (!(anAttributeType instanceof GeometryAttributeType)) + { + continue; + } + GeometryAttributeType geomAttribute = (GeometryAttributeType) anAttributeType; + + if (shouldDrop) + { + sqlStr = dropGeometryColumn("", tableName, geomAttribute.getLocalName()); + getLogger().info(sqlStr); + result.add(sqlStr); + } + + CoordinateReferenceSystem refSys = geomAttribute.getCoordinateSystem(); + int SRID; + + if (refSys != null) + { + try + { + Set ident = refSys.getIdentifiers(); + if ((ident == null || ident.isEmpty()) && refSys == DefaultGeographicCRS.WGS84) + { + SRID = 4326; + } else + { + String code = ((NamedIdentifier) ident.toArray()[0]).getCode(); + SRID = Integer.parseInt(code); + } + } catch (Exception e) + { + getLogger().warn("SRID could not be determined"); + SRID = -1; + } + } else + { + SRID = -1; + } + + sqlStr = addGeometryColumn("", tableName, geomAttribute, SRID); + getLogger().info(sqlStr); + result.add(sqlStr); + + + String indexName = tableName.replace('-', '_'); + //also build a spatial index on each geometry column. + sql = new StringBuffer("CREATE INDEX spatial_"); + sql.append(indexName); + sql.append("_"); + sql.append(anAttributeType.getLocalName().toLowerCase()); + sql.append(" ON "); + sql.append(encodeSchemaTableName(tableName)); + sql.append(" USING GIST ("); + sql.append(encodeSchemaColumnName(anAttributeType.getLocalName())); + sql.append(" gist_geometry_ops);"); + + sqlStr = sql.toString(); + getLogger().info(sqlStr); + + result.add(sqlStr); } return result; @@ -553,6 +697,96 @@ { typeName = "GEOMETRY"; } else if (typeName.equals("VARCHAR")) + { + int length = -1; + Filter f = anAttributeType.getRestriction(); + if (f != null && f != Filter.EXCLUDE && f != Filter.INCLUDE && + (f instanceof PropertyIsLessThan || f instanceof PropertyIsLessThanOrEqualTo)) + { + try + { + BinaryComparisonOperator cf = (BinaryComparisonOperator) f; + if (cf.getExpression1() instanceof LengthFunction) + { + length = Integer.parseInt(((Literal) cf.getExpression2()).getValue().toString()); + } else + { + if (cf.getExpression2() instanceof LengthFunction) + { + length = Integer.parseInt(((Literal) cf.getExpression1()).getValue().toString()); + } + } + } catch (NumberFormatException e) + { + length = 256; + } + } else + { + length = 256; + } + + if (length < 1) + { + getLogger().warn("FeatureType did not specify string length; defaulted to 256"); + length = 256; + } else if (length > MAX_ALLOWED_VALUE) + { + length = MAX_ALLOWED_VALUE; + } + typeName = typeName + "(" + length + ")"; + } + + if (!anAttributeType.isNillable()) + { + typeName = typeName + " NOT NULL"; + } + + //TODO review!!! Is toString() always OK??? + Object defaultValue = anAttributeType.createDefaultValue(); + + if (defaultValue != null) + { + typeName = typeName + " DEFAULT '" + + defaultValue.toString() + "'"; + } + + buf.append(" \"").append(anAttributeType.getLocalName()).append("\" ").append(typeName).append(","); + + } else + { + String msg; + if (anAttributeType == null) + { + msg = "AttributeType was null!"; + } else + { + msg = "Type '" + anAttributeType.getBinding() + "' not supported!"; + } + throw (new IOException(msg)); + } + } + + return buf.deleteCharAt(buf.length() - 1); + } + + private StringBuffer makeNonGeomSqlCreate(AttributeType[] attributeType) + throws IOException + { + StringBuffer buf = new StringBuffer(""); + + for (AttributeType anAttributeType : attributeType) + { + String typeName; + typeName = CLASS_MAPPINGS.get(anAttributeType.getBinding()); + if (typeName == null) + { + typeName = GEOM_CLASS_MAPPINGS.get(anAttributeType.getBinding()); + if (typeName != null) continue; + } + + if (typeName != null) + { + if (typeName.equals("VARCHAR")) { int length = -1; Filter f = anAttributeType.getRestriction(); @@ -729,6 +963,38 @@ return (statementSQL.toString()); } + protected String makePrepareInsertSql(FeatureType featureType) + { + String tableName = encodeSchemaTableName(featureType.getTypeName()); + AttributeType[] attributeTypes = featureType.getAttributeTypes(); + + String attrValue; + + StringBuffer statementSQL = new StringBuffer("INSERT INTO " + tableName + " ("); + + // encode insertion for attributes, but remember to avoid auto-increment ones, + // they may be included in the feature type as well + for (AttributeType attributeType : attributeTypes) + { + String attName = attributeType.getLocalName(); + + String colName = encodeSchemaColumnName(attName); + statementSQL.append(colName).append(","); + } + + statementSQL.setCharAt(statementSQL.length() - 1, ')'); + statementSQL.append(" VALUES ("); + + for (AttributeType attributeType : attributeTypes) + { + statementSQL.append(" ? ,"); + } + + statementSQL.setCharAt(statementSQL.length() - 1, ')'); + + return (statementSQL.toString()); + } + protected String addQuotes(Object value) { String retString; @@ -765,12 +1031,72 @@ return encodeName(colName); } - public String encodeSchemaTableName(String tableName) { + public String encodeSchemaTableName(String tableName) + { return schemaEnabled ? ("\"" + targetDataStore.getDatabaseSchemaName() + "\".\"" + tableName + "\"") - : ("\"" + tableName + "\""); + : ("\"" + tableName + "\""); } - public String encodeSchemaColumnName(String columnName) { + public String encodeSchemaColumnName(String columnName) + { return "\"" + columnName + "\""; } + + protected void bindFeatureParameters(PreparedStatement pstmt, Feature feature) throws SQLException + { + FeatureType featureType = feature.getFeatureType(); + + AttributeType[] attributeTypes = featureType.getAttributeTypes(); + Object[] attributes = feature.getAttributes(null); + + for (int i = 0; i < attributeTypes.length; i++) + { + if (attributeTypes[i] instanceof GeometryAttributeType) + { + pstmt.setBytes(i + 1, binaryWriter.writeBinary((Geometry) attributes[i])); + } else + { + if (attributeTypes[i].getBinding().equals(Short.class)) + { + pstmt.setShort(i + 1, (Short) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(Integer.class)) + { + pstmt.setInt(i + 1, (Short) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(Long.class)) + { + pstmt.setLong(i + 1, (Long) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(String.class)) + { + pstmt.setString(i + 1, (String) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(Float.class)) + { + pstmt.setFloat(i + 1, (Float) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(Double.class)) + { + pstmt.setDouble(i + 1, (Double) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(Boolean.class)) + { + pstmt.setBoolean(i + 1, (Boolean) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(BigDecimal.class)) + { + pstmt.setBigDecimal(i + 1, (BigDecimal) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(java.sql.Date.class)) + { + pstmt.setDate(i + 1, (java.sql.Date) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(java.sql.Time.class)) + { + pstmt.setTime(i + 1, (java.sql.Time) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(java.sql.Timestamp.class)) + { + pstmt.setTimestamp(i + 1, (java.sql.Timestamp) attributes[i]); + } else if (attributeTypes[i].getBinding().equals(java.util.Date.class)) + { + java.sql.Date sDate = new java.sql.Date(((java.util.Date) attributes[i]).getTime()); + pstmt.setDate(i + 1, sDate); + } + } + + } + } + } diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/AbstractOracleToPostGISJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/AbstractOracleToPostGISJobContext.java index 774e7cd..9f8d017 100644 --- a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/AbstractOracleToPostGISJobContext.java +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/AbstractOracleToPostGISJobContext.java @@ -44,28 +44,31 @@ import com.vividsolutions.jts.io.WKBWriter; import com.ximple.eofms.jobs.context.AbstractOracleJobContext; +import com.ximple.eofms.util.postjts.JtsBinaryWriter; public abstract class AbstractOracleToPostGISJobContext extends AbstractOracleJobContext { private static Map<String, Class> GEOM_TYPE_MAP = new HashMap<String, Class>(); + private static Map<String, Class> GEOM3D_TYPE_MAP = new HashMap<String, Class>(); static { GEOM_TYPE_MAP.put("GEOMETRY", Geometry.class); GEOM_TYPE_MAP.put("POINT", Point.class); - GEOM_TYPE_MAP.put("POINTM", Point.class); GEOM_TYPE_MAP.put("LINESTRING", LineString.class); - GEOM_TYPE_MAP.put("LINESTRINGM", LineString.class); GEOM_TYPE_MAP.put("POLYGON", Polygon.class); - GEOM_TYPE_MAP.put("POLYGONM", Polygon.class); GEOM_TYPE_MAP.put("MULTIPOINT", MultiPoint.class); - GEOM_TYPE_MAP.put("MULTIPOINTM", MultiPoint.class); GEOM_TYPE_MAP.put("MULTILINESTRING", MultiLineString.class); - GEOM_TYPE_MAP.put("MULTILINESTRINGM", MultiLineString.class); GEOM_TYPE_MAP.put("MULTIPOLYGON", MultiPolygon.class); - GEOM_TYPE_MAP.put("MULTIPOLYGONM", MultiPolygon.class); GEOM_TYPE_MAP.put("GEOMETRYCOLLECTION", GeometryCollection.class); - GEOM_TYPE_MAP.put("GEOMETRYCOLLECTIONM", GeometryCollection.class); + + GEOM3D_TYPE_MAP.put("POINTM", Point.class); + GEOM3D_TYPE_MAP.put("LINESTRINGM", LineString.class); + GEOM3D_TYPE_MAP.put("POLYGONM", Polygon.class); + GEOM3D_TYPE_MAP.put("MULTIPOINTM", MultiPoint.class); + GEOM3D_TYPE_MAP.put("MULTILINESTRINGM", MultiLineString.class); + GEOM3D_TYPE_MAP.put("MULTIPOLYGONM", MultiPolygon.class); + GEOM3D_TYPE_MAP.put("GEOMETRYCOLLECTIONM", GeometryCollection.class); } private static Map<Class, String> CLASS_MAPPINGS = new HashMap<Class, String>(); @@ -112,15 +115,15 @@ */ private static final int MAX_ALLOWED_VALUE = 10485760; - protected static final int BATCHSIZE = 25; + protected static final int BATCHSIZE = 256; /** * Well Known Text writer (from JTS). */ protected static WKTWriter geometryWriter = new WKTWriter(); + protected static JtsBinaryWriter binaryWriter = new JtsBinaryWriter(); protected PostgisDataStore targetDataStore; - private Connection connection; protected boolean schemaEnabled = true; @@ -252,7 +255,7 @@ { StringBuffer sql = new StringBuffer("CREATE TABLE "); sql.append(encodeSchemaTableName(tableName)); - sql.append(" ("); + sql.append(" ( gid serial PRIMARY KEY, "); sql.append(makeSqlCreate(attributeType)); sql.append(");"); diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/GeneralDgnConvertPostGISJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/GeneralDgnConvertPostGISJobContext.java index 12fca64..da212f0 100644 --- a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/GeneralDgnConvertPostGISJobContext.java +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/GeneralDgnConvertPostGISJobContext.java @@ -3,7 +3,6 @@ import java.io.IOException; import java.math.BigDecimal; import java.math.RoundingMode; -import java.net.MalformedURLException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; @@ -12,26 +11,19 @@ import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; +import java.sql.PreparedStatement; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.commons.transaction.memory.PessimisticMapWrapper; import org.apache.commons.transaction.util.CommonsLoggingLogger; import org.apache.commons.transaction.util.LoggerFacade; import org.geotools.data.DataStore; -import org.geotools.data.FeatureWriter; import org.geotools.data.Transaction; -import org.geotools.data.DefaultTransaction; -import org.geotools.data.DataSourceException; -import org.geotools.data.FeatureStore; import org.geotools.feature.Feature; import org.geotools.feature.FeatureType; import org.geotools.feature.FeatureTypeBuilder; import org.geotools.feature.IllegalAttributeException; import org.geotools.feature.SchemaException; -import org.geotools.feature.SimpleFeature; -import org.geotools.feature.FeatureCollection; -import org.geotools.feature.FeatureCollections; import org.postgresql.util.PSQLException; import com.vividsolutions.jts.geom.Geometry; @@ -58,7 +50,7 @@ static final LoggerFacade sLogger = new CommonsLoggingLogger(logger); static final GeometryFactory geometryFactory = new GeometryFactory(); - private HashMap<FeatureType, ArrayList<String>> txFeaturesContext = new HashMap<FeatureType, ArrayList<String>>(); + private HashMap<FeatureType, ArrayList<Feature>> txFeaturesContext = new HashMap<FeatureType, ArrayList<Feature>>(); private TreeMap<String, FeatureTypeBuilder> typeBuilders = new TreeMap<String, FeatureTypeBuilder>(); private TreeMap<String, FeatureType> featureTypes = new TreeMap<String, FeatureType>(); @@ -66,6 +58,8 @@ private TWD97GeometryConverterDecorator convertDecorator = null; private String featureBaseName = null; private boolean dropTableMode = true; + + private int accumulate = 0; public GeneralDgnConvertPostGISJobContext(String dataPath, DataStore targetDataStore) { @@ -102,18 +96,26 @@ if (!txFeaturesContext.containsKey(feature.getFeatureType())) { - txFeaturesContext.put(feature.getFeatureType(), new ArrayList<String>()); + txFeaturesContext.put(feature.getFeatureType(), new ArrayList<Feature>()); } - ArrayList<String> arrayList = txFeaturesContext.get(feature.getFeatureType()); + ArrayList<Feature> arrayList = txFeaturesContext.get(feature.getFeatureType()); if (feature.getDefaultGeometry() != null && !feature.getDefaultGeometry().isEmpty()) - arrayList.add(makeInsertSql(feature, -1)); + { + arrayList.add(feature); + accumulate++; + } } else { logger.info("Unknown Element :" + element.getType() + ", lv=" + element.getLevelIndex()); } + + if (accumulate > BATCHSIZE) + { + commitTransaction(); + } } - private Transaction transaction; + // private Transaction transaction; public void startTransaction() { @@ -154,18 +156,22 @@ FeatureType featureType = it.next(); logger.debug("Begin Save into PostGIS:" + featureType.getTypeName()); - ArrayList<String> stmtTexts = txFeaturesContext.get(featureType); + String bindingStmt = makePrepareInsertSql(featureType, -1); + ArrayList<Feature> features = txFeaturesContext.get(featureType); Connection conn = getConnection(); boolean autoCommit = conn.getAutoCommit(); conn.setAutoCommit(true); + PreparedStatement pstmt = conn.prepareStatement(bindingStmt); - for (String stmtText : stmtTexts) + for (Feature feature : features) { - currentStmt = stmtText; - Statement stmt = conn.createStatement(); + // currentStmt = feature; + // Statement stmt = conn.createStatement(); try { - stmt.execute(stmtText); + // stmt.execute(feature); + bindFeatureParameters(pstmt, feature); + pstmt.execute(); } catch (PSQLException e) { if (currentStmt != null) @@ -174,24 +180,29 @@ } logger.error(e.getServerErrorMessage()); logger.error(e.getMessage(), e); + /* } finally { stmt.close(); + */ } + /* if ((i % BATCHSIZE) != 0) { - stmt.addBatch(stmtText); + stmt.addBatch(feature); } else { - stmt.addBatch(stmtText); + stmt.addBatch(feature); stmt.executeBatch(); } i++; */ } - stmtTexts.clear(); + pstmt.close(); + features.clear(); conn.setAutoCommit(autoCommit); logger.debug("End Save into PostGIS:" + featureType.getTypeName()); } + accumulate = 0; } catch (SQLException e) { logger.error(e.getMessage(), e); @@ -221,11 +232,33 @@ return typeBuilders.get(featureName).getFeatureType(); } + public FeatureType createPolygonFeatureElement(String featureName) throws SchemaException + { + if (!typeBuilders.containsKey(featureName)) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createNormalPolygonFeatureTypeBuilder(featureName); + typeBuilders.put(featureName, typeBuilder); + clearFeatureData(typeBuilder); + } + return typeBuilders.get(featureName).getFeatureType(); + } + public FeatureType createLineFeatureElement(String featureName) throws SchemaException { if (!typeBuilders.containsKey(featureName)) { FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createNormalLineFeatureTypeBuilder(featureName); + typeBuilders.put(featureName, typeBuilder); + clearFeatureData(typeBuilder); + } + return typeBuilders.get(featureName).getFeatureType(); + } + + public FeatureType createMultiLineFeatureElement(String featureName) throws SchemaException + { + if (!typeBuilders.containsKey(featureName)) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilderUtil.createNormalMultiLineFeatureTypeBuilder(featureName); typeBuilders.put(featureName, typeBuilder); clearFeatureData(typeBuilder); } @@ -431,7 +464,8 @@ String typeName; if (element instanceof TextElement) { - typeName = getFeatureBaseName() + "P"; + typeName = getFeatureBaseName() + "_P"; + typeName = typeName.toLowerCase(); if (!featureTypes.containsKey(typeName)) { featureTypes.put(typeName, createPointFeatureElement(typeName)); @@ -439,7 +473,8 @@ return featureTypes.get(typeName); } else if (element instanceof TextNodeElement) { - typeName = getFeatureBaseName() + "P"; + typeName = getFeatureBaseName() + "_P"; + typeName = typeName.toLowerCase(); if (!featureTypes.containsKey(typeName)) { featureTypes.put(typeName, createPointFeatureElement(typeName)); @@ -449,15 +484,17 @@ { if (element instanceof ShapeElement) { - typeName = getFeatureBaseName() + "R"; + typeName = getFeatureBaseName() + "_R"; + typeName = typeName.toLowerCase(); if (!featureTypes.containsKey(typeName)) { - featureTypes.put(typeName, createLineFeatureElement(typeName)); + featureTypes.put(typeName, createPolygonFeatureElement(typeName)); } return featureTypes.get(typeName); } else { - typeName = getFeatureBaseName() + "L"; + typeName = getFeatureBaseName() + "_L"; + typeName = typeName.toLowerCase(); if (!featureTypes.containsKey(typeName)) { featureTypes.put(typeName, createLineFeatureElement(typeName)); @@ -466,7 +503,8 @@ } } else if (element instanceof LineElement) { - typeName = getFeatureBaseName() + "L"; + typeName = getFeatureBaseName() + "_L"; + typeName = typeName.toLowerCase(); if (!featureTypes.containsKey(typeName)) { featureTypes.put(typeName, createLineFeatureElement(typeName)); @@ -474,15 +512,17 @@ return featureTypes.get(typeName); } else if (element instanceof ComplexChainElement) { - typeName = getFeatureBaseName() + "L"; + typeName = getFeatureBaseName() + "_ML"; + typeName = typeName.toLowerCase(); if (!featureTypes.containsKey(typeName)) { - featureTypes.put(typeName, createLineFeatureElement(typeName)); + featureTypes.put(typeName, createMultiLineFeatureElement(typeName)); } return featureTypes.get(typeName); } else if (element instanceof ArcElement) { - typeName = getFeatureBaseName() + "A"; + typeName = getFeatureBaseName() + "_A"; + typeName = typeName.toLowerCase(); if (!featureTypes.containsKey(typeName)) { featureTypes.put(typeName, createArcFeatureElement(typeName)); @@ -490,7 +530,8 @@ return featureTypes.get(typeName); } else if (element instanceof EllipseElement) { - typeName = getFeatureBaseName() + "R"; + typeName = getFeatureBaseName() + "_R"; + typeName = typeName.toLowerCase(); if (!featureTypes.containsKey(typeName)) { featureTypes.put(typeName, createEllipseFeatureElement(typeName)); @@ -546,7 +587,7 @@ typeBuilder.getFeatureType().getDefaultGeometry().getLocalName()); dropTable(conn, featureName); - ArrayList<String> schemaTexts = createSchemaTexts(typeBuilder.getFeatureType()); + ArrayList<String> schemaTexts = createNewSchemaTexts(typeBuilder.getFeatureType()); for (String stmtText : schemaTexts) { Statement stmt = conn.createStatement(); @@ -569,7 +610,7 @@ try { Connection conn = targetDataStore.getConnection(Transaction.AUTO_COMMIT); - ArrayList<String> schemaTexts = createSchemaTexts(typeBuilder.getFeatureType()); + ArrayList<String> schemaTexts = createNewSchemaTexts(typeBuilder.getFeatureType()); for (String stmtText : schemaTexts) { Statement stmt = conn.createStatement(); diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/IndexDgnConvertPostGISJobContext.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/IndexDgnConvertPostGISJobContext.java index 0280990..123221a 100644 --- a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/IndexDgnConvertPostGISJobContext.java +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/jobs/context/postgis/IndexDgnConvertPostGISJobContext.java @@ -6,6 +6,7 @@ import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; +import java.sql.PreparedStatement; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; @@ -46,7 +47,7 @@ static final GeometryFactory geometryFactory = new GeometryFactory(); TWD97GeometryConverterDecorator convertDecorator = new TWD97GeometryConverterDecorator(); - private HashMap<FeatureType, ArrayList<String>> txFeaturesContext = new HashMap<FeatureType, ArrayList<String>>(); + private HashMap<FeatureType, ArrayList<Feature>> txFeaturesContext = new HashMap<FeatureType, ArrayList<Feature>>(); private FeatureTypeBuilder typeBuilderPnt = null; private FeatureTypeBuilder typeBuilderRect = null; @@ -54,6 +55,7 @@ private FeatureType featureType2 = null; private boolean dropTableMode = true; + private int accumulate = 0; public IndexDgnConvertPostGISJobContext(String dataPath, DataStore targetDataStore) { @@ -77,10 +79,10 @@ if (!txFeaturesContext.containsKey(feature.getFeatureType())) { - txFeaturesContext.put(feature.getFeatureType(), new ArrayList<String>()); + txFeaturesContext.put(feature.getFeatureType(), new ArrayList<Feature>()); } - ArrayList<String> arrayList = txFeaturesContext.get(feature.getFeatureType()); - arrayList.add(makeInsertSql(feature, -1)); + ArrayList<Feature> arrayList = txFeaturesContext.get(feature.getFeatureType()); + arrayList.add(feature); feature = createFeature2((TextElement) element); if (feature == null) @@ -92,10 +94,16 @@ if (!txFeaturesContext.containsKey(feature.getFeatureType())) { - txFeaturesContext.put(feature.getFeatureType(), new ArrayList<String>()); + txFeaturesContext.put(feature.getFeatureType(), new ArrayList<Feature>()); } arrayList = txFeaturesContext.get(feature.getFeatureType()); - arrayList.add(makeInsertSql(feature, -1)); + arrayList.add(feature); + accumulate++; + + if (accumulate > BATCHSIZE) + { + commitTransaction(); + } } public void startTransaction() @@ -136,20 +144,22 @@ FeatureType featureType = it.next(); logger.debug("Begin Save PostGIS:" + featureType.getTypeName()); - ArrayList<String> stmtTexts = txFeaturesContext.get(featureType); + String bindingStmt = makePrepareInsertSql(featureType, -1); + ArrayList<Feature> features = txFeaturesContext.get(featureType); Connection conn = getConnection(); boolean autoCommit = conn.getAutoCommit(); conn.setAutoCommit(true); - // conn.setAutoCommit(false); - // Statement stmt = conn.createStatement(); - // int i = 0; - for (String stmtText : stmtTexts) + PreparedStatement pstmt = conn.prepareStatement(bindingStmt); + + for (Feature feature : features) { - currentStmt = stmtText; - Statement stmt = conn.createStatement(); + // currentStmt = feature; + // Statement stmt = conn.createStatement(); try { - stmt.execute(stmtText); + // stmt.execute(feature); + bindFeatureParameters(pstmt, feature); + pstmt.execute(); } catch (PSQLException e) { if (currentStmt != null) @@ -158,19 +168,11 @@ } logger.error(e.getServerErrorMessage()); logger.error(e.getMessage(), e); + /* } finally { stmt.close(); + */ } - /* - if ((i % BATCHSIZE) != 0) - { - stmt.addBatch(stmtText); - } else { - stmt.addBatch(stmtText); - stmt.executeBatch(); - } - i++; - */ } /* if ((i % BATCHSIZE) != 0) @@ -178,11 +180,15 @@ stmt.executeBatch(); } stmt.close(); - stmtTexts.clear(); */ + + pstmt.close(); + features.clear(); + conn.setAutoCommit(autoCommit); logger.debug("End Save PostGIS:" + featureType.getTypeName()); } + accumulate = 0; } catch (PSQLException e) { if (currentStmt != null) @@ -221,10 +227,22 @@ Connection conn = targetDataStore.getConnection(Transaction.AUTO_COMMIT); if (dropTableMode) { - dropGeometryColumn(conn, featureName, - typeBuilderRect.getFeatureType().getDefaultGeometry().getLocalName()); - dropTable(conn, featureName); - ArrayList<String> schemaTexts = createSchemaTexts(typeBuilderRect.getFeatureType()); + try + { + dropGeometryColumn(conn, featureName, + typeBuilderRect.getFeatureType().getDefaultGeometry().getLocalName()); + } catch (PSQLException e) + { + logger.debug(e.getMessage(), e); + } + try + { + dropTable(conn, featureName); + } catch (PSQLException e) + { + logger.debug(e.getMessage(), e); + } + ArrayList<String> schemaTexts = createNewSchemaTexts(typeBuilderRect.getFeatureType()); for (String stmtText : schemaTexts) { Statement stmt = conn.createStatement(); @@ -248,7 +266,7 @@ try { Connection conn = targetDataStore.getConnection(Transaction.AUTO_COMMIT); - ArrayList<String> schemaTexts = createSchemaTexts(typeBuilderRect.getFeatureType()); + ArrayList<String> schemaTexts = createNewSchemaTexts(typeBuilderRect.getFeatureType()); for (String stmtText : schemaTexts) { Statement stmt = conn.createStatement(); @@ -284,7 +302,7 @@ typeBuilderPnt.getFeatureType().getDefaultGeometry().getLocalName()); dropTable(conn, featureName); - ArrayList<String> schemaTexts = createSchemaTexts(typeBuilderPnt.getFeatureType()); + ArrayList<String> schemaTexts = createNewSchemaTexts(typeBuilderPnt.getFeatureType()); for (String stmtText : schemaTexts) { Statement stmt = conn.createStatement(); @@ -308,7 +326,7 @@ try { Connection conn = targetDataStore.getConnection(Transaction.AUTO_COMMIT); - ArrayList<String> schemaTexts = createSchemaTexts(typeBuilderPnt.getFeatureType()); + ArrayList<String> schemaTexts = createNewSchemaTexts(typeBuilderPnt.getFeatureType()); for (String stmtText : schemaTexts) { Statement stmt = conn.createStatement(); @@ -337,14 +355,14 @@ String tpclid = textElement.getText(); Envelope extent = TPCLIDConverter.convertTpclIdToEnvelope(tpclid); - Geometry geom = geometryFactory.createLinearRing(new Coordinate[] + Geometry geom = geometryFactory.createPolygon(geometryFactory.createLinearRing(new Coordinate[] { TWDDatumConverter.fromTM2ToTWD97(new Coordinate(extent.getMinX(), extent.getMinY())), TWDDatumConverter.fromTM2ToTWD97(new Coordinate(extent.getMaxX(), extent.getMinY())), TWDDatumConverter.fromTM2ToTWD97(new Coordinate(extent.getMaxX(), extent.getMaxY())), TWDDatumConverter.fromTM2ToTWD97(new Coordinate(extent.getMinX(), extent.getMaxY())), TWDDatumConverter.fromTM2ToTWD97(new Coordinate(extent.getMinX(), extent.getMinY())), - }); + }), null); return featureType.create(new Object[]{ geom, @@ -396,7 +414,7 @@ { dgnname = dgnname.substring(0, i); } - featureType = createFeatureElement(dgnname); + featureType = createFeatureElement(dgnname.toLowerCase()); } return createFeature(featureType, element); } @@ -411,8 +429,8 @@ { dgnname = dgnname.substring(0, i); } - dgnname = dgnname + "P"; - featureType2 = createFeatureElement2(dgnname); + dgnname = dgnname + "_p"; + featureType2 = createFeatureElement2(dgnname.toLowerCase()); } return createFeature2(featureType2, element); } diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/FeatureTypeBuilderUtil.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/FeatureTypeBuilderUtil.java index 0abd936..4fb6712 100644 --- a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/FeatureTypeBuilderUtil.java +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/FeatureTypeBuilderUtil.java @@ -3,9 +3,11 @@ import org.geotools.feature.AttributeTypeFactory; import org.geotools.feature.FeatureTypeBuilder; -import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryFactory; -import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Point; +import com.vividsolutions.jts.geom.Polygon; +import com.vividsolutions.jts.geom.LineString; +import com.vividsolutions.jts.geom.MultiLineString; public final class FeatureTypeBuilderUtil { @@ -14,7 +16,7 @@ public static FeatureTypeBuilder createNormalPointFeatureTypeBuilder(String featureName) { FeatureTypeBuilder typeBuilder = FeatureTypeBuilder.newInstance(featureName); - typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", Geometry.class, true)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", Point.class, true)); typeBuilder.addType(AttributeTypeFactory.newAttributeType("symcolor", String.class, false, 12, "")); typeBuilder.addType(AttributeTypeFactory.newAttributeType("font", Short.class, false, 1, (short) 0)); typeBuilder.addType(AttributeTypeFactory.newAttributeType("just", Short.class, false, 1, (short) 0)); @@ -28,7 +30,27 @@ public static FeatureTypeBuilder createNormalLineFeatureTypeBuilder(String featureName) { FeatureTypeBuilder typeBuilder = FeatureTypeBuilder.newInstance(featureName); - typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", Geometry.class, true)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", LineString.class, true)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symcolor", String.class, false, 12, "")); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symweight", Short.class, false, 1, (short) 0)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symstyle", Short.class, false, 1, (short) 0)); + return typeBuilder; + } + + public static FeatureTypeBuilder createNormalMultiLineFeatureTypeBuilder(String featureName) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilder.newInstance(featureName); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", MultiLineString.class, true)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symcolor", String.class, false, 12, "")); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symweight", Short.class, false, 1, (short) 0)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symstyle", Short.class, false, 1, (short) 0)); + return typeBuilder; + } + + public static FeatureTypeBuilder createNormalPolygonFeatureTypeBuilder(String featureName) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilder.newInstance(featureName); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", Polygon.class, true)); typeBuilder.addType(AttributeTypeFactory.newAttributeType("symcolor", String.class, false, 12, "")); typeBuilder.addType(AttributeTypeFactory.newAttributeType("symweight", Short.class, false, 1, (short) 0)); typeBuilder.addType(AttributeTypeFactory.newAttributeType("symstyle", Short.class, false, 1, (short) 0)); @@ -50,7 +72,7 @@ public static FeatureTypeBuilder createNormalEllipseFeatureTypeBuilder(String featureName) { - return createNormalLineFeatureTypeBuilder(featureName); + return createNormalPolygonFeatureTypeBuilder(featureName); /* FeatureTypeBuilder typeBuilder = FeatureTypeBuilder.newInstance(featureName); typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", Geometry.class, false)); @@ -64,7 +86,7 @@ public static FeatureTypeBuilder createNormalIndexFeatureTypeBuilder(String featureName) { FeatureTypeBuilder typeBuilder = FeatureTypeBuilder.newInstance(featureName); - typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", Geometry.class, true)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", Polygon.class, true)); typeBuilder.addType(AttributeTypeFactory.newAttributeType("x1", Double.class, false, 1, 0.0)); typeBuilder.addType(AttributeTypeFactory.newAttributeType("y1", Double.class, false, 1, 0.0)); typeBuilder.addType(AttributeTypeFactory.newAttributeType("x2", Double.class, false, 1, 0.0)); @@ -80,7 +102,7 @@ { FeatureTypeBuilder typeBuilder = FeatureTypeBuilder.newInstance(featureName); typeBuilder = FeatureTypeBuilder.newInstance(featureName); - typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", Geometry.class, true)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", Point.class, true)); typeBuilder.addType(AttributeTypeFactory.newAttributeType("symcolor", String.class, false, 12, "")); typeBuilder.addType(AttributeTypeFactory.newAttributeType("symweight", Short.class, false, 1, (short) 0)); typeBuilder.addType(AttributeTypeFactory.newAttributeType("symstyle", Short.class, false, 1, (short) 0)); @@ -95,7 +117,7 @@ public static FeatureTypeBuilder createPointFeatureTypeBuilder(String featureName) { FeatureTypeBuilder typeBuilder = FeatureTypeBuilder.newInstance(featureName); - typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", Geometry.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", Point.class, false)); typeBuilder.addType(AttributeTypeFactory.newAttributeType("tid", Short.class, false)); typeBuilder.addType(AttributeTypeFactory.newAttributeType("oid", Long.class, false)); typeBuilder.addType(AttributeTypeFactory.newAttributeType("cid", Short.class, false)); @@ -115,7 +137,7 @@ public static FeatureTypeBuilder createSymbolFeatureTypeBuilder(String featureName) { FeatureTypeBuilder typeBuilder = FeatureTypeBuilder.newInstance(featureName); - typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", Geometry.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", Point.class, false)); typeBuilder.addType(AttributeTypeFactory.newAttributeType("tid", Short.class, false)); typeBuilder.addType(AttributeTypeFactory.newAttributeType("oid", Long.class, false)); typeBuilder.addType(AttributeTypeFactory.newAttributeType("cid", Short.class, false)); @@ -134,10 +156,8 @@ public static FeatureTypeBuilder createPolygonFeatureTypeBuilder(String featureName) { - return createLineStringFeatureTypeBuilder(featureName); - /* FeatureTypeBuilder typeBuilder = FeatureTypeBuilder.newInstance(featureName); - typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", Geometry.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", Polygon.class, false)); typeBuilder.addType(AttributeTypeFactory.newAttributeType("tid", Short.class, false)); typeBuilder.addType(AttributeTypeFactory.newAttributeType("oid", Long.class)); typeBuilder.addType(AttributeTypeFactory.newAttributeType("cid", Short.class, false)); @@ -147,13 +167,27 @@ typeBuilder.addType(AttributeTypeFactory.newAttributeType("symweight", Short.class, false)); typeBuilder.addType(AttributeTypeFactory.newAttributeType("symstyle", Short.class, false)); return typeBuilder; - */ } - public static FeatureTypeBuilder createLineStringFeatureTypeBuilder(String featureName) + public static FeatureTypeBuilder createLineFeatureTypeBuilder(String featureName) { FeatureTypeBuilder typeBuilder = FeatureTypeBuilder.newInstance(featureName); - typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", Geometry.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", LineString.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("tid", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("oid", Long.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("cid", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("lid", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("level", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symcolor", String.class, false, 12)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symweight", Short.class, false)); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("symstyle", Short.class, false)); + return typeBuilder; + } + + public static FeatureTypeBuilder createMultiLineFeatureTypeBuilder(String featureName) + { + FeatureTypeBuilder typeBuilder = FeatureTypeBuilder.newInstance(featureName); + typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", MultiLineString.class, false)); typeBuilder.addType(AttributeTypeFactory.newAttributeType("tid", Short.class, false)); typeBuilder.addType(AttributeTypeFactory.newAttributeType("oid", Long.class, false)); typeBuilder.addType(AttributeTypeFactory.newAttributeType("cid", Short.class, false)); @@ -167,7 +201,7 @@ public static FeatureTypeBuilder createEllipseFeatureTypeBuilder(String featureName) { - return createLineStringFeatureTypeBuilder(featureName); + return createPolygonFeatureTypeBuilder(featureName); /* FeatureTypeBuilder typeBuilder = FeatureTypeBuilder.newInstance(featureName); typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", Geometry.class, false)); @@ -185,7 +219,7 @@ public static FeatureTypeBuilder createArcFeatureTypeBuilder(String featureName) { - return createLineStringFeatureTypeBuilder(featureName); + return createLineFeatureTypeBuilder(featureName); /* FeatureTypeBuilder typeBuilder = FeatureTypeBuilder.newInstance(featureName); typeBuilder.addType(AttributeTypeFactory.newAttributeType("geom", Geometry.class, false)); diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JTSShape.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JTSShape.java new file mode 100644 index 0000000..ebbcd74 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JTSShape.java @@ -0,0 +1,339 @@ +package com.ximple.eofms.util.postjts; + +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.PathIterator; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.CoordinateSequence; +import com.vividsolutions.jts.geom.Envelope; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryCollection; +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.LineString; +import com.vividsolutions.jts.geom.LinearRing; +import com.vividsolutions.jts.geom.Point; +import com.vividsolutions.jts.geom.Polygon; +import com.vividsolutions.jts.geom.impl.PackedCoordinateSequence; + +public class JTSShape implements Shape +{ + static GeometryFactory fac = new GeometryFactory(); + + Geometry geom; + + final static LinearRing[] NOSHELLS = {}; + + public JTSShape(Geometry _geom) + { + this.geom = _geom; + } + + public JTSShape(JtsGeometry _geom) + { + this(_geom.getGeometry()); + } + + public boolean contains(Point2D p) + { + return contains(p.getX(), p.getY()); + } + + public boolean contains(double x, double y) + { + Coordinate c = new Coordinate(x, y); + Point p = fac.createPoint(c); + return geom.contains(p); + } + + public boolean contains(Rectangle2D r) + { + return contains(r.getMinX(), r.getMinY(), r.getWidth(), r.getHeight()); + } + + public boolean contains(double x, double y, double w, double h) + { + Polygon p = createRect(x, y, w, h); + return geom.contains(p); + } + + protected Polygon createRect(double x, double y, double w, double h) + { + double[] arr = {x, y, x + w, y, x + w, y + h, x, y + h, x, y}; + PackedCoordinateSequence shell = new PackedCoordinateSequence.Double(arr, 2); + Polygon p = fac.createPolygon(fac.createLinearRing(shell), NOSHELLS); + return p; + } + + public Rectangle2D getBounds2D() + { + Envelope env = geom.getEnvelopeInternal(); + return new Rectangle2D.Double(env.getMinX(), env.getMaxX(), env.getWidth(), env.getHeight()); + } + + public Rectangle getBounds() + { + // We deal simple code for efficiency here, the getBounds() rounding + // rules are ugly... + return getBounds2D().getBounds(); + } + + public PathIterator getPathIterator(AffineTransform at) + { + return getPathIterator(geom, at); + } + + public PathIterator getPathIterator(AffineTransform at, double flatness) + { + // we don't have much work here, as we only have linear segments, no + // "flattening" necessary. + return getPathIterator(at); + } + + public boolean intersects(Rectangle2D r) + { + return intersects(r.getMinX(), r.getMinY(), r.getWidth(), r.getHeight()); + } + + public boolean intersects(double x, double y, double w, double h) + { + Polygon p = createRect(x, y, w, h); + return geom.intersects(p); + } + + public static GeometryPathIterator getPathIterator(Geometry geometry, AffineTransform _at) + { + if (geometry instanceof Point) + { + return new PointPathIterator((Point) geometry, _at); + } else if (geometry instanceof LineString) + { + return new LineStringPathIterator((LineString) geometry, _at); + } else if (geometry instanceof Polygon) + { + return new PolygonPathIterator((Polygon) geometry, _at); + } else + { + return new GeometryCollectionPathIterator((GeometryCollection) geometry, _at); + } + } + + public static abstract class GeometryPathIterator implements PathIterator + { + + protected final AffineTransform at; + protected int index = 0; + + GeometryPathIterator(AffineTransform _at) + { + this.at = _at; + } + + public final int getWindingRule() + { + return PathIterator.WIND_EVEN_ODD; + } + + public void next() + { + index++; + } + } + + public static class PointPathIterator extends GeometryPathIterator + { + final Point p; + + public PointPathIterator(Point _p, AffineTransform _at) + { + super(_at); + p = _p; + } + + public int currentSegment(float[] coords) + { + switch (index) + { + case 0: + coords[0] = (float) p.getX(); + coords[1] = (float) p.getY(); + at.transform(coords, 0, coords, 0, 1); + return PathIterator.SEG_MOVETO; + case 1: + return PathIterator.SEG_CLOSE; + default: + throw new IllegalStateException(); + } + } + + public int currentSegment(double[] coords) + { + switch (index) + { + case 0: + coords[0] = p.getX(); + coords[1] = p.getY(); + at.transform(coords, 0, coords, 0, 1); + return PathIterator.SEG_MOVETO; + case 1: + return PathIterator.SEG_CLOSE; + default: + throw new IllegalStateException(); + } + } + + public boolean isDone() + { + return index > 1; + } + } + + public static class LineStringPathIterator extends GeometryPathIterator + { + CoordinateSequence cs; + + final boolean isRing; + + public LineStringPathIterator(LineString ls, AffineTransform _at) + { + super(_at); + cs = ls.getCoordinateSequence(); + isRing = ls instanceof LinearRing; + } + + /** + * only to be called from PolygonPathIterator subclass + */ + protected void reInit(CoordinateSequence _cs) + { + cs = _cs; + index = 0; + } + + public int currentSegment(float[] coords) + { + if (index == 0) + { + coords[0] = (float) cs.getOrdinate(index, 0); + coords[1] = (float) cs.getOrdinate(index, 1); + at.transform(coords, 0, coords, 0, 1); + return PathIterator.SEG_MOVETO; + } else if (index < cs.size()) + { + coords[0] = (float) cs.getOrdinate(index, 0); + coords[1] = (float) cs.getOrdinate(index, 1); + at.transform(coords, 0, coords, 0, 1); + return PathIterator.SEG_LINETO; + } else if (isRing && index == cs.size()) + { + return PathIterator.SEG_CLOSE; + } else + { + throw new IllegalStateException(); + } + } + + public int currentSegment(double[] coords) + { + if (index == 0) + { + coords[0] = cs.getOrdinate(index, 0); + coords[1] = cs.getOrdinate(index, 1); + at.transform(coords, 0, coords, 0, 1); + return PathIterator.SEG_MOVETO; + } else if (index < cs.size()) + { + coords[0] = cs.getOrdinate(index, 0); + coords[1] = cs.getOrdinate(index, 1); + at.transform(coords, 0, coords, 0, 1); + return PathIterator.SEG_LINETO; + } else if (isRing && index == cs.size()) + { + return PathIterator.SEG_CLOSE; + } else + { + throw new IllegalStateException(); + } + } + + public boolean isDone() + { + return isRing ? index > cs.size() : index >= cs.size(); + } + } + + public static class PolygonPathIterator extends LineStringPathIterator + { + final Polygon pg; + int outerindex = -1; + + public PolygonPathIterator(Polygon _pg, AffineTransform _at) + { + super(_pg.getExteriorRing(), _at); + pg = _pg; + index = -1; + } + + public boolean isDone() + { + return outerindex >= pg.getNumInteriorRing(); + } + + public void next() + { + super.next(); + if (super.isDone()) + { + outerindex++; + if (outerindex < pg.getNumInteriorRing()) + { + super.reInit(pg.getInteriorRingN(outerindex).getCoordinateSequence()); + } + } + } + } + + public static class GeometryCollectionPathIterator extends GeometryPathIterator + { + final GeometryCollection coll; + GeometryPathIterator current; + + public GeometryCollectionPathIterator(GeometryCollection _coll, AffineTransform _at) + { + super(_at); + coll = _coll; + current = getPathIterator(coll.getGeometryN(index), _at); + } + + public boolean isDone() + { + return index > coll.getNumGeometries(); + } + + public void next() + { + current.next(); + if (current.isDone()) + { + index++; + if (index < coll.getNumGeometries()) + { + current = getPathIterator(coll.getGeometryN(index), at); + } + } + } + + public int currentSegment(float[] coords) + { + return current.currentSegment(coords); + } + + public int currentSegment(double[] coords) + { + return current.currentSegment(coords); + } + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsBinaryParser.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsBinaryParser.java new file mode 100644 index 0000000..1ee359a --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsBinaryParser.java @@ -0,0 +1,287 @@ +/* + * JtsBinaryParser.java + * + * Binary Parser for JTS - relies on org.postgis V1.0.0+ package. + * + * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com + * + * 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, either 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. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA or visit the web at + * http://www.gnu.org. + * + * $Id$ + */ +package com.ximple.eofms.util.postjts; + +import org.postgis.binary.ByteGetter; +import org.postgis.binary.ByteGetter.BinaryByteGetter; +import org.postgis.binary.ByteGetter.StringByteGetter; +import org.postgis.binary.ValueGetter; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.CoordinateSequence; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryCollection; +import com.vividsolutions.jts.geom.LineString; +import com.vividsolutions.jts.geom.LinearRing; +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.impl.PackedCoordinateSequence; + +/** + * Parse binary representation of geometries. Currently, only text rep (hexed) + * implementation is tested. + * <p/> + * It should be easy to add char[] and CharSequence ByteGetter instances, + * although the latter one is not compatible with older jdks. + * <p/> + * I did not implement real unsigned 32-bit integers or emulate them with long, + * as both java Arrays and Strings currently can have only 2^31-1 elements + * (bytes), so we cannot even get or build Geometries with more than approx. + * 2^28 coordinates (8 bytes each). + * + * @author Markus Schaber, markus.schaber@logix-tt.com + */ +public class JtsBinaryParser +{ + + /** + * Get the appropriate ValueGetter for my endianness + * + * @param bytes The appropriate Byte Getter + * @return the ValueGetter + */ + public static ValueGetter valueGetterForEndian(ByteGetter bytes) + { + if (bytes.get(0) == ValueGetter.XDR.NUMBER) + { // XDR + return new ValueGetter.XDR(bytes); + } else if (bytes.get(0) == ValueGetter.NDR.NUMBER) + { + return new ValueGetter.NDR(bytes); + } else + { + throw new IllegalArgumentException("Unknown Endian type:" + bytes.get(0)); + } + } + + /** + * Parse a hex encoded geometry + */ + public Geometry parse(String value) + { + StringByteGetter bytes = new ByteGetter.StringByteGetter(value); + return parseGeometry(valueGetterForEndian(bytes)); + } + + /** + * Parse a binary encoded geometry. + */ + public Geometry parse(byte[] value) + { + BinaryByteGetter bytes = new ByteGetter.BinaryByteGetter(value); + return parseGeometry(valueGetterForEndian(bytes)); + } + + /** + * Parse a geometry starting at offset. + */ + protected Geometry parseGeometry(ValueGetter data) + { + return parseGeometry(data, 0, false); + } + + /** + * Parse with a known geometry factory + */ + protected Geometry parseGeometry(ValueGetter data, int srid, boolean inheritSrid) + { + byte endian = data.getByte(); // skip and test endian flag + if (endian != data.endian) + { + throw new IllegalArgumentException("Endian inconsistency!"); + } + int typeword = data.getInt(); + + int realtype = typeword & 0x1FFFFFFF; // cut off high flag bits + + boolean haveZ = (typeword & 0x80000000) != 0; + boolean haveM = (typeword & 0x40000000) != 0; + boolean haveS = (typeword & 0x20000000) != 0; + + if (haveS) + { + int newsrid = data.getInt(); + if (inheritSrid && newsrid != srid) + { + throw new IllegalArgumentException("Inconsistent srids in complex geometry: " + srid + ", " + newsrid); + } else + { + srid = newsrid; + } + } else if (!inheritSrid) + { + srid = -1; + } + + Geometry result; + switch (realtype) + { + case org.postgis.Geometry.POINT: + result = parsePoint(data, haveZ, haveM); + break; + case org.postgis.Geometry.LINESTRING: + result = parseLineString(data, haveZ, haveM); + break; + case org.postgis.Geometry.POLYGON: + result = parsePolygon(data, haveZ, haveM, srid); + break; + case org.postgis.Geometry.MULTIPOINT: + result = parseMultiPoint(data, srid); + break; + case org.postgis.Geometry.MULTILINESTRING: + result = parseMultiLineString(data, srid); + break; + case org.postgis.Geometry.MULTIPOLYGON: + result = parseMultiPolygon(data, srid); + break; + case org.postgis.Geometry.GEOMETRYCOLLECTION: + result = parseCollection(data, srid); + break; + default: + throw new IllegalArgumentException("Unknown Geometry Type!"); + } + + result.setSRID(srid); + + return result; + } + + private Point parsePoint(ValueGetter data, boolean haveZ, boolean haveM) + { + double X = data.getDouble(); + double Y = data.getDouble(); + Point result; + if (haveZ) + { + double Z = data.getDouble(); + result = JtsGeometry.geofac.createPoint(new Coordinate(X, Y, Z)); + } else + { + result = JtsGeometry.geofac.createPoint(new Coordinate(X, Y)); + } + + if (haveM) + { // skip M value + data.getDouble(); + } + + return result; + } + + /** + * Parse an Array of "full" Geometries + */ + private void parseGeometryArray(ValueGetter data, Geometry[] container, int srid) + { + for (int i = 0; i < container.length; i++) + { + container[i] = parseGeometry(data, srid, true); + } + } + + /** + * Parse an Array of "slim" Points (without endianness and type, part of + * LinearRing and Linestring, but not MultiPoint! + * + * @param haveZ + * @param haveM + */ + private CoordinateSequence parseCS(ValueGetter data, boolean haveZ, boolean haveM) + { + int count = data.getInt(); + int dims = haveZ ? 3 : 2; + CoordinateSequence cs = new PackedCoordinateSequence.Double(count, dims); + + for (int i = 0; i < count; i++) + { + for (int d = 0; d < dims; d++) + { + cs.setOrdinate(i, d, data.getDouble()); + } + if (haveM) + { // skip M value + data.getDouble(); + } + } + return cs; + } + + private MultiPoint parseMultiPoint(ValueGetter data, int srid) + { + Point[] points = new Point[data.getInt()]; + parseGeometryArray(data, points, srid); + return JtsGeometry.geofac.createMultiPoint(points); + } + + private LineString parseLineString(ValueGetter data, boolean haveZ, boolean haveM) + { + return JtsGeometry.geofac.createLineString(parseCS(data, haveZ, haveM)); + } + + private LinearRing parseLinearRing(ValueGetter data, boolean haveZ, boolean haveM) + { + return JtsGeometry.geofac.createLinearRing(parseCS(data, haveZ, haveM)); + } + + private Polygon parsePolygon(ValueGetter data, boolean haveZ, boolean haveM, int srid) + { + int holecount = data.getInt() - 1; + LinearRing[] rings = new LinearRing[holecount]; + LinearRing shell = parseLinearRing(data, haveZ, haveM); + shell.setSRID(srid); + for (int i = 0; i < holecount; i++) + { + rings[i] = parseLinearRing(data, haveZ, haveM); + rings[i].setSRID(srid); + } + return JtsGeometry.geofac.createPolygon(shell, rings); + } + + private MultiLineString parseMultiLineString(ValueGetter data, int srid) + { + int count = data.getInt(); + LineString[] strings = new LineString[count]; + parseGeometryArray(data, strings, srid); + return JtsGeometry.geofac.createMultiLineString(strings); + } + + private MultiPolygon parseMultiPolygon(ValueGetter data, int srid) + { + int count = data.getInt(); + Polygon[] polys = new Polygon[count]; + parseGeometryArray(data, polys, srid); + return JtsGeometry.geofac.createMultiPolygon(polys); + } + + private GeometryCollection parseCollection(ValueGetter data, int srid) + { + int count = data.getInt(); + Geometry[] geoms = new Geometry[count]; + parseGeometryArray(data, geoms, srid); + return JtsGeometry.geofac.createGeometryCollection(geoms); + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsBinaryWriter.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsBinaryWriter.java new file mode 100644 index 0000000..36a9d7b --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsBinaryWriter.java @@ -0,0 +1,469 @@ +/* + * JtsBinaryWriter.java + * + * PostGIS extension for PostgreSQL JDBC driver - Binary Writer + * + * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com + * + * 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, either 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. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA or visit the web at + * http://www.gnu.org. + * + * $Id$ + */ +package com.ximple.eofms.util.postjts; + +import org.postgis.binary.ByteSetter; +import org.postgis.binary.ValueSetter; + +import com.vividsolutions.jts.geom.CoordinateSequence; +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; + +/** + * Create binary representation of geometries. Currently, only text rep (hexed) + * implementation is tested. Supports only 2 dimensional geometries. + * <p/> + * It should be easy to add char[] and CharSequence ByteGetter instances, + * although the latter one is not compatible with older jdks. + * <p/> + * I did not implement real unsigned 32-bit integers or emulate them with long, + * as both java Arrays and Strings currently can have only 2^31-1 elements + * (bytes), so we cannot even get or build Geometries with more than approx. + * 2^28 coordinates (8 bytes each). + * + * @author markus.schaber@logi-track.com + */ +public class JtsBinaryWriter +{ + + /** + * Get the appropriate ValueGetter for my endianness + * + * @param bytes The appropriate Byte Getter + * @return the ValueGetter + */ + public static ValueSetter valueSetterForEndian(ByteSetter bytes, byte endian) + { + if (endian == ValueSetter.XDR.NUMBER) + { // XDR + return new ValueSetter.XDR(bytes); + } else if (endian == ValueSetter.NDR.NUMBER) + { + return new ValueSetter.NDR(bytes); + } else + { + throw new IllegalArgumentException("Unknown Endian type:" + endian); + } + } + + /** + * Write a hex encoded geometry + * <p/> + * Currently, geometries with more than 2 dimensions and measures are not + * cleanly supported, but SRID is honored. + */ + public String writeHexed(Geometry geom, byte REP) + { + int length = estimateBytes(geom); + ByteSetter.StringByteSetter bytes = new ByteSetter.StringByteSetter(length); + writeGeometry(geom, valueSetterForEndian(bytes, REP)); + return bytes.result(); + } + + public String writeHexed(Geometry geom) + { + return writeHexed(geom, ValueSetter.NDR.NUMBER); + } + + /** + * Write a binary encoded geometry. + * <p/> + * Currently, geometries with more than 2 dimensions and measures are not + * cleanly supported, but SRID is honored. + */ + public byte[] writeBinary(Geometry geom, byte REP) + { + int length = estimateBytes(geom); + ByteSetter.BinaryByteSetter bytes = new ByteSetter.BinaryByteSetter(length); + writeGeometry(geom, valueSetterForEndian(bytes, REP)); + return bytes.result(); + } + + public byte[] writeBinary(Geometry geom) + { + return writeBinary(geom, ValueSetter.NDR.NUMBER); + } + + /** + * Parse a geometry starting at offset. + */ + protected void writeGeometry(Geometry geom, ValueSetter dest) + { + final int dimension; + if (geom == null) + { + throw new NullPointerException(); + } else if (geom.isEmpty()) + { + // don't set any flag bits + dimension = 0; + } else + { + dimension = getCoordDim(geom); + if (dimension < 2 || dimension > 4) + { + throw new IllegalArgumentException("Unsupported geometry dimensionality: " + dimension); + } + } + // write endian flag + dest.setByte(dest.endian); + + // write typeword + final int plaintype = getWKBType(geom); + int typeword = plaintype; + if (dimension == 3 || dimension == 4) + { + typeword |= 0x80000000; + } + if (dimension == 4) + { + typeword |= 0x40000000; + } + + final boolean haveSrid = checkSrid(geom); + if (haveSrid) + { + typeword |= 0x20000000; + } + + dest.setInt(typeword); + + if (haveSrid) + { + dest.setInt(geom.getSRID()); + } + + switch (plaintype) + { + case org.postgis.Geometry.POINT: + writePoint((Point) geom, dest); + break; + case org.postgis.Geometry.LINESTRING: + writeLineString((LineString) geom, dest); + break; + case org.postgis.Geometry.POLYGON: + writePolygon((Polygon) geom, dest); + break; + case org.postgis.Geometry.MULTIPOINT: + writeMultiPoint((MultiPoint) geom, dest); + break; + case org.postgis.Geometry.MULTILINESTRING: + writeMultiLineString((MultiLineString) geom, dest); + break; + case org.postgis.Geometry.MULTIPOLYGON: + writeMultiPolygon((MultiPolygon) geom, dest); + break; + case org.postgis.Geometry.GEOMETRYCOLLECTION: + writeCollection((GeometryCollection) geom, dest); + break; + default: + throw new IllegalArgumentException("Unknown Geometry Type: " + plaintype); + } + } + + public static int getWKBType(Geometry geom) + { + // We always write emtpy geometries as emtpy collections - for OpenGIS + // conformance + if (geom.isEmpty()) + { + return org.postgis.Geometry.GEOMETRYCOLLECTION; + } else if (geom instanceof Point) + { + return org.postgis.Geometry.POINT; + } else if (geom instanceof com.vividsolutions.jts.geom.LineString) + { + return org.postgis.Geometry.LINESTRING; + } else if (geom instanceof com.vividsolutions.jts.geom.Polygon) + { + return org.postgis.Geometry.POLYGON; + } else if (geom instanceof MultiPoint) + { + return org.postgis.Geometry.MULTIPOINT; + } else if (geom instanceof MultiLineString) + { + return org.postgis.Geometry.MULTILINESTRING; + } else if (geom instanceof com.vividsolutions.jts.geom.MultiPolygon) + { + return org.postgis.Geometry.MULTIPOLYGON; + } + if (geom instanceof com.vividsolutions.jts.geom.GeometryCollection) + { + return org.postgis.Geometry.GEOMETRYCOLLECTION; + } else + { + throw new IllegalArgumentException("Unknown Geometry Type: " + geom.getClass().getName()); + } + } + + /** + * Writes a "slim" Point (without endiannes, srid ant type, only the + * ordinates and measure. Used by writeGeometry. + */ + private void writePoint(Point geom, ValueSetter dest) + { + writeCoordinates(geom.getCoordinateSequence(), getCoordDim(geom), dest); + } + + /** + * Write a Coordinatesequence, part of LinearRing and Linestring, but not + * MultiPoint! + */ + private void writeCoordinates(CoordinateSequence seq, int dims, ValueSetter dest) + { + for (int i = 0; i < seq.size(); i++) + { + for (int d = 0; d < dims; d++) + { + dest.setDouble(seq.getOrdinate(i, d)); + } + } + } + + private void writeMultiPoint(MultiPoint geom, ValueSetter dest) + { + dest.setInt(geom.getNumPoints()); + for (int i = 0; i < geom.getNumPoints(); i++) + { + writeGeometry(geom.getGeometryN(i), dest); + } + } + + private void writeLineString(LineString geom, ValueSetter dest) + { + dest.setInt(geom.getNumPoints()); + writeCoordinates(geom.getCoordinateSequence(), getCoordDim(geom), dest); + } + + private void writePolygon(Polygon geom, ValueSetter dest) + { + dest.setInt(geom.getNumInteriorRing() + 1); + writeLineString(geom.getExteriorRing(), dest); + for (int i = 0; i < geom.getNumInteriorRing(); i++) + { + writeLineString(geom.getInteriorRingN(i), dest); + } + } + + private void writeMultiLineString(MultiLineString geom, ValueSetter dest) + { + writeGeometryArray(geom, dest); + } + + private void writeMultiPolygon(MultiPolygon geom, ValueSetter dest) + { + writeGeometryArray(geom, dest); + } + + private void writeCollection(GeometryCollection geom, ValueSetter dest) + { + writeGeometryArray(geom, dest); + } + + private void writeGeometryArray(Geometry geom, ValueSetter dest) + { + dest.setInt(geom.getNumGeometries()); + for (int i = 0; i < geom.getNumGeometries(); i++) + { + writeGeometry(geom.getGeometryN(i), dest); + } + } + + /** + * Estimate how much bytes a geometry will need in WKB. + */ + protected int estimateBytes(Geometry geom) + { + int result = 0; + + // write endian flag + result += 1; + + // write typeword + result += 4; + + if (checkSrid(geom)) + { + result += 4; + } + + switch (getWKBType(geom)) + { + case org.postgis.Geometry.POINT: + result += estimatePoint((Point) geom); + break; + case org.postgis.Geometry.LINESTRING: + result += estimateLineString((LineString) geom); + break; + case org.postgis.Geometry.POLYGON: + result += estimatePolygon((Polygon) geom); + break; + case org.postgis.Geometry.MULTIPOINT: + result += estimateMultiPoint((MultiPoint) geom); + break; + case org.postgis.Geometry.MULTILINESTRING: + result += estimateMultiLineString((MultiLineString) geom); + break; + case org.postgis.Geometry.MULTIPOLYGON: + result += estimateMultiPolygon((MultiPolygon) geom); + break; + case org.postgis.Geometry.GEOMETRYCOLLECTION: + result += estimateCollection((GeometryCollection) geom); + break; + default: + throw new IllegalArgumentException("Unknown Geometry Type: " + getWKBType(geom)); + } + return result; + } + + private boolean checkSrid(Geometry geom) + { + final int srid = geom.getSRID(); + // SRID is default 0 with jts geometries + return (srid != -1) && (srid != 0); + } + + private int estimatePoint(Point geom) + { + return 8 * getCoordDim(geom); + } + + /** + * Write an Array of "full" Geometries + */ + private int estimateGeometryArray(Geometry container) + { + int result = 0; + for (int i = 0; i < container.getNumGeometries(); i++) + { + result += estimateBytes(container.getGeometryN(i)); + } + return result; + } + + /** + * Estimate an array of "fat" Points + */ + private int estimateMultiPoint(MultiPoint geom) + { + // int size + int result = 4; + if (geom.getNumGeometries() > 0) + { + // We can shortcut here, compared to estimateGeometryArray, as all + // subgeoms have the same fixed size + result += geom.getNumGeometries() * estimateBytes(geom.getGeometryN(0)); + } + return result; + } + + private int estimateLineString(LineString geom) + { + if (geom == null || geom.getNumGeometries() == 0) + { + return 0; + } else + { + return 4 + 8 * getCoordSequenceDim(geom.getCoordinateSequence()) * geom.getCoordinateSequence().size(); + } + } + + private int estimatePolygon(Polygon geom) + { + // int length + int result = 4; + result += estimateLineString(geom.getExteriorRing()); + for (int i = 0; i < geom.getNumInteriorRing(); i++) + { + result += estimateLineString(geom.getInteriorRingN(i)); + } + return result; + } + + private int estimateMultiLineString(MultiLineString geom) + { + // 4-byte count + subgeometries + return 4 + estimateGeometryArray(geom); + } + + private int estimateMultiPolygon(MultiPolygon geom) + { + // 4-byte count + subgeometries + return 4 + estimateGeometryArray(geom); + } + + private int estimateCollection(GeometryCollection geom) + { + // 4-byte count + subgeometries + return 4 + estimateGeometryArray(geom); + } + + public static final int getCoordDim(Geometry geom) + { + if (geom.isEmpty()) + { + return 0; + } + if (geom instanceof Point) + { + return getCoordSequenceDim(((Point) geom).getCoordinateSequence()); + } else if (geom instanceof LineString) + { + return getCoordSequenceDim(((LineString) geom).getCoordinateSequence()); + } else if (geom instanceof Polygon) + { + return getCoordSequenceDim(((Polygon) geom).getExteriorRing().getCoordinateSequence()); + } else + { + return getCoordDim(geom.getGeometryN(0)); + } + } + + public static final int getCoordSequenceDim(CoordinateSequence coords) + { + if (coords == null || coords.size() == 0) + return 0; + // JTS has a really strange way to handle dimensions! + // Just have a look at PackedCoordinateSequence and + // CoordinateArraySequence + int dimensions = coords.getDimension(); + if (dimensions == 3) + { + // CoordinateArraySequence will always return 3, so we have to + // check, if + // the third ordinate contains NaN, then the geom is actually + // 2-dimensional + return Double.isNaN(coords.getOrdinate(0, CoordinateSequence.Z)) ? 2 : 3; + } else + { + return dimensions; + } + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsGeometry.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsGeometry.java new file mode 100644 index 0000000..18a6295 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsGeometry.java @@ -0,0 +1,187 @@ +/* + * JtsGeometry.java + * + * Wrapper for PostgreSQL JDBC driver to allow transparent reading and writing + * of JTS geometries + * + * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com + * + * 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, either 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. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA or visit the web at + * http://www.gnu.org. + * + * $Id$ + */ + +package com.ximple.eofms.util.postjts; + +import java.sql.SQLException; + +import org.postgresql.util.PGobject; + +import com.vividsolutions.jts.geom.CoordinateSequenceFactory; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryCollection; +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.Polygon; +import com.vividsolutions.jts.geom.PrecisionModel; +import com.vividsolutions.jts.geom.impl.PackedCoordinateSequenceFactory; +import com.vividsolutions.jts.io.WKTReader; + +/** + * JTS Geometry SQL wrapper. Supports PostGIS 1.x (lwgeom hexwkb) for writing + * and both PostGIS 0.x (EWKT) and 1.x (lwgeom hexwkb) for reading. + * + * @author Markus Schaber + */ + +public class JtsGeometry extends PGobject +{ + /* JDK 1.5 Serialization */ + private static final long serialVersionUID = 0x100; + + Geometry geom; + + final static JtsBinaryParser bp = new JtsBinaryParser(); + + final static JtsBinaryWriter bw = new JtsBinaryWriter(); + + final static PrecisionModel prec = new PrecisionModel(); + + final static CoordinateSequenceFactory csfac = PackedCoordinateSequenceFactory.DOUBLE_FACTORY; + + final static GeometryFactory geofac = new GeometryFactory(prec, 0, csfac); + + static final WKTReader reader = new WKTReader(geofac); + + /** + * Constructor called by JDBC drivers + */ + public JtsGeometry() + { + setType("geometry"); + } + + public JtsGeometry(Geometry geom) + { + this(); + this.geom = geom; + } + + public JtsGeometry(String value) throws SQLException + { + this(); + setValue(value); + } + + public void setValue(String value) throws SQLException + { + geom = geomFromString(value); + } + + public static Geometry geomFromString(String value) throws SQLException + { + try + { + value = value.trim(); + if (value.startsWith("00") || value.startsWith("01")) + { + return bp.parse(value); + } else + { + Geometry result; + // no srid := 0 in JTS world + int srid = 0; + // break up geometry into srid and wkt + if (value.startsWith("SRID=")) + { + String[] temp = value.split(";"); + value = temp[1].trim(); + srid = Integer.parseInt(temp[0].substring(5)); + } + + result = reader.read(value); + setSridRecurse(result, srid); + return result; + } + } catch (Exception E) + { + E.printStackTrace(); + throw new SQLException("Error parsing SQL data:" + E); + } + } + + /** + * Recursively set a srid for the geometry and all subgeometries + */ + public static void setSridRecurse(final Geometry geom, final int srid) + { + geom.setSRID(srid); + if (geom instanceof GeometryCollection) + { + final int subcnt = geom.getNumGeometries(); + for (int i = 0; i < subcnt; i++) + { + setSridRecurse(geom.getGeometryN(i), srid); + } + } else if (geom instanceof Polygon) + { + Polygon poly = (Polygon) geom; + poly.getExteriorRing().setSRID(srid); + final int subcnt = poly.getNumInteriorRing(); + for (int i = 0; i < subcnt; i++) + { + poly.getInteriorRingN(i).setSRID(srid); + } + } + } + + public Geometry getGeometry() + { + return geom; + } + + public String toString() + { + return geom.toString(); + } + + public String getValue() + { + return bw.writeHexed(getGeometry()); + } + + public Object clone() + { + JtsGeometry obj = new JtsGeometry(geom); + obj.setType(type); + return obj; + } + + public boolean equals(Object obj) + { + if ((obj != null) && (obj instanceof JtsGeometry)) + { + Geometry other = ((JtsGeometry) obj).geom; + if (this.geom == other) + { // handles identity as well as both + // ==null + return true; + } else if (this.geom != null && other != null) + { + return other.equals(this.geom); + } + } + return false; + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsGisWrapper.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsGisWrapper.java new file mode 100644 index 0000000..1af43b4 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsGisWrapper.java @@ -0,0 +1,173 @@ +/* + * JtsWrapper.java + * + * Allows transparent usage of JTS Geometry classes via PostgreSQL JDBC driver + * connected to a PostGIS enabled PostgreSQL server. + * + * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com + * + * 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, either 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. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA or visit the web at + * http://www.gnu.org. + * + * $Id$ + */ + +package com.ximple.eofms.util.postjts; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Properties; + +import org.postgresql.Driver; +import org.postgresql.PGConnection; + +/** + * JtsGisWrapper + * <p/> + * Wraps the PostGreSQL Driver to add the JTS/PostGIS Object Classes. + * <p/> + * This method currently works with J2EE DataSource implementations, and with + * DriverManager framework. + * <p/> + * Simply replace the "jdbc:postgresql:" with a "jdbc:postgresql_JTS" in the + * jdbc URL. + * + * @author markus.schaber@logix-tt.com + */ +public class JtsGisWrapper extends Driver +{ + + private static final String POSTGRES_PROTOCOL = "jdbc:postgresql:"; + private static final String POSTGIS_PROTOCOL = "jdbc:postgresql_JTS:"; + public static final String REVISION = "$Revision: 1977 $"; + + public JtsGisWrapper() + { + super(); + } + + static + { + try + { + // Analogy to org.postgresql.Driver + java.sql.DriverManager.registerDriver(new JtsGisWrapper()); + } catch (SQLException e) + { + e.printStackTrace(); + } + } + + /** + * Creates a postgresql connection, and then adds the PostGIS data types to + * it calling addpgtypes() + * + * @param url the URL of the database to connect to + * @param info a list of arbitrary tag/value pairs as connection arguments + * @return a connection to the URL or null if it isnt us + * @throws SQLException if a database access error occurs + * @see java.sql.Driver#connect + * @see org.postgresql.Driver + */ + public java.sql.Connection connect(String url, Properties info) throws SQLException + { + url = mangleURL(url); + Connection result = super.connect(url, info); + addGISTypes((PGConnection) result); + return result; + } + + /** + * adds the JTS/PostGIS Data types to a PG Connection. + * + * @param pgconn + * @throws SQLException + */ + public static void addGISTypes(PGConnection pgconn) throws SQLException + { + pgconn.addDataType("geometry", JtsGeometry.class); + pgconn.addDataType("box3d", org.postgis.PGbox3d.class); + pgconn.addDataType("box2d", org.postgis.PGbox2d.class); + } + + /** + * Mangles the PostGIS URL to return the original PostGreSQL URL + * @param url url + * @return string + * @throws java.sql.SQLException error + */ + public static String mangleURL(String url) throws SQLException + { + if (url.startsWith(POSTGIS_PROTOCOL)) + { + return POSTGRES_PROTOCOL + url.substring(POSTGIS_PROTOCOL.length()); + } else + { + throw new SQLException("Unknown protocol or subprotocol in url " + url); + } + } + + /** + * Returns true if the driver thinks it can open a connection to the given + * URL. Typically, drivers will return true if they understand the + * subprotocol specified in the URL and false if they don't. Our protocols + * start with jdbc:postgresql_postGIS: + * + * @param url the URL of the driver + * @return true if this driver accepts the given URL + * @throws SQLException if a database-access error occurs (Dont know why + * it would *shrug*) + * @see java.sql.Driver#acceptsURL + */ + public boolean acceptsURL(String url) throws SQLException + { + try + { + url = mangleURL(url); + } catch (SQLException e) + { + return false; + } + return super.acceptsURL(url); + } + + /** + * Gets the underlying drivers major version number + * + * @return the drivers major version number + */ + + public int getMajorVersion() + { + return super.getMajorVersion(); + } + + /** + * Get the underlying drivers minor version number + * + * @return the drivers minor version number + */ + public int getMinorVersion() + { + return super.getMinorVersion(); + } + + /** + * Returns our own CVS version plus postgres Version + */ + public static String getVersion() + { + return "JtsGisWrapper " + REVISION + ", wrapping " + Driver.getVersion(); + } +} diff --git a/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsWrapper.java b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsWrapper.java new file mode 100644 index 0000000..b87f551 --- /dev/null +++ b/xdgnjobs/ximple-spatialjob/src/main/java/com/ximple/eofms/util/postjts/JtsWrapper.java @@ -0,0 +1,180 @@ +/* + * JtsWrapper.java + * + * Allows transparent usage of JTS Geometry classes via PostgreSQL JDBC driver + * connected to a PostGIS enabled PostgreSQL server. + * + * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com + * + * 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, either 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. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA or visit the web at + * http://www.gnu.org. + * + * $Id$ + */ + +package com.ximple.eofms.util.postjts; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.postgresql.Driver; +import org.postgresql.PGConnection; + +/** + * DriverWrapper + * <p/> + * Wraps the PostGreSQL Driver to add the JTS/PostGIS Object Classes. + * <p/> + * This method currently works with J2EE DataSource implementations, and with + * DriverManager framework. + * <p/> + * Simply replace the "jdbc:postgresql:" with a "jdbc:postgres_jts:" in the jdbc + * URL. + * <p/> + * When using the drivermanager, you need to initialize JtsWrapper instead of + * (or in addition to) org.postgresql.Driver. When using a J2EE DataSource + * implementation, set the driver class property in the datasource config, the + * following works for jboss: + * <p/> + * <driver-class>org.postgis.jts.PostGisWrapper</driver-class> + * + * @author markus.schaber@logix-tt.com + */ +public class JtsWrapper extends Driver +{ + + protected static final Logger logger = Logger.getLogger("org.postgis.DriverWrapper"); + + private static final String POSTGRES_PROTOCOL = "jdbc:postgresql:"; + private static final String POSTGIS_PROTOCOL = "jdbc:postgres_jts:"; + public static final String REVISION = "$Revision: 2570 $"; + + public JtsWrapper() + { + super(); + } + + static + { + try + { + // Try to register ourself to the DriverManager + java.sql.DriverManager.registerDriver(new JtsWrapper()); + } catch (SQLException e) + { + logger.log(Level.WARNING, "Error registering PostgreSQL Jts Wrapper Driver", e); + } + } + + /** + * Creates a postgresql connection, and then adds the JTS GIS data types to + * it calling addpgtypes() + * + * @param url the URL of the database to connect to + * @param info a list of arbitrary tag/value pairs as connection arguments + * @return a connection to the URL or null if it isnt us + * @throws SQLException if a database access error occurs + * @see java.sql.Driver#connect + * @see org.postgresql.Driver + */ + public java.sql.Connection connect(String url, Properties info) throws SQLException + { + url = mangleURL(url); + Connection result = super.connect(url, info); + addGISTypes((PGConnection) result); + return result; + } + + /** + * adds the JTS/PostGIS Data types to a PG Connection. + * + * @param pgconn postgres connection + * @throws SQLException error + */ + public static void addGISTypes(PGConnection pgconn) throws SQLException + { + pgconn.addDataType("geometry", JtsGeometry.class); + } + + /** + * Mangles the PostGIS URL to return the original PostGreSQL URL + * @param url url + * @return string + * @throws java.sql.SQLException erroe + */ + public static String mangleURL(String url) throws SQLException + { + if (url.startsWith(POSTGIS_PROTOCOL)) + { + return POSTGRES_PROTOCOL + url.substring(POSTGIS_PROTOCOL.length()); + } else + { + throw new SQLException("Unknown protocol or subprotocol in url " + url); + } + } + + /** + * Check whether the driver thinks he can handle the given URL. + * + * @param url the URL of the driver + * @return true if this driver accepts the given URL + * @throws SQLException Passed through from the underlying PostgreSQL + * driver, should not happen. + * @see java.sql.Driver#acceptsURL + */ + public boolean acceptsURL(String url) throws SQLException + { + try + { + url = mangleURL(url); + } catch (SQLException e) + { + return false; + } + return super.acceptsURL(url); + } + + /** + * Gets the underlying drivers major version number + * + * @return the drivers major version number + */ + + public int getMajorVersion() + { + return super.getMajorVersion(); + } + + /** + * Get the underlying drivers minor version number + * + * @return the drivers minor version number + */ + public int getMinorVersion() + { + return super.getMinorVersion(); + } + + /** + * Returns our own CVS version plus postgres Version + * @return version + */ + public static String getVersion() + { + return "JtsGisWrapper " + REVISION + ", wrapping " + Driver.getVersion(); + } +} -- Gitblit v0.0.0-SNAPSHOT