From 0c0a5e2af07f5b3863489935ffa52acbd7333887 Mon Sep 17 00:00:00 2001 From: Karel Maesen Date: Tue, 23 Aug 2011 14:05:50 +0200 Subject: [PATCH] HHH-6510 Added SQL Server 2008 support. Converts SQL Server convertor integration tests to proper unit tests. --- .../org/hibernate/type/BasicTypeRegistry.java | 3 +- hibernate-spatial/hibernate-spatial.gradle | 1 + ...r.java => GeometryJavaTypeDescriptor.java} | 6 +- ...or.java => GeometrySqlTypeDescriptor.java} | 11 +- .../org/hibernate/spatial/GeometryType.java | 2 +- .../dialect/oracle/OracleJDBCTypeFactory.java | 8 +- .../oracle/OracleSpatial10gDialect.java | 43 +- .../dialect/oracle/SQLTypeFactory.java | 20 + .../spatial/dialect/oracle/StructLoader.java | 20 - .../dialect/postgis/PostgisDialect.java | 28 +- .../sqlserver/SQLServerGeometryUserType.java | 81 +++ .../SqlServer2008GeometryTypeDescriptor.java | 38 ++ .../SqlServer2008GeometryValueBinder.java | 40 +- .../SqlServer2008GeometryValueExtractor.java | 51 +- .../SqlServer2008SpatialDialect.java | 179 +++++++ .../sqlserver/convertors/AbstractDecoder.java | 81 +++ .../sqlserver/convertors/AbstractEncoder.java | 108 ++++ .../AbstractGeometryCollectionDecoder.java | 79 +++ .../dialect/sqlserver/convertors/Decoder.java | 44 ++ .../sqlserver/convertors/Decoders.java | 97 ++++ .../dialect/sqlserver/convertors/Encoder.java | 42 ++ .../sqlserver/convertors/Encoders.java | 73 +++ .../dialect/sqlserver/convertors/Figure.java | 62 +++ .../sqlserver/convertors/FigureAttribute.java | 52 ++ .../convertors/GeometryCollectionDecoder.java | 57 +++ .../convertors/GeometryCollectionEncoder.java | 75 +++ .../sqlserver/convertors/IndexRange.java | 45 ++ .../convertors/LineStringDecoder.java | 80 +++ .../convertors/LineStringEncoder.java | 65 +++ .../convertors/MultiLineStringDecoder.java | 59 +++ .../convertors/MultiPointDecoder.java | 60 +++ .../convertors/MultiPointEncoder.java | 52 ++ .../convertors/MultiPolygonDecoder.java | 55 ++ .../sqlserver/convertors/OpenGisType.java | 73 +++ .../sqlserver/convertors/PointDecoder.java | 71 +++ .../sqlserver/convertors/PointEncoder.java | 111 ++++ .../sqlserver/convertors/PolygonDecoder.java | 81 +++ .../sqlserver/convertors/PolygonEncoder.java | 95 ++++ .../dialect/sqlserver/convertors/Shape.java | 50 ++ .../convertors/SqlServerGeometry.java | 480 ++++++++++++++++++ .../dialect/sqlserver/convertors/package.html | 13 + .../integration/SpatialIntegrator.java | 45 +- .../spatial/TestSupportFactories.java | 6 +- .../SQLServerExpressionTemplate.java | 49 ++ .../sqlserver/SQLServerTestSupport.java | 28 + .../SqlServerExpectationsFactory.java | 252 +++++++++ .../convertors/AbstractConvertorTest.java | 132 +++++ .../convertors/ConvertorTestData.java | 16 + .../GeometryCollectionConvertorTest.java | 56 ++ .../convertors/LineStringConvertorTest.java | 128 +++++ .../MultiLineStringConvertorTest.java | 49 ++ .../convertors/MultiPointConvertorTest.java | 49 ++ .../convertors/MultiPolygonConvertorTest.java | 49 ++ .../convertors/PointConvertorTest.java | 98 ++++ .../convertors/PolygonConvertorTest.java | 51 ++ .../convertors/SpatialObjectGenerator.java | 134 +++++ .../src/test/resources/hibernate.properties | 13 +- .../create-sqlserver-test-schema.sql | 15 + .../sqlserver/drop-sqlserver-test-schema.sql | 1 + ...ibernate-spatial-sqlserver-test.properties | 10 + .../sqlserver/sqlserver-2008-test-data.ser | Bin 0 -> 20258 bytes 61 files changed, 3797 insertions(+), 75 deletions(-) rename hibernate-spatial/src/main/java/org/hibernate/spatial/{SpatialGeometryJavaTypeDescriptor.java => GeometryJavaTypeDescriptor.java} (85%) rename hibernate-spatial/src/main/java/org/hibernate/spatial/{SpatialGeometrySqlTypeDescriptor.java => GeometrySqlTypeDescriptor.java} (70%) create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SQLTypeFactory.java delete mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/StructLoader.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SQLServerGeometryUserType.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SqlServer2008GeometryTypeDescriptor.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SqlServer2008SpatialDialect.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/AbstractDecoder.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/AbstractEncoder.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/AbstractGeometryCollectionDecoder.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/Decoder.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/Decoders.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/Encoder.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/Encoders.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/Figure.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/FigureAttribute.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/GeometryCollectionDecoder.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/GeometryCollectionEncoder.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/IndexRange.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/LineStringDecoder.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/LineStringEncoder.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/MultiLineStringDecoder.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/MultiPointDecoder.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/MultiPointEncoder.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/MultiPolygonDecoder.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/OpenGisType.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/PointDecoder.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/PointEncoder.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/PolygonDecoder.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/PolygonEncoder.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/Shape.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/SqlServerGeometry.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/package.html create mode 100644 hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/SQLServerExpressionTemplate.java create mode 100644 hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/SQLServerTestSupport.java create mode 100644 hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/SqlServerExpectationsFactory.java create mode 100644 hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/AbstractConvertorTest.java create mode 100644 hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/ConvertorTestData.java create mode 100644 hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/GeometryCollectionConvertorTest.java create mode 100644 hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/LineStringConvertorTest.java create mode 100644 hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/MultiLineStringConvertorTest.java create mode 100644 hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/MultiPointConvertorTest.java create mode 100644 hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/MultiPolygonConvertorTest.java create mode 100644 hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/PointConvertorTest.java create mode 100644 hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/PolygonConvertorTest.java create mode 100644 hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/SpatialObjectGenerator.java create mode 100644 hibernate-spatial/src/test/resources/sqlserver/create-sqlserver-test-schema.sql create mode 100644 hibernate-spatial/src/test/resources/sqlserver/drop-sqlserver-test-schema.sql create mode 100644 hibernate-spatial/src/test/resources/sqlserver/hibernate-spatial-sqlserver-test.properties create mode 100644 hibernate-spatial/src/test/resources/sqlserver/sqlserver-2008-test-data.ser diff --git a/hibernate-core/src/main/java/org/hibernate/type/BasicTypeRegistry.java b/hibernate-core/src/main/java/org/hibernate/type/BasicTypeRegistry.java index 3ac4046885..c2d5859c5a 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/BasicTypeRegistry.java +++ b/hibernate-core/src/main/java/org/hibernate/type/BasicTypeRegistry.java @@ -127,8 +127,7 @@ public class BasicTypeRegistry implements Serializable { @SuppressWarnings({ "UnusedDeclaration" }) private BasicTypeRegistry(Map registeredTypes) { registry.putAll( registeredTypes ); - //TODO - this is just a temporary work-around! -// locked = true; + locked = true; } public void register(BasicType type) { diff --git a/hibernate-spatial/hibernate-spatial.gradle b/hibernate-spatial/hibernate-spatial.gradle index 6f806d9382..20addb8c08 100644 --- a/hibernate-spatial/hibernate-spatial.gradle +++ b/hibernate-spatial/hibernate-spatial.gradle @@ -21,6 +21,7 @@ dependencies { testCompile( project(':hibernate-testing') ) testCompile( [group: 'commons-dbcp', name: 'commons-dbcp', version: '1.4']) testCompile([group: 'com.oracle.jdbc', name:'ojdbc6', version:'11.1.0.7.0']) + testCompile([group: 'com.microsoft', name: 'sqljdbc', version: '2.0']) } sourceSets { diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/SpatialGeometryJavaTypeDescriptor.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/GeometryJavaTypeDescriptor.java similarity index 85% rename from hibernate-spatial/src/main/java/org/hibernate/spatial/SpatialGeometryJavaTypeDescriptor.java rename to hibernate-spatial/src/main/java/org/hibernate/spatial/GeometryJavaTypeDescriptor.java index 6f540930ca..3c92def594 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/SpatialGeometryJavaTypeDescriptor.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/GeometryJavaTypeDescriptor.java @@ -12,12 +12,12 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor; * @author Karel Maesen, Geovise BVBA * creation-date: 7/27/11 */ -public class SpatialGeometryJavaTypeDescriptor extends AbstractTypeDescriptor { +public class GeometryJavaTypeDescriptor extends AbstractTypeDescriptor { - public static final JavaTypeDescriptor INSTANCE = new SpatialGeometryJavaTypeDescriptor( Geometry.class ); + public static final JavaTypeDescriptor INSTANCE = new GeometryJavaTypeDescriptor( Geometry.class ); - protected SpatialGeometryJavaTypeDescriptor(Class type) { + protected GeometryJavaTypeDescriptor(Class type) { super( type ); } diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/SpatialGeometrySqlTypeDescriptor.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/GeometrySqlTypeDescriptor.java similarity index 70% rename from hibernate-spatial/src/main/java/org/hibernate/spatial/SpatialGeometrySqlTypeDescriptor.java rename to hibernate-spatial/src/main/java/org/hibernate/spatial/GeometrySqlTypeDescriptor.java index b00aab823b..53691c54a4 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/SpatialGeometrySqlTypeDescriptor.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/GeometrySqlTypeDescriptor.java @@ -1,7 +1,5 @@ package org.hibernate.spatial; -import java.sql.Types; - import org.hibernate.type.descriptor.ValueBinder; import org.hibernate.type.descriptor.ValueExtractor; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; @@ -14,16 +12,13 @@ import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; * @author Karel Maesen, Geovise BVBA * creation-date: 7/27/11 */ -public class SpatialGeometrySqlTypeDescriptor implements SqlTypeDescriptor { +public class GeometrySqlTypeDescriptor implements SqlTypeDescriptor { - public static final SpatialGeometrySqlTypeDescriptor INSTANCE = new SpatialGeometrySqlTypeDescriptor(); + public static final GeometrySqlTypeDescriptor INSTANCE = new GeometrySqlTypeDescriptor(); @Override public int getSqlType() { - return Types.STRUCT; //this works only for postgis! - //sqltype remapping issue: HHH-6074 needs to be resolved first. -// return Types.OTHER; - + return 3000; //this value doesn't conflict with presently defined java.sql.Types values. } @Override diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/GeometryType.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/GeometryType.java index 6251213ca8..7923aee9be 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/GeometryType.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/GeometryType.java @@ -56,7 +56,7 @@ public class GeometryType extends AbstractSingleColumnStandardBasicTypeGEOMETRY. + * + * + * @param code The {@link java.sql.Types} typecode + * @param length The datatype length + * @param precision The datatype precision + * @param scale The datatype scale + * @return + * @throws HibernateException + */ + @Override + public String getTypeName(int code, long length, int precision, int scale) throws HibernateException { + if (code == 3000 ) return "GEOMETRY"; + return super.getTypeName(code, length, precision, scale); + } + + @Override public SqlTypeDescriptor remapSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) { - if ( sqlTypeDescriptor instanceof SpatialGeometrySqlTypeDescriptor ) { + if ( sqlTypeDescriptor instanceof GeometrySqlTypeDescriptor) { return PGGeometryTypeDescriptor.INSTANCE; } return super.remapSqlTypeDescriptor( sqlTypeDescriptor ); diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SQLServerGeometryUserType.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SQLServerGeometryUserType.java new file mode 100644 index 0000000000..5a1752208f --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SQLServerGeometryUserType.java @@ -0,0 +1,81 @@ +///* +// * $Id: SQLServerGeometryUserType.java 302 2011-05-07 18:23:11Z maesenka $ +// * +// * This file is part of Hibernate Spatial, an extension to the +// * hibernate ORM solution for geographic data. +// * +// * Copyright © 2007-2010 Geovise BVBA +// * +// * 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, or (at your option) any later version. +// * +// * 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 +// * +// * For more information, visit: http://www.hibernatespatial.org/ +// */ +// +//package org.hibernatespatial.sqlserver; +// +//import java.sql.Blob; +//import java.sql.Connection; +//import java.sql.SQLException; +//import java.sql.Types; +// +//import com.vividsolutions.jts.geom.Geometry; +//import org.hibernatespatial.AbstractDBGeometryType; +//import org.hibernatespatial.sqlserver.convertors.Decoders; +//import org.hibernatespatial.sqlserver.convertors.Encoders; +// +///** +// * The GeometryUserType for Microsoft SQL Server (2008). +// * +// * @author Karel Maesen, Geovise BVBA. +// */ +//public class SQLServerGeometryUserType extends AbstractDBGeometryType { +// +// public Geometry convert2JTS(Object obj) { +// byte[] raw = null; +// if ( obj == null ) { +// return null; +// } +// if ( ( obj instanceof byte[] ) ) { +// raw = (byte[]) obj; +// } +// else if ( obj instanceof Blob ) { +// raw = toByteArray( (Blob) obj ); +// } +// else { +// throw new IllegalArgumentException( "Expected byte array." ); +// } +// return Decoders.decode( raw ); +// } +// +// private byte[] toByteArray(Blob blob) { +// try { +// return blob.getBytes( 1, (int) blob.length() ); +// } +// catch ( SQLException e ) { +// throw new RuntimeException( "Error on transforming blob into array.", e ); +// } +// } +// +// public Object conv2DBGeometry(Geometry geom, Connection connection) { +// if ( geom == null ) { +// throw new IllegalArgumentException( "Null geometry passed." ); +// } +// return Encoders.encode( geom ); +// } +// +// public int[] sqlTypes() { +// return new int[] { Types.ARRAY }; +// } +//} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SqlServer2008GeometryTypeDescriptor.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SqlServer2008GeometryTypeDescriptor.java new file mode 100644 index 0000000000..3fadeaaf27 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SqlServer2008GeometryTypeDescriptor.java @@ -0,0 +1,38 @@ +package org.hibernate.spatial.dialect.sqlserver; + +import java.sql.Types; + +import org.hibernate.type.descriptor.ValueBinder; +import org.hibernate.type.descriptor.ValueExtractor; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; +import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; + +/** + * @author Karel Maesen, Geovise BVBA + * creation-date: 8/23/11 + */ +public class SqlServer2008GeometryTypeDescriptor implements SqlTypeDescriptor { + + public static final SqlTypeDescriptor INSTANCE = new SqlServer2008GeometryTypeDescriptor(); + + @Override + public int getSqlType() { + return Types.ARRAY; + } + + @Override + public boolean canBeRemapped() { + return false; + } + + @Override + public ValueBinder getBinder(final JavaTypeDescriptor javaTypeDescriptor) { + return (ValueBinder) new SqlServer2008GeometryValueBinder(); + } + + @Override + public ValueExtractor getExtractor(final JavaTypeDescriptor javaTypeDescriptor) { + return (ValueExtractor) new SqlServer2008GeometryValueExtractor(); + } + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SqlServer2008GeometryValueBinder.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SqlServer2008GeometryValueBinder.java index 424bdb01a4..fc4c563030 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SqlServer2008GeometryValueBinder.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SqlServer2008GeometryValueBinder.java @@ -1,8 +1,46 @@ package org.hibernate.spatial.dialect.sqlserver; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Types; + +import com.vividsolutions.jts.geom.Geometry; + +import org.hibernate.spatial.HBSpatialExtension; +import org.hibernate.spatial.dialect.sqlserver.convertors.Encoders; +import org.hibernate.spatial.mgeom.MGeometryFactory; +import org.hibernate.type.descriptor.ValueBinder; +import org.hibernate.type.descriptor.WrapperOptions; + /** * @author Karel Maesen, Geovise BVBA * creation-date: 8/23/11 */ -public class SqlServer2008GeometryValueBinder { +public class SqlServer2008GeometryValueBinder implements ValueBinder { + + + @Override + public void bind(PreparedStatement st, Geometry value, int index, WrapperOptions options) throws SQLException { + if ( value == null ) { + st.setNull( index, Types.STRUCT ); + } + else { + Geometry jtsGeom = (Geometry) value; + Object dbGeom = toNative( jtsGeom, st.getConnection() ); + st.setObject( index, dbGeom ); + } + } + + public MGeometryFactory getGeometryFactory() { + return HBSpatialExtension.getDefaultGeomFactory(); + } + + public Object toNative(Geometry geom, Connection connection) { + if ( geom == null ) { + throw new IllegalArgumentException( "Null geometry passed." ); + } + return Encoders.encode( geom ); + } + } diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SqlServer2008GeometryValueExtractor.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SqlServer2008GeometryValueExtractor.java index 1342c54995..ba769d6501 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SqlServer2008GeometryValueExtractor.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SqlServer2008GeometryValueExtractor.java @@ -1,8 +1,57 @@ package org.hibernate.spatial.dialect.sqlserver; +import java.sql.Blob; +import java.sql.ResultSet; +import java.sql.SQLException; + +import com.vividsolutions.jts.geom.Geometry; + +import org.hibernate.spatial.HBSpatialExtension; +import org.hibernate.spatial.dialect.sqlserver.convertors.Decoders; +import org.hibernate.spatial.mgeom.MGeometryFactory; +import org.hibernate.type.descriptor.ValueExtractor; +import org.hibernate.type.descriptor.WrapperOptions; + /** * @author Karel Maesen, Geovise BVBA * creation-date: 8/23/11 */ -public class SqlServer2008GeometryValueExtractor { +public class SqlServer2008GeometryValueExtractor implements ValueExtractor { + + @Override + public Geometry extract(ResultSet rs, String name, WrapperOptions options) throws SQLException { + Object geomObj = rs.getObject( name ); + return toJTS( geomObj ); + } + + public MGeometryFactory getGeometryFactory() { + return HBSpatialExtension.getDefaultGeomFactory(); + } + + public Geometry toJTS(Object obj) { + byte[] raw = null; + if ( obj == null ) { + return null; + } + if ( ( obj instanceof byte[] ) ) { + raw = (byte[]) obj; + } + else if ( obj instanceof Blob ) { + raw = toByteArray( (Blob) obj ); + } + else { + throw new IllegalArgumentException( "Expected byte array." ); + } + return Decoders.decode( raw ); + } + + private byte[] toByteArray(Blob blob) { + try { + return blob.getBytes( 1, (int) blob.length() ); + } + catch ( SQLException e ) { + throw new RuntimeException( "Error on transforming blob into array.", e ); + } + } + } diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SqlServer2008SpatialDialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SqlServer2008SpatialDialect.java new file mode 100644 index 0000000000..c8e98c107c --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SqlServer2008SpatialDialect.java @@ -0,0 +1,179 @@ +/* + * $Id: SQLServerSpatialDialect.java 302 2011-05-07 18:23:11Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2009 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver; + + +import org.hibernate.dialect.SQLServer2008Dialect; +import org.hibernate.dialect.function.SQLFunctionTemplate; +import org.hibernate.spatial.GeometryType; +import org.hibernate.spatial.SpatialDialect; +import org.hibernate.spatial.SpatialFunction; +import org.hibernate.spatial.GeometrySqlTypeDescriptor; +import org.hibernate.spatial.SpatialRelation; +import org.hibernate.type.StandardBasicTypes; +import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; + +/** + * The SpatialDialect for Microsoft SQL Server (2008). + * + * @author Karel Maesen, Martin Steinwender. + */ +public class SqlServer2008SpatialDialect extends SQLServer2008Dialect implements SpatialDialect { + + public final static String SHORT_NAME = "sqlserver"; + + public final static String COLUMN_TYPE = "GEOMETRY"; + + public SqlServer2008SpatialDialect() { + super(); + registerColumnType( java.sql.Types.ARRAY, COLUMN_TYPE ); + + // registering OGC functions + // (spec_simplefeatures_sql_99-04.pdf) + + // section 2.1.1.1 + // Registerfunction calls for registering geometry functions: + // first argument is the OGC standard functionname, + // second the Function as it occurs in the spatial dialect + registerFunction( "dimension", new SQLFunctionTemplate( StandardBasicTypes.INTEGER, "?1.STDimension()" ) ); + registerFunction( "geometrytype", new SQLFunctionTemplate( StandardBasicTypes.STRING, "?1.STGeometryType()" ) ); + registerFunction( "srid", new SQLFunctionTemplate( StandardBasicTypes.INTEGER, "?1.STSrid" ) ); + registerFunction( "envelope", new SQLFunctionTemplate( GeometryType.INSTANCE, "?1.STEnvelope()" ) ); + registerFunction( "astext", new SQLFunctionTemplate( StandardBasicTypes.STRING, "?1.STAsText()" ) ); + registerFunction( "asbinary", new SQLFunctionTemplate( StandardBasicTypes.BINARY, "?1.STAsBinary()" ) ); + + registerFunction( "isempty", new SQLFunctionTemplate( StandardBasicTypes.BOOLEAN, "?1.STIsEmpty()" ) ); + registerFunction( "issimple", new SQLFunctionTemplate( StandardBasicTypes.BOOLEAN, "?1.STIsSimple()" ) ); + registerFunction( "boundary", new SQLFunctionTemplate( GeometryType.INSTANCE, "?1.STBoundary()" ) ); + + // section 2.1.1.2 + // Register functions for spatial relation constructs + registerFunction( "contains", new SQLFunctionTemplate( StandardBasicTypes.BOOLEAN, "?1.STContains(?2)" ) ); + registerFunction( "crosses", new SQLFunctionTemplate( StandardBasicTypes.BOOLEAN, "?1.STCrosses(?2)" ) ); + registerFunction( "disjoint", new SQLFunctionTemplate( StandardBasicTypes.BOOLEAN, "?1.STDisjoint(?2)" ) ); + registerFunction( "equals", new SQLFunctionTemplate( StandardBasicTypes.BOOLEAN, "?1.STEquals(?2)" ) ); + registerFunction( "intersects", new SQLFunctionTemplate( StandardBasicTypes.BOOLEAN, "?1.STIntersects(?2)" ) ); + registerFunction( "overlaps", new SQLFunctionTemplate( StandardBasicTypes.BOOLEAN, "?1.STOverlaps(?2)" ) ); + registerFunction( "touches", new SQLFunctionTemplate( StandardBasicTypes.BOOLEAN, "?1.STTouches(?2)" ) ); + registerFunction( "within", new SQLFunctionTemplate( StandardBasicTypes.BOOLEAN, "?1.STWithin(?2)" ) ); + registerFunction( "relate", new SQLFunctionTemplate( StandardBasicTypes.BOOLEAN, "?1.STRelate(?2,?3)" ) ); + + // section 2.1.1.3 + // Register spatial analysis functions. + registerFunction( "distance", new SQLFunctionTemplate( StandardBasicTypes.DOUBLE, "?1.STDistance(?2)" ) ); + registerFunction( "buffer", new SQLFunctionTemplate( GeometryType.INSTANCE, "?1.STBuffer(?2)" ) ); + registerFunction( "convexhull", new SQLFunctionTemplate( GeometryType.INSTANCE, "?1.STConvexHull()" ) ); + registerFunction( "difference", new SQLFunctionTemplate( GeometryType.INSTANCE, "?1.STDifference(?2)" ) ); + registerFunction( "intersection", new SQLFunctionTemplate( GeometryType.INSTANCE, "?1.STIntersection(?2)" ) ); + registerFunction( "symdifference", new SQLFunctionTemplate( GeometryType.INSTANCE, "?1.STSymDifference(?2)" ) ); + registerFunction( "geomunion", new SQLFunctionTemplate( GeometryType.INSTANCE, "?1.STUnion(?2)" ) ); + // we rename OGC union to geomunion because union is a reserved SQL keyword. + // (See also postgis documentation). + + // portable spatial aggregate functions + // no aggregatefunctions implemented in sql-server2000 + //registerFunction("extent", new SQLFunctionTemplate(geomType, "?1.STExtent()")); + + // section 2.1.9.1 methods on surfaces + registerFunction( "area", new SQLFunctionTemplate( StandardBasicTypes.DOUBLE, "?1.STArea()" ) ); + registerFunction( "centroid", new SQLFunctionTemplate( GeometryType.INSTANCE, "?1.STCentroid()" ) ); + registerFunction( "pointonsurface", new SQLFunctionTemplate( GeometryType.INSTANCE, "?1.STPointOnSurface()" ) ); + } + + @Override + public SqlTypeDescriptor remapSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) { + if ( sqlTypeDescriptor instanceof GeometrySqlTypeDescriptor) { + return SqlServer2008GeometryTypeDescriptor.INSTANCE; + } + return super.remapSqlTypeDescriptor( sqlTypeDescriptor ); + } + + public String getSpatialRelateSQL(String columnName, int spatialRelation) { + final String stfunction; + switch ( spatialRelation ) { + case SpatialRelation.WITHIN: + stfunction = "STWithin"; + break; + case SpatialRelation.CONTAINS: + stfunction = "STContains"; + break; + case SpatialRelation.CROSSES: + stfunction = "STCrosses"; + break; + case SpatialRelation.OVERLAPS: + stfunction = "STOverlaps"; + break; + case SpatialRelation.DISJOINT: + stfunction = "STDisjoint"; + break; + case SpatialRelation.INTERSECTS: + stfunction = "STIntersects"; + break; + case SpatialRelation.TOUCHES: + stfunction = "STTouches"; + break; + case SpatialRelation.EQUALS: + stfunction = "STEquals"; + break; + default: + throw new IllegalArgumentException( + "Spatial relation is not known by this dialect" + ); + } + + return columnName + "." + stfunction + "(?) = 1"; + } + + public String getSpatialFilterExpression(String columnName) { + return columnName + ".Filter(?) = 1"; + } + + public String getSpatialAggregateSQL(String columnName, int aggregation) { + throw new UnsupportedOperationException( "No spatial aggregate SQL functions." ); + } + + public String getDWithinSQL(String columnName) { + throw new UnsupportedOperationException( "SQL Server has no DWithin function." ); + } + + + public String getHavingSridSQL(String columnName) { + return columnName + ".STSrid = (?)"; + } + + public String getIsEmptySQL(String columnName, boolean isEmpty) { + String base = "(" + columnName + ".STIsEmpty() "; + return isEmpty ? base + " = 1 )" : base + " = 0 )"; + } + + public boolean supportsFiltering() { + return true; + } + + public boolean supports(SpatialFunction function) { + return ( getFunctions().get( function.toString() ) != null ); + } +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/AbstractDecoder.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/AbstractDecoder.java new file mode 100644 index 0000000000..14c01d2df6 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/AbstractDecoder.java @@ -0,0 +1,81 @@ +/* + * $Id: AbstractDecoder.java 163 2010-03-08 22:29:37Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007-2010 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +import com.vividsolutions.jts.geom.Geometry; + +import org.hibernate.spatial.mgeom.MGeometryFactory; + +abstract class AbstractDecoder implements Decoder { + + private final MGeometryFactory geometryFactory; + + public AbstractDecoder(MGeometryFactory factory) { + this.geometryFactory = factory; + } + + public G decode(SqlServerGeometry nativeGeom) { + if ( !accepts( nativeGeom ) ) { + throw new IllegalArgumentException( getClass().getSimpleName() + " received object of type " + nativeGeom.openGisType() ); + } + if ( nativeGeom.isEmpty() ) { + G nullGeom = createNullGeometry(); + setSrid( nativeGeom, nullGeom ); + return nullGeom; + } + G result = createGeometry( nativeGeom ); + setSrid( nativeGeom, result ); + return result; + } + + public boolean accepts(OpenGisType type) { + return type == getOpenGisType(); + } + + public boolean accepts(SqlServerGeometry nativeGeom) { + return accepts( nativeGeom.openGisType() ); + } + + protected abstract OpenGisType getOpenGisType(); + + protected abstract G createNullGeometry(); + + protected abstract G createGeometry(SqlServerGeometry nativeGeom); + + protected abstract G createGeometry(SqlServerGeometry nativeGeom, int shapeIndex); + + protected MGeometryFactory getGeometryFactory() { + return this.geometryFactory; + } + + protected void setSrid(SqlServerGeometry sqlServerGeom, G result) { + if ( sqlServerGeom.getSrid() != null ) { + result.setSRID( sqlServerGeom.getSrid() ); + } + } + + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/AbstractEncoder.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/AbstractEncoder.java new file mode 100644 index 0000000000..a7e9e8a538 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/AbstractEncoder.java @@ -0,0 +1,108 @@ +/* + * $Id: AbstractEncoder.java 162 2010-03-07 21:21:38Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2009 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +import java.util.ArrayList; +import java.util.List; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Geometry; + +import org.hibernate.spatial.mgeom.MGeometry; + + +abstract class AbstractEncoder implements Encoder { + + public SqlServerGeometry encode(G geom) { + SqlServerGeometry nativeGeom = new SqlServerGeometry(); + nativeGeom.setSrid( geom.getSRID() ); + if ( geom.isValid() ) { + nativeGeom.setIsValid(); + } + + if ( hasMValues( geom ) ) { + nativeGeom.setHasMValues(); + } + + List coordinates = new ArrayList(); + List
figures = new ArrayList
(); + List shapes = new ArrayList(); + + encode( geom, -1, coordinates, figures, shapes ); + encodePoints( nativeGeom, coordinates ); + encodeFigures( nativeGeom, figures ); + encodeShapes( nativeGeom, shapes ); + return nativeGeom; + } + + /** + * Appends the points, figures, shapes to the resp. lists + * + * @param geom geometry to serialization + * @param parentShapeIndex index of the parent Shape for the geometry + * @param coordinates coordinate list to append to + * @param figures figure list to append to + * @param shapes shape list to append to + */ + protected abstract void encode(Geometry geom, int parentShapeIndex, List coordinates, List
figures, List shapes); + + protected void encodeShapes(SqlServerGeometry nativeGeom, List shapes) { + nativeGeom.setNumberOfShapes( shapes.size() ); + for ( int i = 0; i < shapes.size(); i++ ) { + nativeGeom.setShape( i, shapes.get( i ) ); + } + } + + protected void encodeFigures(SqlServerGeometry nativeGeom, List
figures) { + nativeGeom.setNumberOfFigures( figures.size() ); + for ( int i = 0; i < figures.size(); i++ ) { + nativeGeom.setFigure( i, figures.get( i ) ); + } + } + + protected boolean hasMValues(G geom) { + return geom instanceof MGeometry; + } + + + protected void encodePoints(SqlServerGeometry nativeGeom, List coordinates) { + nativeGeom.setNumberOfPoints( coordinates.size() ); + nativeGeom.allocateMValueArray(); + for ( int i = 0; i < coordinates.size(); i++ ) { + setCoordinate( nativeGeom, i, coordinates.get( i ) ); + } + } + + protected void setCoordinate(SqlServerGeometry nativeGeom, int idx, Coordinate coordinate) { + if ( !nativeGeom.hasZValues() && !Double.isNaN( coordinate.z ) ) { + nativeGeom.setHasZValues(); + nativeGeom.allocateZValueArray(); + } + + nativeGeom.setCoordinate( idx, coordinate ); + } + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/AbstractGeometryCollectionDecoder.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/AbstractGeometryCollectionDecoder.java new file mode 100644 index 0000000000..b9950e4b84 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/AbstractGeometryCollectionDecoder.java @@ -0,0 +1,79 @@ +/* + * $Id:$ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007-2010 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +import java.util.ArrayList; +import java.util.List; + +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryCollection; + +import org.hibernate.spatial.mgeom.MGeometryFactory; + +abstract class AbstractGeometryCollectionDecoder extends AbstractDecoder { + + public AbstractGeometryCollectionDecoder(MGeometryFactory factory) { + super( factory ); + } + + @Override + protected OpenGisType getOpenGisType() { + return OpenGisType.GEOMETRYCOLLECTION; + } + + @Override + protected T createNullGeometry() { + return createGeometry( (List) null, false ); + } + + @Override + protected T createGeometry(SqlServerGeometry nativeGeom) { + return createGeometry( nativeGeom, 0 ); + } + + @Override + protected T createGeometry(SqlServerGeometry nativeGeom, int shapeIndex) { + int startChildIdx = shapeIndex + 1; + List geometries = new ArrayList( nativeGeom.getNumShapes() ); + for ( int childIdx = startChildIdx; childIdx < nativeGeom.getNumShapes(); childIdx++ ) { + if ( !nativeGeom.isParentShapeOf( shapeIndex, childIdx ) ) { + continue; + } + AbstractDecoder decoder = (AbstractDecoder) Decoders.decoderFor( + nativeGeom.getOpenGisTypeOfShape( + childIdx + ) + ); + Geometry geometry = decoder.createGeometry( nativeGeom, childIdx ); + geometries.add( geometry ); + } + return createGeometry( geometries, nativeGeom.hasMValues() ); + } + + abstract protected T createGeometry(List geometries, boolean hasM); + + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/Decoder.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/Decoder.java new file mode 100644 index 0000000000..3b0fe296e8 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/Decoder.java @@ -0,0 +1,44 @@ +/* + * $Id: Decoder.java 201 2010-04-05 13:49:25Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2009 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +import com.vividsolutions.jts.geom.Geometry; + +/** + * Decodes native database objects to geometries of type T. + * + * @author Karel Maesen, Geovise BVBA. + */ +public interface Decoder { + + public T decode(SqlServerGeometry nativeGeom); + + public boolean accepts(SqlServerGeometry nativeGeom); + + public boolean accepts(OpenGisType type); + + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/Decoders.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/Decoders.java new file mode 100644 index 0000000000..fb8a41eeb2 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/Decoders.java @@ -0,0 +1,97 @@ +/* + * $Id: Decoders.java 201 2010-04-05 13:49:25Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007-2010 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +import java.util.ArrayList; +import java.util.List; + +import com.vividsolutions.jts.geom.Geometry; + +import org.hibernate.spatial.HBSpatialExtension; +import org.hibernate.spatial.mgeom.MGeometryFactory; + +/** + * Decodes SQL Server Geometry objects to JTS Geometrys. + * + * @author Karel Maesen, Geovise BVBA. + */ +public class Decoders { + + final private static List> DECODERS = new ArrayList>(); + + static { + MGeometryFactory factory = HBSpatialExtension.getDefaultGeomFactory(); + + //Decoders + DECODERS.add( new PointDecoder( factory ) ); + DECODERS.add( new LineStringDecoder( factory ) ); + DECODERS.add( new PolygonDecoder( factory ) ); + DECODERS.add( new MultiLineStringDecoder( factory ) ); + DECODERS.add( new MultiPolygonDecoder( factory ) ); + DECODERS.add( new MultiPointDecoder( factory ) ); + DECODERS.add( new GeometryCollectionDecoder( factory ) ); + } + + + private static Decoder decoderFor(SqlServerGeometry object) { + for ( Decoder decoder : DECODERS ) { + if ( decoder.accepts( object ) ) { + return decoder; + } + } + throw new IllegalArgumentException( "No decoder for type " + object.openGisType() ); + } + + /** + * Decodes the SQL Server Geometry object to its JTS Geometry instance + * + * @param raw + * + * @return + */ + public static Geometry decode(byte[] raw) { + SqlServerGeometry sqlServerGeom = SqlServerGeometry.deserialize( raw ); + Decoder decoder = decoderFor( sqlServerGeom ); + return decoder.decode( sqlServerGeom ); + } + + /** + * Returns the decoder capable of decoding an object of the specified OpenGisType + * + * @param type OpenGisType for which a decoder is returned + * + * @return + */ + public static Decoder decoderFor(OpenGisType type) { + for ( Decoder decoder : DECODERS ) { + if ( decoder.accepts( type ) ) { + return decoder; + } + } + throw new IllegalArgumentException( "No decoder for type " + type ); + } + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/Encoder.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/Encoder.java new file mode 100644 index 0000000000..55356291fb --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/Encoder.java @@ -0,0 +1,42 @@ +/* + * $Id: Encoder.java 201 2010-04-05 13:49:25Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2009 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +import com.vividsolutions.jts.geom.Geometry; + +/** + * An Encoder can encode + * geometries of type T to a SqlServerGeometry. + * + * @author Karel Maesen, Geovise BVBA. + */ +public interface Encoder { + + public SqlServerGeometry encode(T geom); + + public boolean accepts(Geometry geom); + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/Encoders.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/Encoders.java new file mode 100644 index 0000000000..ec0635a8fa --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/Encoders.java @@ -0,0 +1,73 @@ +/* + * $Id: Encoders.java 201 2010-04-05 13:49:25Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2009 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +import java.util.ArrayList; +import java.util.List; + +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryCollection; +import com.vividsolutions.jts.geom.MultiLineString; +import com.vividsolutions.jts.geom.MultiPolygon; + +/** + * Serializes a JTS Geometry to a byte-array. + * + * @author Karel Maesen, Geovise BVBA. + */ +public class Encoders { + + final private static List> ENCODERS = new ArrayList>(); + + + static { + //Encoders + ENCODERS.add( new PointEncoder() ); + ENCODERS.add( new LineStringEncoder() ); + ENCODERS.add( new PolygonEncoder() ); + ENCODERS.add( new MultiPointEncoder() ); + ENCODERS.add( new GeometryCollectionEncoder( OpenGisType.MULTILINESTRING ) ); + ENCODERS.add( new GeometryCollectionEncoder( OpenGisType.MULTIPOLYGON ) ); + ENCODERS.add( new GeometryCollectionEncoder( OpenGisType.GEOMETRYCOLLECTION ) ); + + } + + public static Encoder encoderFor(Geometry geom) { + for ( Encoder encoder : ENCODERS ) { + if ( encoder.accepts( geom ) ) { + return encoder; + } + } + throw new IllegalArgumentException( "No encoder for type " + geom.getGeometryType() ); + } + + public static byte[] encode(T geom) { + Encoder encoder = (Encoder) encoderFor( geom ); + SqlServerGeometry sqlServerGeometry = encoder.encode( geom ); + return SqlServerGeometry.serialize( sqlServerGeometry ); + } + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/Figure.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/Figure.java new file mode 100644 index 0000000000..48e4cc520f --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/Figure.java @@ -0,0 +1,62 @@ +/* + * $Id: Figure.java 156 2010-01-28 22:59:30Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2009 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +import java.nio.ByteBuffer; + +class Figure { + + + final FigureAttribute figureAttribute; + final int pointOffset; + + Figure(FigureAttribute attribute, int offset) { + this.figureAttribute = attribute; + this.pointOffset = offset; + } + + static int getByteSize() { + return 5; + } + + void store(ByteBuffer buffer) { + buffer.put( figureAttribute.byteValue ); + buffer.putInt( pointOffset ); + } + + boolean isInteriorRing() { + return this.figureAttribute.equals( FigureAttribute.InteriorRing ); + } + + boolean isExteriorRing() { + return this.figureAttribute.equals( FigureAttribute.ExteriorRing ); + } + + boolean isStroke() { + return this.figureAttribute.equals( FigureAttribute.Stroke ); + } + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/FigureAttribute.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/FigureAttribute.java new file mode 100644 index 0000000000..2d17616597 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/FigureAttribute.java @@ -0,0 +1,52 @@ +/* + * $Id: FigureAttribute.java 155 2010-01-13 21:00:35Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2009 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +/** + * @author Karel Maesen, Geovise BVBA + * @Date 2009-11-29 + */ +enum FigureAttribute { + InteriorRing( (byte) 0 ), + Stroke( (byte) 1 ), + ExteriorRing( (byte) 2 ); + + final byte byteValue; + + FigureAttribute(byte v) { + byteValue = v; + } + + static FigureAttribute valueOf(byte b) { + for ( FigureAttribute fa : values() ) { + if ( fa.byteValue == b ) { + return fa; + } + } + throw new IllegalArgumentException( String.format( "Can't interpret value %d as FigureAttribute.", b ) ); + } +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/GeometryCollectionDecoder.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/GeometryCollectionDecoder.java new file mode 100644 index 0000000000..9b93c18cfe --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/GeometryCollectionDecoder.java @@ -0,0 +1,57 @@ +/* + * $Id:$ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007-2010 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +import java.util.List; + +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryCollection; + +import org.hibernate.spatial.mgeom.MGeometryFactory; + +/** + * Decoder for GeometryCollections. + * + * @Author Karel Maesen + */ +class GeometryCollectionDecoder extends AbstractGeometryCollectionDecoder { + + public GeometryCollectionDecoder(MGeometryFactory factory) { + super( factory ); + } + + @Override + protected OpenGisType getOpenGisType() { + return OpenGisType.GEOMETRYCOLLECTION; + } + + protected GeometryCollection createGeometry(List geometries, boolean hasM) { + Geometry[] geomArray = geometries != null ? geometries.toArray( new Geometry[geometries.size()] ) : null; + return getGeometryFactory().createGeometryCollection( geomArray ); + } + + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/GeometryCollectionEncoder.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/GeometryCollectionEncoder.java new file mode 100644 index 0000000000..3929db7fc5 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/GeometryCollectionEncoder.java @@ -0,0 +1,75 @@ +/* + * $Id:$ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2009 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +import java.util.List; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryCollection; + +/** + * Encoder for GeometryCollections. + * + * @Author Karel Maesen + */ +class GeometryCollectionEncoder extends AbstractEncoder { + + private final OpenGisType openGisType; + + GeometryCollectionEncoder(OpenGisType openGisType) { + this.openGisType = openGisType; + } + + public boolean accepts(Geometry geom) { + return this.openGisType.typeOf( geom ); + } + + @Override + protected void encode(Geometry geom, int parentShapeIndex, List coordinates, List
figures, List shapes) { + if ( geom.isEmpty() ) { + shapes.add( new Shape( parentShapeIndex, -1, this.openGisType ) ); + return; + } + int thisShapeIndex = shapes.size(); + Shape thisShape = createShape( parentShapeIndex, figures ); + shapes.add( thisShape ); + for ( int i = 0; i < geom.getNumGeometries(); i++ ) { + Geometry component = geom.getGeometryN( i ); + encodeComponent( component, thisShapeIndex, coordinates, figures, shapes ); + } + } + + protected Shape createShape(int parentShapeIndex, List
figures) { + Shape thisShape = new Shape( parentShapeIndex, figures.size(), this.openGisType ); + return thisShape; + } + + protected void encodeComponent(Geometry geom, int thisShapeIndex, List coordinates, List
figures, List shapes) { + AbstractEncoder encoder = (AbstractEncoder) Encoders.encoderFor( geom ); + encoder.encode( geom, thisShapeIndex, coordinates, figures, shapes ); + } +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/IndexRange.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/IndexRange.java new file mode 100644 index 0000000000..bd495d9b77 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/IndexRange.java @@ -0,0 +1,45 @@ +/* + * $Id:$ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007-2010 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +/** + * A Range of indices. + */ +class IndexRange { + + final int start; + final int end; + + IndexRange(int start, int end) { + this.start = start; + this.end = end; + } + + int length() { + return this.end - this.start; + } + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/LineStringDecoder.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/LineStringDecoder.java new file mode 100644 index 0000000000..d630d3abf6 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/LineStringDecoder.java @@ -0,0 +1,80 @@ +/* + * $Id: LineStringDecoder.java 163 2010-03-08 22:29:37Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007-2010 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.CoordinateSequence; +import com.vividsolutions.jts.geom.LineString; + +import org.hibernate.spatial.mgeom.MCoordinate; +import org.hibernate.spatial.mgeom.MGeometryFactory; + +class LineStringDecoder extends AbstractDecoder { + + public LineStringDecoder(MGeometryFactory factory) { + super( factory ); + } + + @Override + protected OpenGisType getOpenGisType() { + return OpenGisType.LINESTRING; + } + + protected LineString createNullGeometry() { + return getGeometryFactory().createLineString( (CoordinateSequence) null ); + } + + protected LineString createGeometry(SqlServerGeometry nativeGeom) { + return createLineString( nativeGeom, new IndexRange( 0, nativeGeom.getNumPoints() ) ); + } + + @Override + protected LineString createGeometry(SqlServerGeometry nativeGeom, int shapeIndex) { + if ( nativeGeom.isEmptyShape( shapeIndex ) ) { + return createNullGeometry(); + } + int figureOffset = nativeGeom.getFiguresForShape( shapeIndex ).start; + IndexRange pntIndexRange = nativeGeom.getPointsForFigure( figureOffset ); + return createLineString( nativeGeom, pntIndexRange ); + } + + protected LineString createLineString(SqlServerGeometry nativeGeom, IndexRange pntIndexRange) { + Coordinate[] coordinates = nativeGeom.coordinateRange( pntIndexRange ); + return createLineString( coordinates, nativeGeom.hasMValues() ); + } + + private LineString createLineString(Coordinate[] coords, boolean hasM) { + if ( hasM ) { + return getGeometryFactory().createMLineString( (MCoordinate[]) coords ); + } + else { + return getGeometryFactory().createLineString( coords ); + } + + } + + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/LineStringEncoder.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/LineStringEncoder.java new file mode 100644 index 0000000000..5fa3edc555 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/LineStringEncoder.java @@ -0,0 +1,65 @@ +/* + * $Id: LineStringEncoder.java 162 2010-03-07 21:21:38Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2009 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +import java.util.List; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.LineString; + +class LineStringEncoder extends AbstractEncoder { + + @Override + protected void encode(Geometry geom, int parentShapeIndex, List coordinates, List
figures, List shapes) { + if ( !( geom instanceof LineString ) ) { + throw new IllegalArgumentException( "Require LineString geometry" ); + } + if ( geom.isEmpty() ) { + shapes.add( new Shape( parentShapeIndex, -1, OpenGisType.LINESTRING ) ); + return; + } + int figureOffset = figures.size(); + int pointOffset = coordinates.size(); + for ( Coordinate coordinate : geom.getCoordinates() ) { + coordinates.add( coordinate ); + } + figures.add( new Figure( FigureAttribute.Stroke, pointOffset ) ); + shapes.add( new Shape( parentShapeIndex, figureOffset, OpenGisType.LINESTRING ) ); + } + + @Override + protected void encodePoints(SqlServerGeometry nativeGeom, List coordinates) { + super.encodePoints( nativeGeom, coordinates ); + if ( coordinates.size() == 2 ) { + nativeGeom.setIsSingleLineSegment(); + } + } + + public boolean accepts(Geometry geom) { + return geom instanceof LineString; + } +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/MultiLineStringDecoder.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/MultiLineStringDecoder.java new file mode 100644 index 0000000000..93d4197d0a --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/MultiLineStringDecoder.java @@ -0,0 +1,59 @@ +/* + * $Id: MultiLineStringDecoder.java 201 2010-04-05 13:49:25Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007-2010 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +import java.util.List; + +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.LineString; +import com.vividsolutions.jts.geom.MultiLineString; + +import org.hibernate.spatial.mgeom.MGeometryFactory; +import org.hibernate.spatial.mgeom.MLineString; + +class MultiLineStringDecoder extends AbstractGeometryCollectionDecoder { + + public MultiLineStringDecoder(MGeometryFactory factory) { + super( factory ); + } + + @Override + protected OpenGisType getOpenGisType() { + return OpenGisType.MULTILINESTRING; + } + + + @Override + protected MultiLineString createGeometry(List geometries, boolean hasM) { + if ( hasM ) { + MLineString[] mlAr = geometries != null ? geometries.toArray( new MLineString[geometries.size()] ) : null; + return getGeometryFactory().createMultiMLineString( mlAr ); + } + LineString[] lAr = geometries != null ? geometries.toArray( new LineString[geometries.size()] ) : null; + return getGeometryFactory().createMultiLineString( lAr ); + } + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/MultiPointDecoder.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/MultiPointDecoder.java new file mode 100644 index 0000000000..c64dec893d --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/MultiPointDecoder.java @@ -0,0 +1,60 @@ +/* + * $Id: MultiPointDecoder.java 201 2010-04-05 13:49:25Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007-2010 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +import java.util.List; + +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.MultiPoint; +import com.vividsolutions.jts.geom.Point; + +import org.hibernate.spatial.mgeom.MGeometryFactory; + +/** + * Decoder for GeometryCollections. + * + * @author Karel Maesen, Geovise BVBA + */ + +class MultiPointDecoder extends AbstractGeometryCollectionDecoder { + + public MultiPointDecoder(MGeometryFactory factory) { + super( factory ); + } + + + @Override + protected OpenGisType getOpenGisType() { + return OpenGisType.MULTIPOINT; + } + + @Override + protected MultiPoint createGeometry(List geometries, boolean hasM) { + Point[] points = geometries != null ? geometries.toArray( new Point[geometries.size()] ) : null; + return getGeometryFactory().createMultiPoint( points ); + } + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/MultiPointEncoder.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/MultiPointEncoder.java new file mode 100644 index 0000000000..3fe80a6ed0 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/MultiPointEncoder.java @@ -0,0 +1,52 @@ +/* + * $Id:$ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007-2010 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.MultiPoint; + +import org.hibernate.spatial.mgeom.MCoordinate; + + +class MultiPointEncoder extends GeometryCollectionEncoder { + + public MultiPointEncoder() { + super( OpenGisType.MULTIPOINT ); + } + + @Override + protected boolean hasMValues(MultiPoint geom) { + for ( Coordinate c : geom.getCoordinates() ) { + if ( !( c instanceof MCoordinate ) ) { + return false; + } + if ( !Double.isNaN( ( (MCoordinate) c ).m ) ) { + return true; + } + } + return false; + } +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/MultiPolygonDecoder.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/MultiPolygonDecoder.java new file mode 100644 index 0000000000..602132ea98 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/MultiPolygonDecoder.java @@ -0,0 +1,55 @@ +/* + * $Id: MultiPolygonDecoder.java 201 2010-04-05 13:49:25Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007-2010 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +import java.util.List; + +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.MultiPolygon; +import com.vividsolutions.jts.geom.Polygon; + +import org.hibernate.spatial.mgeom.MGeometryFactory; + +class MultiPolygonDecoder extends AbstractGeometryCollectionDecoder { + + public MultiPolygonDecoder(MGeometryFactory factory) { + super( factory ); + } + + + @Override + protected OpenGisType getOpenGisType() { + return OpenGisType.MULTIPOLYGON; + } + + @Override + protected MultiPolygon createGeometry(List geometries, boolean hasM) { + Polygon[] polygons = geometries != null ? geometries.toArray( new Polygon[geometries.size()] ) : null; + return getGeometryFactory().createMultiPolygon( polygons ); + } + + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/OpenGisType.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/OpenGisType.java new file mode 100644 index 0000000000..c57723b4a0 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/OpenGisType.java @@ -0,0 +1,73 @@ +/* + * $Id: OpenGisType.java 201 2010-04-05 13:49:25Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2009 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +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; + +/** + * The type of geometry. + * + * @author Karel Maesen, Geovise BVBA. + * Date: Nov 2, 2009 + */ +public enum OpenGisType { + POINT( (byte) 1, Point.class ), + LINESTRING( (byte) 2, LineString.class ), + POLYGON( (byte) 3, Polygon.class ), + MULTIPOINT( (byte) 4, MultiPoint.class ), + MULTILINESTRING( (byte) 5, MultiLineString.class ), + MULTIPOLYGON( (byte) 6, MultiPolygon.class ), + GEOMETRYCOLLECTION( (byte) 7, GeometryCollection.class ), + INVALID_TYPE( (byte) 0, null ); + + final byte byteValue; + final Class geomClass; + + OpenGisType(byte v, Class geomClass) { + this.byteValue = v; + this.geomClass = geomClass; + } + + boolean typeOf(Object o) { + return geomClass.isAssignableFrom( o.getClass() ); + } + + static OpenGisType valueOf(byte b) { + for ( OpenGisType t : values() ) { + if ( t.byteValue == b ) { + return t; + } + } + return INVALID_TYPE; + } + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/PointDecoder.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/PointDecoder.java new file mode 100644 index 0000000000..646105a675 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/PointDecoder.java @@ -0,0 +1,71 @@ +/* + * $Id: PointDecoder.java 163 2010-03-08 22:29:37Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007-2010 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Point; + +import org.hibernate.spatial.mgeom.MGeometryFactory; + +/** + * @author Karel Maesen, Geovise BVBA. + * Date: Nov 2, 2009 + */ +class PointDecoder extends AbstractDecoder { + + public PointDecoder(MGeometryFactory factory) { + super( factory ); + } + + @Override + protected OpenGisType getOpenGisType() { + return OpenGisType.POINT; + } + + protected Point createNullGeometry() { + return getGeometryFactory().createPoint( (Coordinate) null ); + } + + protected Point createGeometry(SqlServerGeometry nativeGeom) { + return createPoint( nativeGeom, 0 ); + } + + @Override + protected Point createGeometry(SqlServerGeometry nativeGeom, int shapeIndex) { + if ( nativeGeom.isEmptyShape( shapeIndex ) ) { + return createNullGeometry(); + } + int figureOffset = nativeGeom.getFiguresForShape( shapeIndex ).start; + int pntOffset = nativeGeom.getPointsForFigure( figureOffset ).start; + return createPoint( nativeGeom, pntOffset ); + } + + private Point createPoint(SqlServerGeometry nativeGeom, int pntOffset) { + return getGeometryFactory().createPoint( nativeGeom.getCoordinate( pntOffset ) ); + } + + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/PointEncoder.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/PointEncoder.java new file mode 100644 index 0000000000..5e6379dac5 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/PointEncoder.java @@ -0,0 +1,111 @@ +/* + * $Id: PointEncoder.java 278 2010-12-18 14:03:32Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007-2010 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +import java.util.List; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.Point; + +import org.hibernate.spatial.mgeom.MCoordinate; + +/** + * @author Karel Maesen, Geovise BVBA. + * Date: Nov 2, 2009 + */ +class PointEncoder extends AbstractEncoder { + + /** + * Encodes a point as an SQLGeometryV1 object. + *

+ * This is a specific implementation because points don't explicitly serialize figure and shape components. + * + * @param geom Geometry to serialize + * + * @return + */ + @Override + public SqlServerGeometry encode(Point geom) { + + SqlServerGeometry sqlServerGeom = new SqlServerGeometry(); + sqlServerGeom.setSrid( geom.getSRID() ); + sqlServerGeom.setIsValid(); + + if ( geom.isEmpty() ) { + sqlServerGeom.setNumberOfPoints( 0 ); + sqlServerGeom.setNumberOfFigures( 0 ); + sqlServerGeom.setNumberOfShapes( 1 ); + sqlServerGeom.setShape( 0, new Shape( -1, -1, OpenGisType.POINT ) ); + return sqlServerGeom; + } + + sqlServerGeom.setIsSinglePoint(); + sqlServerGeom.setNumberOfPoints( 1 ); + Coordinate coordinate = geom.getCoordinate(); + if ( is3DPoint( coordinate ) ) { + sqlServerGeom.setHasZValues(); + sqlServerGeom.allocateZValueArray(); + } + if ( isMPoint( coordinate ) ) { + sqlServerGeom.setHasMValues(); + sqlServerGeom.allocateMValueArray(); + } + sqlServerGeom.setCoordinate( 0, coordinate ); + return sqlServerGeom; + } + + @Override + protected void encode(Geometry geom, int parentIdx, List coordinates, List

figures, List shapes) { + if ( !( geom instanceof Point ) ) { + throw new IllegalArgumentException( "Require Point geometry" ); + } + if ( geom.isEmpty() ) { + shapes.add( new Shape( parentIdx, -1, OpenGisType.POINT ) ); + return; + } + int pntOffset = coordinates.size(); + int figureOffset = figures.size(); + coordinates.add( geom.getCoordinate() ); + Figure figure = new Figure( FigureAttribute.Stroke, pntOffset ); + figures.add( figure ); + Shape shape = new Shape( parentIdx, figureOffset, OpenGisType.POINT ); + shapes.add( shape ); + } + + private boolean isMPoint(Coordinate coordinate) { + return ( coordinate instanceof MCoordinate ) && + !Double.isNaN( ( (MCoordinate) coordinate ).m ); + } + + private boolean is3DPoint(Coordinate coordinate) { + return !Double.isNaN( coordinate.z ); + } + + public boolean accepts(Geometry geom) { + return geom instanceof Point; + } +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/PolygonDecoder.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/PolygonDecoder.java new file mode 100644 index 0000000000..98696a6bab --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/PolygonDecoder.java @@ -0,0 +1,81 @@ +/* + * $Id: PolygonDecoder.java 201 2010-04-05 13:49:25Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007-2010 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.LinearRing; +import com.vividsolutions.jts.geom.Polygon; + +import org.hibernate.spatial.mgeom.MGeometryFactory; + +/** + * @author Karel Maesen, Geovise BVBA + */ +class PolygonDecoder extends AbstractDecoder { + + public PolygonDecoder(MGeometryFactory factory) { + super( factory ); + } + + @Override + protected OpenGisType getOpenGisType() { + return OpenGisType.POLYGON; + } + + protected Polygon createNullGeometry() { + return getGeometryFactory().createPolygon( null, null ); + } + + protected Polygon createGeometry(SqlServerGeometry nativeGeom) { + return createGeometry( nativeGeom, 0 ); + } + + protected Polygon createGeometry(SqlServerGeometry nativeGeom, int shapeIndex) { + if ( nativeGeom.isEmptyShape( shapeIndex ) ) { + return createNullGeometry(); + } + //polygons consist of one exterior ring figure, and several interior ones. + IndexRange figureRange = nativeGeom.getFiguresForShape( shapeIndex ); + LinearRing[] holes = new LinearRing[figureRange.length() - 1]; + LinearRing shell = null; + for ( int figureIdx = figureRange.start, i = 0; figureIdx < figureRange.end; figureIdx++ ) { + IndexRange pntIndexRange = nativeGeom.getPointsForFigure( figureIdx ); + if ( nativeGeom.isFigureInteriorRing( figureIdx ) ) { + holes[i++] = toLinearRing( nativeGeom, pntIndexRange ); + } + else { + shell = toLinearRing( nativeGeom, pntIndexRange ); + } + } + return getGeometryFactory().createPolygon( shell, holes ); + } + + private LinearRing toLinearRing(SqlServerGeometry nativeGeom, IndexRange range) { + Coordinate[] coordinates = nativeGeom.coordinateRange( range ); + return getGeometryFactory().createLinearRing( coordinates ); + } + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/PolygonEncoder.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/PolygonEncoder.java new file mode 100644 index 0000000000..1dad70c0c8 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/PolygonEncoder.java @@ -0,0 +1,95 @@ +/* + * $Id: PolygonEncoder.java 201 2010-04-05 13:49:25Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007-2010 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +import java.util.List; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.LineString; +import com.vividsolutions.jts.geom.Polygon; + +/** + * Encoder for Polygons. + * + * @uthor Karel Maesen, Geovise BVBA + */ +class PolygonEncoder extends AbstractEncoder { + + public boolean accepts(Geometry geom) { + return geom instanceof Polygon; + } + + @Override + protected void encode(Geometry geom, int parentShapeIndex, List coordinates, List
figures, List shapes) { + if ( !( geom instanceof Polygon ) ) { + throw new IllegalArgumentException( "Polygon geometry expected." ); + } + if ( geom.isEmpty() ) { + shapes.add( new Shape( parentShapeIndex, -1, OpenGisType.POLYGON ) ); + return; + } + Polygon polygon = (Polygon) geom; + int figureOffset = figures.size(); + shapes.add( new Shape( parentShapeIndex, figureOffset, OpenGisType.POLYGON ) ); + + int pointOffset = coordinates.size(); + addExteriorRing( polygon, coordinates, figures ); + addInteriorRings( polygon, coordinates, figures ); + + } + + + private void addInteriorRings(Polygon geom, List coordinates, List
figures) { + for ( int idx = 0; idx < geom.getNumInteriorRing(); idx++ ) { + addInteriorRing( geom.getInteriorRingN( idx ), coordinates, figures ); + } + } + + private void addInteriorRing(LineString ring, List coordinates, List
figures) { + int pointOffset = coordinates.size(); + addPoints( ring, coordinates ); + Figure figure = new Figure( FigureAttribute.InteriorRing, pointOffset ); + figures.add( figure ); + + } + + private void addPoints(LineString ring, List coordinates) { + for ( Coordinate c : ring.getCoordinates() ) { + coordinates.add( c ); + } + } + + private void addExteriorRing(Polygon geom, List coordinates, List
figures) { + LineString shell = geom.getExteriorRing(); + int offset = coordinates.size(); + addPoints( shell, coordinates ); + Figure exterior = new Figure( FigureAttribute.ExteriorRing, offset ); + figures.add( exterior ); + } + + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/Shape.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/Shape.java new file mode 100644 index 0000000000..f8cecbcfdc --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/Shape.java @@ -0,0 +1,50 @@ +/* + * $Id: Shape.java 155 2010-01-13 21:00:35Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2009 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +import java.nio.ByteBuffer; + +class Shape { + final int parentOffset; + final int figureOffset; + final OpenGisType openGisType; + + Shape(int parentOffset, int figureOffset, OpenGisType openGisType) { + this.figureOffset = figureOffset; + this.parentOffset = parentOffset; + this.openGisType = openGisType; + } + + static int getByteSize() { + return 9; + } + + void store(ByteBuffer buffer) { + buffer.putInt( parentOffset ); + buffer.putInt( figureOffset ); + buffer.put( openGisType.byteValue ); + } +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/SqlServerGeometry.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/SqlServerGeometry.java new file mode 100644 index 0000000000..1f1af5d41e --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/SqlServerGeometry.java @@ -0,0 +1,480 @@ +/* + * $Id: SqlServerGeometry.java 201 2010-04-05 13:49:25Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007-2010 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +import com.vividsolutions.jts.geom.Coordinate; + +import org.hibernate.spatial.mgeom.MCoordinate; + +/** + * A SqlServerGeometry represents the native SQL Server database object. + *

+ *

Instances are created by deserializing the byte array returned in the JDBC result set. + * They present the structure of the SQL Server Geometry object as specified in Microsoft SQL Server CLR Types Serialization Formats . + * + * @author Karel Maesen, Geovise BVBA. + */ +public class SqlServerGeometry { + + public static final byte SUPPORTED_VERSION = 1; + + private static final byte hasZValuesMask = 1; + private static final byte hasMValuesMask = 2; + private static final byte isValidMask = 4; + private static final byte isSinglePointMask = 8; + private static final byte isSingleLineSegment = 16; + + private ByteBuffer buffer; + private Integer srid; + private byte version; + private byte serializationPropertiesByte; + private int numberOfPoints; + private double[] points; + private double[] mValues; + private double[] zValues; + private int numberOfFigures; + private Figure[] figures = null; + private int numberOfShapes; + private Shape[] shapes = null; + + + private SqlServerGeometry(byte[] bytes) { + buffer = ByteBuffer.wrap( bytes ); + buffer.order( ByteOrder.LITTLE_ENDIAN ); + } + + SqlServerGeometry() { + } + + + public static byte[] serialize(SqlServerGeometry sqlServerGeom) { + int capacity = sqlServerGeom.calculateCapacity(); + ByteBuffer buffer = ByteBuffer.allocate( capacity ); + buffer.order( ByteOrder.LITTLE_ENDIAN ); + buffer.putInt( sqlServerGeom.srid ); + buffer.put( SUPPORTED_VERSION ); + buffer.put( sqlServerGeom.serializationPropertiesByte ); + if ( !sqlServerGeom.isSinglePoint() && !sqlServerGeom.isSingleLineSegment() ) { + buffer.putInt( sqlServerGeom.numberOfPoints ); + } + for ( int i = 0; i < sqlServerGeom.getNumPoints(); i++ ) { + buffer.putDouble( sqlServerGeom.points[2 * i] ); + buffer.putDouble( sqlServerGeom.points[2 * i + 1] ); + } + if ( sqlServerGeom.hasZValues() ) { + for ( int i = 0; i < sqlServerGeom.zValues.length; i++ ) { + buffer.putDouble( sqlServerGeom.zValues[i] ); + } + } + if ( sqlServerGeom.hasMValues() ) { + for ( int i = 0; i < sqlServerGeom.mValues.length; i++ ) { + buffer.putDouble( sqlServerGeom.mValues[i] ); + } + } + if ( sqlServerGeom.isSingleLineSegment() || sqlServerGeom.isSinglePoint() ) { + return buffer.array(); + } + + //in all other cases, we continue to serialize shapes and figures + buffer.putInt( sqlServerGeom.getNumFigures() ); + for ( int i = 0; i < sqlServerGeom.getNumFigures(); i++ ) { + sqlServerGeom.getFigure( i ).store( buffer ); + } + + buffer.putInt( sqlServerGeom.getNumShapes() ); + for ( int i = 0; i < sqlServerGeom.getNumShapes(); i++ ) { + sqlServerGeom.getShape( i ).store( buffer ); + } + + return buffer.array(); + } + + public static SqlServerGeometry deserialize(byte[] bytes) { + SqlServerGeometry result = new SqlServerGeometry( bytes ); + result.parse(); + return result; + } + + Coordinate getCoordinate(int index) { + Coordinate coordinate; + if ( hasMValues() ) { + coordinate = new MCoordinate(); + ( (MCoordinate) coordinate ).m = mValues[index]; + } + else { + coordinate = new Coordinate(); + } + coordinate.x = points[2 * index]; + coordinate.y = points[2 * index + 1]; + if ( hasZValues() ) { + coordinate.z = zValues[index]; + } + return coordinate; + } + + boolean isParentShapeOf(int parent, int child) { + return getShape( child ).parentOffset == parent; + } + + boolean isEmptyShape(int shapeIndex) { + return getShape( shapeIndex ).figureOffset == -1; + } + + IndexRange getFiguresForShape(int shapeIndex) { + int startIdx = getShape( shapeIndex ).figureOffset; + if ( startIdx == -1 ) { + return new IndexRange( -1, -1 ); //empty figures + } + int endIdx = -1; + int nextShapeIdx = shapeIndex + 1; + if ( nextShapeIdx == getNumShapes() ) { + endIdx = getNumFigures(); + } + else { + endIdx = getShape( nextShapeIdx ).figureOffset; + } + return new IndexRange( startIdx, endIdx ); + } + + /** + * Returns the range of indices in the point array for the specified figure. + * + * @param figureIndex index to shape in shape array + * + * @return index range for + */ + IndexRange getPointsForFigure(int figureIndex) { + int start = getFigure( figureIndex ).pointOffset; + int end = -1; + int nextFigure = figureIndex + 1; + if ( nextFigure == getNumFigures() ) { + end = getNumPoints(); + } + else { + end = getFigure( nextFigure ).pointOffset; + } + return new IndexRange( start, end ); + } + + boolean isFigureInteriorRing(int figureIdx) { + return getFigure( figureIdx ).isInteriorRing(); + } + + OpenGisType getOpenGisTypeOfShape(int shpIdx) { + return getShape( shpIdx ).openGisType; + } + + Coordinate[] coordinateRange(IndexRange range) { + Coordinate[] coordinates = createCoordinateArray( range.end - range.start ); + for ( int idx = range.start, i = 0; idx < range.end; idx++, i++ ) { + coordinates[i] = getCoordinate( idx ); + } + return coordinates; + } + + private Coordinate[] createCoordinateArray(int size) { + if ( hasMValues() ) { + return new MCoordinate[size]; + } + else { + return new Coordinate[size]; + } + } + + + private Figure getFigure(int index) { + return figures[index]; + } + + private Shape getShape(int index) { + return shapes[index]; + } + + void setCoordinate(int index, Coordinate coordinate) { + points[2 * index] = coordinate.x; + points[2 * index + 1] = coordinate.y; + if ( hasZValues() ) { + zValues[index] = coordinate.z; + } + if ( hasMValues() ) { + mValues[index] = ( (MCoordinate) coordinate ).m; + } + } + + boolean isEmpty() { + return this.numberOfPoints == 0; + } + + OpenGisType openGisType() { + if ( isValid() && isSinglePoint() ) { + return OpenGisType.POINT; + } + if ( isValid() && isSingleLineSegment() ) { + return OpenGisType.LINESTRING; + } + return firstShapeOpenGisType(); + } + + void setHasZValues() { + serializationPropertiesByte |= hasZValuesMask; + } + + void allocateZValueArray() { + if ( this.hasZValues() ) { + this.zValues = new double[this.numberOfPoints]; + } + } + + void allocateMValueArray() { + if ( this.hasMValues() ) { + this.mValues = new double[this.numberOfPoints]; + } + } + + void setHasMValues() { + serializationPropertiesByte |= hasMValuesMask; + } + + void setIsValid() { + serializationPropertiesByte |= isValidMask; + } + + void setIsSinglePoint() { + setNumberOfPoints( 1 ); + serializationPropertiesByte |= isSinglePointMask; + } + + void setIsSingleLineSegment() { + serializationPropertiesByte |= isSingleLineSegment; + } + + int getNumPoints() { + return this.numberOfPoints; + } + + void setNumberOfPoints(int num) { + this.numberOfPoints = num; + this.points = new double[2 * this.numberOfPoints]; + } + + private void parse() { + srid = buffer.getInt(); + version = buffer.get(); + if ( !isCompatible() ) { + throw new IllegalStateException( "Version mismatch. Expected version " + SUPPORTED_VERSION + ", but received version " + version ); + } + serializationPropertiesByte = buffer.get(); + determineNumberOfPoints(); + readPoints(); + if ( hasZValues() ) { + readZValues(); + } + if ( hasMValues() ) { + readMValues(); + } + + if ( isSingleLineSegment() || + isSinglePoint() ) { + //generate figure and shape. + // These are assumed, not explicitly encoded in the + // serialized data. See specs. + setNumberOfFigures( 1 ); + setFigure( 0, new Figure( FigureAttribute.Stroke, 0 ) ); + setNumberOfShapes( 1 ); + OpenGisType gisType = isSinglePoint() ? OpenGisType.POINT : OpenGisType.LINESTRING; + setShape( 0, new Shape( -1, 0, gisType ) ); + return; + } + //in all other cases, figures and shapes are + //explicitly encoded. + readFigures(); + readShapes(); + } + + private void readShapes() { + setNumberOfShapes( buffer.getInt() ); + for ( int sIdx = 0; sIdx < numberOfShapes; sIdx++ ) { + int parentOffset = buffer.getInt(); + int figureOffset = buffer.getInt(); + byte ogtByte = buffer.get(); + OpenGisType type = OpenGisType.valueOf( ogtByte ); + Shape shape = new Shape( parentOffset, figureOffset, type ); + setShape( sIdx, shape ); + } + } + + private void readFigures() { + setNumberOfFigures( buffer.getInt() ); + for ( int fIdx = 0; fIdx < numberOfFigures; fIdx++ ) { + byte faByte = buffer.get(); + int pointOffset = buffer.getInt(); + FigureAttribute fa = FigureAttribute.valueOf( faByte ); + Figure figure = new Figure( fa, pointOffset ); + setFigure( fIdx, figure ); + } + } + + private OpenGisType firstShapeOpenGisType() { + if ( shapes == null || shapes.length == 0 ) { + return OpenGisType.INVALID_TYPE; + } + return shapes[0].openGisType; + } + + private int calculateCapacity() { + int numPoints = getNumPoints(); + int prefixSize = 6; + + if ( isSinglePoint() || + isSingleLineSegment() ) { + int capacity = prefixSize + 16 * numPoints; + if ( hasZValues() ) { + capacity += 8 * numPoints; + } + if ( hasMValues() ) { + capacity += 8 * numPoints; + } + return capacity; + } + + int pointSize = getPointByteSize(); + int size = prefixSize + 3 * 4; // prefix + 3 ints for points, shapes and figures + size += getNumPoints() * pointSize; + size += getNumFigures() * Figure.getByteSize(); + size += getNumShapes() * Shape.getByteSize(); + return size; + } + + int getNumShapes() { + return this.numberOfShapes; + } + + private int getPointByteSize() { + int size = 16; //for X/Y values + if ( hasMValues() ) { + size += 8; + } + if ( hasZValues() ) { + size += 8; + } + return size; + + } + + private void readPoints() { + points = new double[2 * numberOfPoints]; + for ( int i = 0; i < numberOfPoints; i++ ) { + points[2 * i] = buffer.getDouble(); + points[2 * i + 1] = buffer.getDouble(); + } + } + + private void readZValues() { + zValues = new double[numberOfPoints]; + for ( int i = 0; i < numberOfPoints; i++ ) { + zValues[i] = buffer.getDouble(); + } + } + + + private void readMValues() { + mValues = new double[numberOfPoints]; + for ( int i = 0; i < numberOfPoints; i++ ) { + mValues[i] = buffer.getDouble(); + } + } + + private void determineNumberOfPoints() { + if ( isSinglePoint() ) { + numberOfPoints = 1; + return; + } + if ( isSingleLineSegment() ) { + numberOfPoints = 2; + return; + } + numberOfPoints = buffer.getInt(); + } + + boolean isCompatible() { + return version == SUPPORTED_VERSION; + } + + void setSrid(Integer srid) { + this.srid = ( srid == null ) ? -1 : srid; + } + + Integer getSrid() { + return srid != -1 ? srid : null; + } + + boolean hasZValues() { + return ( serializationPropertiesByte & hasZValuesMask ) != 0; + } + + boolean hasMValues() { + return ( serializationPropertiesByte & hasMValuesMask ) != 0; + } + + boolean isValid() { + return ( serializationPropertiesByte & isValidMask ) != 0; + } + + boolean isSinglePoint() { + return ( serializationPropertiesByte & isSinglePointMask ) != 0; + } + + boolean isSingleLineSegment() { + return ( serializationPropertiesByte & isSingleLineSegment ) != 0; + } + + void setNumberOfFigures(int num) { + numberOfFigures = num; + figures = new Figure[numberOfFigures]; + } + + void setFigure(int i, Figure figure) { + figures[i] = figure; + } + + void setNumberOfShapes(int num) { + numberOfShapes = num; + shapes = new Shape[numberOfShapes]; + } + + void setShape(int i, Shape shape) { + shapes[i] = shape; + } + + int getNumFigures() { + return this.numberOfFigures; + } + + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/package.html b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/package.html new file mode 100644 index 0000000000..a993e2d76b --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/convertors/package.html @@ -0,0 +1,13 @@ + + + + + +

Provides classes to translate between SQL Server Geometries and JTS Geometrys.

+ +

The binary format of a SQL Server Geometry is specified in Microsoft + SQL Server CLR Types Serialization Formats.

+ + \ No newline at end of file diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/integration/SpatialIntegrator.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/integration/SpatialIntegrator.java index c74de81413..e32fd54c7f 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/integration/SpatialIntegrator.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/integration/SpatialIntegrator.java @@ -6,6 +6,9 @@ import org.hibernate.integrator.spi.Integrator; import org.hibernate.metamodel.source.MetadataImplementor; import org.hibernate.service.spi.SessionFactoryServiceRegistry; import org.hibernate.spatial.GeometryType; +import org.hibernate.type.TypeResolver; + +import java.lang.reflect.Field; /** * @author Karel Maesen, Geovise BVBA @@ -13,18 +16,52 @@ import org.hibernate.spatial.GeometryType; */ public class SpatialIntegrator implements Integrator { + private static final String UNLOCK_ERROR_MSG = "SpatialIntegrator failed to unlock BasicTypeRegistry"; + @Override public void integrate(Configuration configuration, SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) { - sessionFactory.getTypeResolver().registerTypeOverride( GeometryType.INSTANCE ); - } + addType(sessionFactory.getTypeResolver()); + } @Override public void integrate(MetadataImplementor metadata, SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) { - metadata.getTypeResolver().registerTypeOverride( GeometryType.INSTANCE ); - } + addType(metadata.getTypeResolver()); + } @Override public void disintegrate(SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) { //do nothing. } + + private void addType(TypeResolver typeResolver) { + unlock(typeResolver); + typeResolver.registerTypeOverride(GeometryType.INSTANCE); + lock(typeResolver); + } + + private void lock(TypeResolver typeResolver) { + setLocked(typeResolver, true); + } + + private void unlock(TypeResolver typeResolver) { + setLocked(typeResolver, false); + } + + private void setLocked(TypeResolver typeResolver, boolean locked) { + try { + Field registryFld = typeResolver.getClass().getDeclaredField("basicTypeRegistry"); + registryFld.setAccessible(true); + Object registry = registryFld.get(typeResolver); + Field lockedFld = registry.getClass().getDeclaredField("locked"); + lockedFld.setAccessible(true); + lockedFld.setBoolean(registry, locked); + lockedFld.setAccessible(false); + registryFld.setAccessible(true); + } catch (NoSuchFieldException e) { + throw new IllegalStateException(UNLOCK_ERROR_MSG, e); + } catch (IllegalAccessException e) { + throw new IllegalStateException(UNLOCK_ERROR_MSG, e); + } + + } } diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/TestSupportFactories.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/TestSupportFactories.java index 358f3c6310..7f046b5879 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/TestSupportFactories.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/TestSupportFactories.java @@ -49,9 +49,9 @@ public class TestSupportFactories { // if ("org.hibernate.spatial.geodb.GeoDBDialect".equals(canonicalName)) { // return "org.hibernate.spatial.geodb.GeoDBSupport"; // } -// if ("org.hibernatespatial.sqlserver.SQLServerSpatialDialect".equals(canonicalName)) { -// return "org.hibernatespatial.sqlserver.SQLServerTestSupport"; -// } + if ("org.hibernate.spatial.dialect.sqlserver.SqlServer2008SpatialDialect".equals(canonicalName)) { + return "org.hibernate.spatial.dialect.sqlserver.SQLServerTestSupport"; + } // if ("org.hibernatespatial.mysql.MySQLSpatialDialect".equals(canonicalName) || // "org.hibernatespatial.mysql.MySQLSpatialInnoDBDialect".equals(canonicalName)) { // return "org.hibernatespatial.mysql.MySQLTestSupport"; diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/SQLServerExpressionTemplate.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/SQLServerExpressionTemplate.java new file mode 100644 index 0000000000..8fe492766d --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/SQLServerExpressionTemplate.java @@ -0,0 +1,49 @@ +/* + * $Id: SQLServerExpressionTemplate.java 182 2010-03-20 17:30:12Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007-2010 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver; + +import org.hibernate.spatial.test.SQLExpressionTemplate; +import org.hibernate.spatial.test.TestDataElement; + +/** + * @author Karel Maesen, Geovise BVBA + */ +public class SQLServerExpressionTemplate implements SQLExpressionTemplate { + + final String SQL_TEMPLATE = "insert into geomtest values (%d, '%s', Geometry::STGeomFromText('%s', %d))"; + + public String toInsertSql(TestDataElement testDataElement) { + return String.format( + SQL_TEMPLATE, + testDataElement.id, + testDataElement.type, + testDataElement.wkt, + testDataElement.srid + ); + } + + +} diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/SQLServerTestSupport.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/SQLServerTestSupport.java new file mode 100644 index 0000000000..fb50bf198f --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/SQLServerTestSupport.java @@ -0,0 +1,28 @@ +package org.hibernate.spatial.dialect.sqlserver; + +import org.hibernate.spatial.test.DataSourceUtils; +import org.hibernate.spatial.test.SQLExpressionTemplate; +import org.hibernate.spatial.test.TestData; +import org.hibernate.spatial.test.TestSupport; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; + +/** + * @author Karel Maesen, Geovise BVBA + * creation-date: Oct 15, 2010 + */ +public class SQLServerTestSupport extends TestSupport { + + + public TestData createTestData(BaseCoreFunctionalTestCase testcase) { + return TestData.fromFile( "test-data-set.xml" ); + } + + public SqlServerExpectationsFactory createExpectationsFactory(DataSourceUtils dataSourceUtils) { + return new SqlServerExpectationsFactory( dataSourceUtils ); + } + + @Override + public SQLExpressionTemplate getSQLExpressionTemplate() { + return new SQLServerExpressionTemplate(); + } +} diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/SqlServerExpectationsFactory.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/SqlServerExpectationsFactory.java new file mode 100644 index 0000000000..8122aff3ce --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/SqlServerExpectationsFactory.java @@ -0,0 +1,252 @@ +/* + * $Id: SqlServerExpectationsFactory.java 293 2011-03-04 22:47:49Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007-2010 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver; + +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.Point; + +import org.hibernate.spatial.dialect.sqlserver.convertors.Decoders; +import org.hibernate.spatial.test.AbstractExpectationsFactory; +import org.hibernate.spatial.test.DataSourceUtils; +import org.hibernate.spatial.test.NativeSQLStatement; + + +/** + * Implementation of an AbstractExpectationsFactory + * for Microsoft SQL Server (2008). + */ +public class SqlServerExpectationsFactory extends AbstractExpectationsFactory { + + + public SqlServerExpectationsFactory(DataSourceUtils utils) { + super( utils ); + } + + @Override + protected NativeSQLStatement createNativeDimensionSQL() { + return createNativeSQLStatement( "select t.id, t.geom.STDimension() from GeomTest t" ); + } + + @Override + protected NativeSQLStatement createNativeBufferStatement(Double distance) { + return createNativeSQLStatement( + "select t.id, t.geom.STBuffer(?) from GeomTest t where t.geom.STSrid = 4326", + new Object[] { distance } + ); + } + + @Override + protected NativeSQLStatement createNativeConvexHullStatement(Geometry geom) { + return createNativeSQLStatementAllWKTParams( + "select t.id, t.geom.STUnion(geometry::STGeomFromText(?, 4326)).STConvexHull() from GeomTest t where t.geom.STSrid = 4326", + geom.toText() + ); + } + + @Override + protected NativeSQLStatement createNativeIntersectionStatement(Geometry geom) { + return createNativeSQLStatementAllWKTParams( + "select t.id, t.geom.STIntersection(geometry::STGeomFromText(?, 4326)) from GeomTest t where t.geom.STSrid = 4326", + geom.toText() + ); + } + + @Override + protected NativeSQLStatement createNativeDifferenceStatement(Geometry geom) { + return createNativeSQLStatementAllWKTParams( + "select t.id, t.geom.STDifference(geometry::STGeomFromText(?, 4326)) from GeomTest t where t.geom.STSrid = 4326", + geom.toText() + ); + } + + @Override + protected NativeSQLStatement createNativeSymDifferenceStatement(Geometry geom) { + return createNativeSQLStatementAllWKTParams( + "select t.id, t.geom.STSymDifference(geometry::STGeomFromText(?, 4326)) from GeomTest t where t.geom.STSrid = 4326", + geom.toText() + ); + } + + @Override + protected NativeSQLStatement createNativeGeomUnionStatement(Geometry geom) { + return createNativeSQLStatementAllWKTParams( + "select t.id, t.geom.STUnion(geometry::STGeomFromText(?, 4326)) from GeomTest t where t.geom.STSrid = 4326", + geom.toText() + ); + } + + @Override + protected NativeSQLStatement createNativeAsTextStatement() { + return createNativeSQLStatement( "select t.id, t.geom.STAsText() from GeomTest t" ); + } + + @Override + protected NativeSQLStatement createNativeSridStatement() { + return createNativeSQLStatement( "select t.id, t.geom.STSrid from GeomTest t" ); + } + + @Override + protected NativeSQLStatement createNativeIsSimpleStatement() { + return createNativeSQLStatement( "select t.id, t.geom.STIsSimple() from GeomTest t" ); + } + + @Override + protected NativeSQLStatement createNativeIsEmptyStatement() { + return createNativeSQLStatement( "select t.id, t.geom.STIsEmpty() from GeomTest t" ); + } + + @Override + protected NativeSQLStatement createNativeIsNotEmptyStatement() { + return createNativeSQLStatement( "select t.id, ~t.geom.STIsEmpty() from GeomTest t" ); + } + + @Override + protected NativeSQLStatement createNativeBoundaryStatement() { + return createNativeSQLStatement( "select t.id, t.geom.STBoundary() from GeomTest t" ); + } + + @Override + protected NativeSQLStatement createNativeEnvelopeStatement() { + return createNativeSQLStatement( "select t.id, t.geom.STEnvelope() from GeomTest t" ); + } + + @Override + protected NativeSQLStatement createNativeAsBinaryStatement() { + return createNativeSQLStatement( "select t.id, t.geom.STAsBinary() from GeomTest t" ); + } + + @Override + protected NativeSQLStatement createNativeGeometryTypeStatement() { + return createNativeSQLStatement( "select t.id, t.geom.STGeometryType() from GeomTest t" ); + } + + @Override + protected Geometry decode(Object o) { + return Decoders.decode( (byte[]) o ); + } + + @Override + protected NativeSQLStatement createNativeWithinStatement(Geometry geom) { + return createNativeSQLStatementAllWKTParams( + "select t.id, t.geom.STWithin(geometry::STGeomFromText(?, 4326)) from GeomTest t where t.geom.STWithin(geometry::STGeomFromText(?, 4326)) = 'true' and t.geom.STSrid = 4326", + geom.toText() + ); + } + + @Override + protected NativeSQLStatement createNativeEqualsStatement(Geometry geom) { + return createNativeSQLStatementAllWKTParams( + "select t.id, t.geom.STEquals(geometry::STGeomFromText(?, 4326)) from GeomTest t where t.geom.STEquals(geometry::STGeomFromText(?, 4326)) = 'true' and t.geom.STSrid = 4326", + geom.toText() + ); + } + + @Override + protected NativeSQLStatement createNativeCrossesStatement(Geometry geom) { + return createNativeSQLStatementAllWKTParams( + "select t.id, t.geom.STCrosses(geometry::STGeomFromText(?, 4326)) from GeomTest t where t.geom.STCrosses(geometry::STGeomFromText(?, 4326)) = 'true' and t.geom.STSrid = 4326", + geom.toText() + ); + } + + @Override + protected NativeSQLStatement createNativeContainsStatement(Geometry geom) { + return createNativeSQLStatementAllWKTParams( + "select t.id, t.geom.STContains(geometry::STGeomFromText(?, 4326)) from GeomTest t where t.geom.STContains(geometry::STGeomFromText(?, 4326)) = 'true' and t.geom.STSrid = 4326", + geom.toText() + ); + } + + @Override + protected NativeSQLStatement createNativeDisjointStatement(Geometry geom) { + return createNativeSQLStatementAllWKTParams( + "select t.id, t.geom.STDisjoint(geometry::STGeomFromText(?, 4326)) from GeomTest t where t.geom.STDisjoint(geometry::STGeomFromText(?, 4326)) = 'true' and t.geom.STSrid = 4326", + geom.toText() + ); + } + + @Override + protected NativeSQLStatement createNativeTransformStatement(int epsg) { + throw new UnsupportedOperationException(); + } + + @Override + protected NativeSQLStatement createNativeHavingSRIDStatement(int srid) { + return createNativeSQLStatement( "select t.id, 1 from GeomTest t where t.geom.STSrid = " + srid ); + } + + @Override + protected NativeSQLStatement createNativeIntersectsStatement(Geometry geom) { + return createNativeSQLStatementAllWKTParams( + "select t.id, t.geom.STIntersects(geometry::STGeomFromText(?, 4326)) from GeomTest t where t.geom.STIntersects(geometry::STGeomFromText(?, 4326)) = 'true' and t.geom.STSrid = 4326", + geom.toText() + ); + } + + @Override + protected NativeSQLStatement createNativeFilterStatement(Geometry geom) { + return createNativeSQLStatementAllWKTParams( + "select t.id, t.geom.Filter(geometry::STGeomFromText(?, 4326)) from GeomTest t where t.geom.Filter(geometry::STGeomFromText(?, 4326)) = 1 and t.geom.STSrid = 4326", + geom.toText() + ); + } + + @Override + protected NativeSQLStatement createNativeTouchesStatement(Geometry geom) { + return createNativeSQLStatementAllWKTParams( + "select t.id, t.geom.STTouches(geometry::STGeomFromText(?, 4326)) from GeomTest t where t.geom.STTouches(geometry::STGeomFromText(?, 4326)) = 'true' and t.geom.STSrid = 4326", + geom.toText() + ); + } + + @Override + protected NativeSQLStatement createNativeOverlapsStatement(Geometry geom) { + return createNativeSQLStatementAllWKTParams( + "select t.id, t.geom.STOverlaps(geometry::STGeomFromText(?, 4326)) from GeomTest t where t.geom.STOverlaps(geometry::STGeomFromText(?, 4326)) = 'true' and t.geom.STSrid = 4326", + geom.toText() + ); + } + + @Override + protected NativeSQLStatement createNativeRelateStatement(Geometry geom, String matrix) { + String sql = "select t.id, t.geom.STRelate(geometry::STGeomFromText(?, 4326), '" + matrix + "' ) from GeomTest t where t.geom.STRelate(geometry::STGeomFromText(?, 4326), '" + matrix + "') = 'true' and t.geom.STSrid = 4326"; + return createNativeSQLStatementAllWKTParams( sql, geom.toText() ); + } + + @Override + protected NativeSQLStatement createNativeDwithinStatement(Point geom, double distance) { + throw new UnsupportedOperationException(); + } + + @Override + protected NativeSQLStatement createNativeDistanceStatement(Geometry geom) { + return createNativeSQLStatementAllWKTParams( + "select t.id, t.geom.STDistance(geometry::STGeomFromText(?, 4326)) from GeomTest t where t.geom.STSrid = 4326", + geom.toText() + ); + } + +} diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/AbstractConvertorTest.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/AbstractConvertorTest.java new file mode 100644 index 0000000000..a2bdcc09d2 --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/AbstractConvertorTest.java @@ -0,0 +1,132 @@ +/* + * $Id: AbstractConvertorTest.java 278 2010-12-18 14:03:32Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007-2010 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +import com.vividsolutions.jts.geom.Geometry; + +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertTrue; + +/** + * @author Karel Maesen, Geovise BVBA. + * Date: Nov 2, 2009 + */ +public class AbstractConvertorTest { + + private final static String TEST_DATA = "sqlserver/sqlserver-2008-test-data.ser"; + + List testData = readTestData(); + Map decodedGeoms = new HashMap(); + Map rawResults; + Map encodedGeoms; + Map expectedGeoms; + + + + public List readTestData(){ + InputStream in = this.getClass().getClassLoader().getResourceAsStream(TEST_DATA); + if (in == null) { + throw new RuntimeException("Can't find file " + TEST_DATA); + } + try { + ObjectInputStream oin = new ObjectInputStream(in); + return (List)oin.readObject(); + } catch (IOException e) { + throw new RuntimeException(e); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } finally { + try { + in.close(); + } catch (IOException e) { + // nothing to do + } + } + } + + + public void doDecoding(OpenGisType type) { + List testData = readTestData(); + rawResults = toRawResults(testData, type.toString()); + expectedGeoms = toExpected(testData, type.toString()); + for ( Integer id : rawResults.keySet() ) { + Geometry geometry = Decoders.decode( (byte[]) rawResults.get( id ) ); + decodedGeoms.put( id, geometry ); + } + } + + private Map toExpected(List testData, String type) { + Map result = new HashMap(); + for (ConvertorTestData item : testData) { + if (! item.type.equals(type)) continue; + result.put(item.id, item.geometry); + } + return result; + } + + private Map toRawResults(List testData, String type) { + Map result = new HashMap(); + for (ConvertorTestData item : testData) { + if (! item.type.equals(type)) continue; + result.put(item.id, item.bytes); + } + return result; + } + + public void doEncoding() { + encodedGeoms = new HashMap(); + for ( Integer id : decodedGeoms.keySet() ) { + Geometry geom = decodedGeoms.get( id ); + byte[] bytes = Encoders.encode( geom ); + encodedGeoms.put( id, bytes ); + } + } + + public void test_encoding() { + for ( Integer id : encodedGeoms.keySet() ) { + assertTrue( + "Wrong encoding for case " + id, + Arrays.equals( (byte[]) rawResults.get( id ), encodedGeoms.get( id ) ) + ); + } + } + + public void test_decoding() { + for ( Integer id : decodedGeoms.keySet() ) { + Geometry expected = expectedGeoms.get( id ); + Geometry received = decodedGeoms.get( id ); + assertTrue( "Wrong decoding for case " + id, expected.equalsExact( received ) ); + } + } +} + diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/ConvertorTestData.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/ConvertorTestData.java new file mode 100644 index 0000000000..b935d1501c --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/ConvertorTestData.java @@ -0,0 +1,16 @@ +package org.hibernate.spatial.dialect.sqlserver.convertors; + +import com.vividsolutions.jts.geom.Geometry; + +import java.io.Serializable; + +/** + * @author Karel Maesen, Geovise BVBA + * creation-date: 1/11/12 + */ +public class ConvertorTestData implements Serializable { + public Integer id; + public String type; + public Geometry geometry; + public byte[] bytes; +} diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/GeometryCollectionConvertorTest.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/GeometryCollectionConvertorTest.java new file mode 100644 index 0000000000..39bc5bf44c --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/GeometryCollectionConvertorTest.java @@ -0,0 +1,56 @@ +/* + * $Id: GeometryCollectionConvertorTest.java 167 2010-03-11 22:26:10Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007-2010 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +import org.junit.Before; +import org.junit.Test; + +/** + * Created by IntelliJ IDEA. + * User: maesenka + * Date: Jan 24, 2010 + * Time: 5:33:19 PM + * To change this template use File | Settings | File Templates. + */ +public class GeometryCollectionConvertorTest extends AbstractConvertorTest { + + @Before + public void setUp() { + doDecoding( OpenGisType.GEOMETRYCOLLECTION ); + doEncoding(); + } + + @Test + public void test_encoding() { + super.test_encoding(); + } + + @Test + public void test_decoding() { + super.test_decoding(); + } + +} diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/LineStringConvertorTest.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/LineStringConvertorTest.java new file mode 100644 index 0000000000..bb6be4cd21 --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/LineStringConvertorTest.java @@ -0,0 +1,128 @@ +/* + * $Id: LineStringConvertorTest.java 278 2010-12-18 14:03:32Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2009 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.LineString; +import org.junit.Before; +import org.junit.Test; + +import org.hibernate.spatial.mgeom.MCoordinate; + +import static junit.framework.Assert.assertEquals; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertTrue; + +public class LineStringConvertorTest extends AbstractConvertorTest { + + @Before + public void setUp() { + doDecoding( OpenGisType.LINESTRING ); + doEncoding(); + } + + + @Test + public void test_srid() { + assertTrue( decodedGeoms.get( 5 ) instanceof LineString ); + assertTrue( decodedGeoms.get( 6 ) instanceof LineString ); + + assertEquals( 4326, decodedGeoms.get( 5 ).getSRID() ); + assertEquals( 4326, decodedGeoms.get( 6 ).getSRID() ); + + } + + @Test + public void test_num_points() { + assertEquals( 2, decodedGeoms.get( 5 ).getNumPoints() ); + assertEquals( 4, decodedGeoms.get( 6 ).getNumPoints() ); + } + + + @Test + public void test_coordinates() { + + Coordinate[] received = decodedGeoms.get( 5 ).getCoordinates(); + MCoordinate[] expected = new MCoordinate[] { + new MCoordinate( 10.0, 5.0 ), + new MCoordinate( 20.0, 15.0 ) + }; + assertArrayEquals( received, expected ); + + received = decodedGeoms.get( 6 ).getCoordinates(); + expected = new MCoordinate[] { + new MCoordinate( 10.0, 5.0 ), + new MCoordinate( 20.0, 15.0 ), + new MCoordinate( 30.3, 22.4 ), + new MCoordinate( 10.0, 30.0 ) + }; + assertArrayEquals( expected, received ); + + received = decodedGeoms.get( 7 ).getCoordinates(); + expected = new MCoordinate[] { + new MCoordinate( 10.0, 5.0 ), + new MCoordinate( 20.0, 15.0 ) + }; + expected[0].z = 0; + expected[1].z = 3; + assertArrayEquals( expected, received ); + + //case 9 + received = decodedGeoms.get( 9 ).getCoordinates(); + expected = new MCoordinate[] { + new MCoordinate( 10, 5 ), + new MCoordinate( 20, 15 ), + new MCoordinate( 30.3, 22.4 ), + new MCoordinate( 10, 30 ) + }; + expected[0].z = 1; + expected[1].z = 2; + expected[2].z = 5; + expected[3].z = 2; + assertArrayEquals( expected, received ); + + //case 10 + received = decodedGeoms.get( 10 ).getCoordinates(); + expected[0].m = 1; + expected[1].m = 3; + expected[2].m = 10; + expected[3].m = 12; + assertArrayEquals( expected, received ); + + + } + + @Test + public void test_encoding() { + super.test_encoding(); + } + + @Test + public void test_decoding() { + super.test_decoding(); + } + +} diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/MultiLineStringConvertorTest.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/MultiLineStringConvertorTest.java new file mode 100644 index 0000000000..aae89eb67c --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/MultiLineStringConvertorTest.java @@ -0,0 +1,49 @@ +/* + * $Id: MultiLineStringConvertorTest.java 155 2010-01-13 21:00:35Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2009 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +import org.junit.Before; +import org.junit.Test; + +public class MultiLineStringConvertorTest extends AbstractConvertorTest { + + @Before + public void setUp() { + doDecoding( OpenGisType.MULTILINESTRING ); + doEncoding(); + } + + @Test + public void test_encoding() { + super.test_encoding(); + } + + @Test + public void test_decoding() { + super.test_decoding(); + } + +} diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/MultiPointConvertorTest.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/MultiPointConvertorTest.java new file mode 100644 index 0000000000..ed82a1655e --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/MultiPointConvertorTest.java @@ -0,0 +1,49 @@ +/* + * $Id: MultiPointConvertorTest.java 155 2010-01-13 21:00:35Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2009 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +import org.junit.Before; +import org.junit.Test; + +public class MultiPointConvertorTest extends AbstractConvertorTest { + + @Before + public void setUp() { + doDecoding( OpenGisType.MULTIPOINT ); + doEncoding(); + } + + @Test + public void test_encoding() { + super.test_encoding(); + } + + @Test + public void test_decoding() { + super.test_decoding(); + } + +} diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/MultiPolygonConvertorTest.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/MultiPolygonConvertorTest.java new file mode 100644 index 0000000000..45ebd7924e --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/MultiPolygonConvertorTest.java @@ -0,0 +1,49 @@ +/* + * $Id: MultiPolygonConvertorTest.java 155 2010-01-13 21:00:35Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2009 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +import org.junit.Before; +import org.junit.Test; + +public class MultiPolygonConvertorTest extends AbstractConvertorTest { + + @Before + public void setUp() { + doDecoding( OpenGisType.MULTIPOLYGON ); + doEncoding(); + } + + @Test + public void test_encoding() { + super.test_encoding(); + } + + @Test + public void test_decoding() { + super.test_decoding(); + } + +} diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/PointConvertorTest.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/PointConvertorTest.java new file mode 100644 index 0000000000..fcc5172749 --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/PointConvertorTest.java @@ -0,0 +1,98 @@ +/* + * $Id: PointConvertorTest.java 278 2010-12-18 14:03:32Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2009 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Point; +import org.junit.Before; +import org.junit.Test; + +import org.hibernate.spatial.mgeom.MCoordinate; + +import static junit.framework.Assert.assertEquals; + +/** + * @author Karel Maesen, Geovise BVBA. + * Date: Nov 2, 2009 + */ +public class PointConvertorTest extends AbstractConvertorTest { + + @Before + public void setup() { + doDecoding( OpenGisType.POINT ); + doEncoding(); + } + + @Test + public void test_verify_srid() { + assertEquals( 0, decodedGeoms.get( 1 ).getSRID() ); + assertEquals( 4326, decodedGeoms.get( 2 ).getSRID() ); + assertEquals( 31370, decodedGeoms.get( 3 ).getSRID() ); + } + + @Test + public void test_class() { + for ( Integer id : decodedGeoms.keySet() ) { + assertEquals( Point.class, decodedGeoms.get( id ).getClass() ); + } + } + + @Test + public void test_coordinates() { + Coordinate expected; + Coordinate received; + expected = new Coordinate( 10.0, 5.0 ); + assertEquals( expected, decodedGeoms.get( 1 ).getCoordinate() ); + expected = new Coordinate( 52.25, 2.53 ); + assertEquals( expected, decodedGeoms.get( 2 ).getCoordinate() ); + expected = new Coordinate( 150000.0, 200000.0 ); + assertEquals( expected, decodedGeoms.get( 3 ).getCoordinate() ); + expected = new MCoordinate( 10.0, 2.0, 1.0, 3.0 ); + assertEquals( expected, decodedGeoms.get( 4 ).getCoordinate() ); + } + + @Test + public void test_encoding() { + super.test_encoding(); + } + + @Test + public void test_decoding() { + super.test_decoding(); + } + + @Test + public void test_test_empty_point() { + //TODO -- How? + } + + @Test + public void test_no_srid() { + //TODO -- How? + } + + +} diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/PolygonConvertorTest.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/PolygonConvertorTest.java new file mode 100644 index 0000000000..fbf0b53e6a --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/PolygonConvertorTest.java @@ -0,0 +1,51 @@ +/* + * $Id: PolygonConvertorTest.java 155 2010-01-13 21:00:35Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2009 Geovise BVBA + * + * 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, or (at your option) any later version. + * + * 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 + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.sqlserver.convertors; + +import org.junit.Before; +import org.junit.Test; + +public class PolygonConvertorTest extends AbstractConvertorTest { + + + @Before + public void setUp() { + doDecoding( OpenGisType.POLYGON ); + doEncoding(); + } + + @Test + public void test_encoding() { + super.test_encoding(); + } + + @Test + public void test_decoding() { + super.test_decoding(); + } + + +} diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/SpatialObjectGenerator.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/SpatialObjectGenerator.java new file mode 100644 index 0000000000..e98603cc87 --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/sqlserver/convertors/SpatialObjectGenerator.java @@ -0,0 +1,134 @@ +package org.hibernate.spatial.dialect.sqlserver.convertors; + +import com.vividsolutions.jts.geom.Geometry; +import org.hibernate.spatial.dialect.sqlserver.SQLServerExpressionTemplate; +import org.hibernate.spatial.dialect.sqlserver.SQLServerTestSupport; +import org.hibernate.spatial.test.DataSourceUtils; +import org.hibernate.spatial.test.TestData; +import org.hibernate.spatial.test.TestSupport; + +import java.io.*; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * A simple utitlity to generate the binary geometry objects by inserting spatial objects into a SQL Server 2008 instance, + * and reading back the results. + * + * @author Karel Maesen, Geovise BVBA + * creation-date: 1/11/12 + */ +public class SpatialObjectGenerator { + + private final static String TEST_DATA = "sqlserver-2008-test-data.ser"; + + private final static DataSourceUtils dataSourceUtils = new DataSourceUtils( + "sqlserver/hibernate-spatial-sqlserver-test.properties", + new SQLServerExpressionTemplate() + ); + + private final static TestSupport support = new SQLServerTestSupport(); + + private final static String[] TYPES; + + static { + TYPES = new String[OpenGisType.values().length]; + int i = 0; + for (OpenGisType type : OpenGisType.values()) { + TYPES[i++] = type.toString(); + } + } + + private final TestData testData = support.createTestData(null); + + public static void main(String[] argv) { + File outFile = createOutputFile(argv); + SpatialObjectGenerator generator = new SpatialObjectGenerator(); + try { + generator.prepare(); + List result = generator.generateTestDataObjects(); + writeTo(outFile, result); + } catch (IOException e) { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } catch (SQLException e) { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } finally{ + try { + generator.discard(); + } catch (SQLException e) { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } catch (IOException e) { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + } + + } + + private static void writeTo(File outFile, List result) { + FileOutputStream fos = null; + ObjectOutputStream out = null; + + try { + fos = new FileOutputStream(outFile); + out = new ObjectOutputStream(fos); + out.writeObject(result); + out.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } catch (IOException e) { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + + System.out.printf("Wrote %d objects to %s.", result.size(), outFile.getAbsolutePath()); + } + + private static File createOutputFile(String[] argv) { + String tmpDir = System.getProperty("java.io.tmpdir"); + File outFile = new File(tmpDir, TEST_DATA); + if (argv.length > 0) { + outFile = new File(argv[1]); + } + return outFile; + } + + + public void prepare() throws IOException, SQLException { + String sql = dataSourceUtils.parseSqlIn("sqlserver/create-sqlserver-test-schema.sql"); + dataSourceUtils.executeStatement(sql); + dataSourceUtils.insertTestData(testData); + } + + public List generateTestDataObjects() { + List result = new ArrayList(); + for (String type : TYPES) { + addTestObjectForType(type, result); + } + return result; + } + + private void addTestObjectForType(String type, List result) { + Map rawResults = dataSourceUtils.rawDbObjects(type.toString()); + Map geometries = dataSourceUtils.expectedGeoms(type.toString(), testData); + addToResult(type, result, rawResults, geometries); + } + + private void addToResult(String type, List result, Map rawResults, Map geometries) { + for (Integer id : rawResults.keySet()) { + ConvertorTestData data = new ConvertorTestData(); + data.id = id; + data.geometry = geometries.get(id); + data.type = type; + data.bytes = (byte[]) rawResults.get(id); + result.add(data); + } + } + + + public void discard() throws SQLException, IOException { + String sql = dataSourceUtils.parseSqlIn("sqlserver/drop-sqlserver-test-schema.sql"); + dataSourceUtils.executeStatement(sql); + } + +} diff --git a/hibernate-spatial/src/test/resources/hibernate.properties b/hibernate-spatial/src/test/resources/hibernate.properties index 732b4758fb..ee28b26921 100644 --- a/hibernate-spatial/src/test/resources/hibernate.properties +++ b/hibernate-spatial/src/test/resources/hibernate.properties @@ -28,13 +28,18 @@ #hibernate.connection.username hibbrtru #hibernate.connection.password hibbrtru -hibernate.dialect org.hibernate.spatial.dialect.oracle.OracleSpatial10gDialect -hibernate.connection.driver_class oracle.jdbc.driver.OracleDriver -hibernate.connection.url jdbc:oracle:thin:@oracle.geovise.com/ORCL +#hibernate.dialect org.hibernate.spatial.dialect.oracle.OracleSpatial10gDialect +#hibernate.connection.driver_class oracle.jdbc.driver.OracleDriver +#hibernate.connection.url jdbc:oracle:thin:@oracle.geovise.com/ORCL +#hibernate.connection.username hbs +#hibernate.connection.password hbs + +hibernate.dialect org.hibernate.spatial.dialect.sqlserver.SqlServer2008SpatialDialect +hibernate.connection.driver_class com.microsoft.sqlserver.jdbc.SQLServerDriver +hibernate.connection.url jdbc:sqlserver://192.168.122.67:1433;databaseName=HBS hibernate.connection.username hbs hibernate.connection.password hbs - hibernate.connection.pool_size 5 hibernate.show_sql true diff --git a/hibernate-spatial/src/test/resources/sqlserver/create-sqlserver-test-schema.sql b/hibernate-spatial/src/test/resources/sqlserver/create-sqlserver-test-schema.sql new file mode 100644 index 0000000000..7f3217b2a2 --- /dev/null +++ b/hibernate-spatial/src/test/resources/sqlserver/create-sqlserver-test-schema.sql @@ -0,0 +1,15 @@ + +CREATE TABLE "HBS"."dbo"."geomtest" +( +id int PRIMARY KEY NOT NULL, +type varchar(50), +geom geometry +) + + + + + + + + diff --git a/hibernate-spatial/src/test/resources/sqlserver/drop-sqlserver-test-schema.sql b/hibernate-spatial/src/test/resources/sqlserver/drop-sqlserver-test-schema.sql new file mode 100644 index 0000000000..d16cac92ea --- /dev/null +++ b/hibernate-spatial/src/test/resources/sqlserver/drop-sqlserver-test-schema.sql @@ -0,0 +1 @@ +DROP TABLE "HBS"."dbo"."geomtest"; \ No newline at end of file diff --git a/hibernate-spatial/src/test/resources/sqlserver/hibernate-spatial-sqlserver-test.properties b/hibernate-spatial/src/test/resources/sqlserver/hibernate-spatial-sqlserver-test.properties new file mode 100644 index 0000000000..47d33b3dc2 --- /dev/null +++ b/hibernate-spatial/src/test/resources/sqlserver/hibernate-spatial-sqlserver-test.properties @@ -0,0 +1,10 @@ +# +# $Id: hibernate-spatial-sqlserver-test.properties 182 2010-03-20 17:30:12Z maesenka $ +# + +jdbcUrl = jdbc:sqlserver://192.168.0.100:1433;databaseName=HBS +jdbcDriver = com.microsoft.sqlserver.jdbc.SQLServerDriver +jdbcUser = hbs +jdbcPass = hbs +dataset = test-data-set.xml + diff --git a/hibernate-spatial/src/test/resources/sqlserver/sqlserver-2008-test-data.ser b/hibernate-spatial/src/test/resources/sqlserver/sqlserver-2008-test-data.ser new file mode 100644 index 0000000000000000000000000000000000000000..ad85f6185be78b8f365976b5d3343a3dbb9a234c GIT binary patch literal 20258 zcmd^GYiu0V6~4QEl0eAAK!5;&xJdwaO;aa8tt1m-J9WB_)5MWToJQF=OK`BgoAo+4 z&<0mk+lZI=(MMW|3JR_INKqwJRcb4sQY-!xAt4a7Dk|kiRHRZxsw$%XXnW7&o7ufP zGae^S9MO@yXYSl{&pr3N?m2hHr#>_d<0Z4?aPDX>Gf^HM$!sc>a>ug6)AnG!{r!v`)Kw@Q%G^JEAYU5GmGhbLVy--#8_68BKl!0@ zX8g#=c)oNrU&;&>#w;ioO5>T$xE;ukm%DQ1T*rZZzx~bbANHqB{h(<$aI9>foAls4 zS<`$dUl`4oOUKG)Wp=1A+J1ES=Gh`< z8k3^c@|Ci`|J5sHmw&V6DO1f;#`2UQo-*4D!(-*HriXua^|D{zmNu!ZnLku0lnxG) zsO$>wh+WZUA9ZK`$V7f@DBn3*GOckFLI}sc_k8}AuWsF7r^%uSMV^ zXR9GIyTU$85%VkEC3CozB`@FVt)KVybH(-b36@O6+PtmHc`~nleet=s=dF*NI~_Xr zqYpvcQ~l{pOzCj*rs>7ab8kxbPtlM~&4+np(bFbueU&$j4RBb$IpV=s|Ik6m| z0~u#Fo{<}mtjb=#4(h{riP`Bs)BommT@`+du!S&3m6DU&xxqB5kES?fgla zlQk@cyNEcVXV-B5QfksgkCwT%9kBlCvYD6d-PXNxV26z)JT&ke5vN)p#M$C8UDKg3 zBjVgbPuY`t-PzJiwk?rKw|N~x-pdG#G=K(L**1sc{gS8niHdIowOqgU2YY2Vc=z$O z&Xeh|$_*anIP}Lqlh)tyDV1V8l2UV+l%`lp z4YT1N!We=of-EF%X4ikPzA9U&i4~p-%fWK|$K6sLk5&H(rA2bREKIJ?uw0uihFoQh zkUK0G7QZ@9?hnw|@E9Etw;*@G2rCqx3_Mn`BIJ&JAYSg?Y9U%-(euJ2e^M;EL0O0f zkWdti9w|MLxC>>2ut{k3PEltg$%?onaC>3o*rCGM>r<(8Y2A~bvr)tr{r49}s3g91 zFt*B|7?dmRpn^SXil0{|H zw7oyOdrQBY#uVA8>o0^+Q%VzJtmIlJh+_^9j~BTNdXgTnu%D{v;s-&U6rl~Q7O+}p zkTZG#1q;1^=mo6CBG%|aFJSeIf)jy7+E_>;_%06$GGJE`Q-dB8a-rEL&!eD=Z`&72 z5#Hbwvj_-r0IKkSwU3b_gy(55AZP$8Enq24^a46F#$k~nmV_zd_u>&;uM5W!zfs{G z&m)Ez<7tlrk|uudm(+~vp^haH>SmI+P48w7cTsw?lhWm;I*vxPvP+01 zB&VA(4r}`5>1ZE-VL&k@bSH}s$*@2ZGXYl57>h;5yEx2vV~zr1Ok&!|8&vTfGn}=4 zx_!BCVx&CG2lr2HTl~_~H#NL!E!rMy+4mRG2mLsw-dq@=w;uNJ_vdFfZ)^I|s=PhD z7&PO6hx2M_<^@t0qsMHNY>tYy;QT6-SS zw<|l)8+MX7Awj5)M)0-P(;J0%D@3r^pzUUl#>i;`{nFXJp<)4%!7m&H2grmbk>O2y zCwucdvN!+9w#9fjCi1rZj+-gT*fwu1jSfN_Y#WeQpMcEWN=D-bh65%gg9=NJ(J&m) z*TuDD)$ejM*pZ)*eE(c@AlxH=H=eXxE-l@J=9DwnjV{iQ*5{}jcWdx9(kZ_ zGjvBL4}bLQP3mAAKEO>aqbBVzsT+CoNiDZ+=P2BEvATl7FyinRVIGi2)g0xa7m%_1 zQ`G3mV3=xI7!IhD!R|WjI_!mBK*pk2F`w4Ff}6n(^h;5N?p_uPr3H5V4$nTcSH_#} z9fRO?c>*!6Tia^{PN98=J_mkVg(}G~E}SYOP6r_`K$WgaHTDh8Y`)cqF$*x>WyNDJ zyj%jqfXaBcVyzK~UO-??akqCzEEZ;Li@_ojyFARqK4KGVxD-rG*msjAv;hUn7{Bew zljgZL(a?0NCfX>sejrdyI|tYiv|44Uo(7drteKmr5Dj7zj87+16AhiL&Fh|GG?=I- zgWTmgCW_PhDsv|jy&}X!Q+Gmzm5u{yO<53-$syV=ouP?O_q7*Q-hDx8qFmXE zv98P1k8a5or+e90yehgn zJpE=P<=0QT2=c)NAwFn+EIwEdp3gfIacv%LKz|~=@t=F4^<9up(#q`-ki9C?$S>Ho z)OQK=1chHhCZ=bbfnj&$B(P?>~$P5UlLZvbkJO#=>4%MW!ssYEgh7d+qT=e7y>hMJv9y zN1yLjxKH3zPN276;42Di@B`a4atVHrqUd91Ui;Lpo&QXlJgd(Bp+IW1_k7VqE|B;L zF7-ufvSlBa0%^*&C3v22x=hGRwbXI9c5>sY1}DV8sx8{4(lm!LUY9}v?sng!y}hwm zaI?4>&u>ktSZ}wo8P4rK_M5k~|#&7tQYMM@i=}~xC zCd6|K%aV&cWyd3!vj&1AE&bL3!3Yrg0#xlLvDly#bwZazOM4T}s565GAoDf-@@V~) z7ls4M@_^y#eu7>=6#{mfL|C8+8i3U^#$tV3L%`J`A;9S8DdY=sp*XE+d-9}3Vdc3D zrSA3i58l)ysCr0DPq`qWA4zFul6J~_-pJRn{(IinPkwf3-I-hM|J}&hI6JWMU;Cuq zax)~n+SCFJJi}rD*>YmYNPZg}&(zF=Q*52b(}_SIP_4a1x>3@h7m%?ipx}re;}E;&Le0$xYQlqN1Sre^;qZVO9!P-pN`~bzZg2uz zO$#)VVF4R70GY2KBZyj_a^eFF2h`<}2~}L^1+2!3jgfjZW@}od2^xSxt70;~MK2&@ zQM_Fq=HMs9!S&z8ELQNjf)K_#R5&({FyOFAbdd<7zsr;HJqnR{JNW035DR_K1ApKn zqw|7)@CDf6(HxCo zutE*a-ubN-Jx!Bp8|jAC6cbL~v`CVXt80dQ{1lxbtfkS`lK3~monkTsBpP_LtXn)x z43O85fDB6F7`v`GPSP!S%JME!Izg-8lctI&CA(&f8%G=`fpWYKAh(i|G>K+1eZles!4OV_rWuMO&||fVT9z!iefWWN8{} zvHa5zlE1zDw#Q9_A_c{hJPm%`=V${0(``#>!IcLWBwWYPhE!9y2#)QcQiXs1e-1K4 zn=vKAjQ))iRXNF#F64@Unlq|#02{r4f+ZAeA)(ml1+2ybHhKXWi;VTAFk?L=l|Bb; zrr;Z=((~J%JP3@{FKgMjh(e5AF&CkGfn=ofh`OdNj2paKLYbK$?KBCJdL`r0g!Y1% T07a