HHH-6512 - Refactors Oracle support.

This commit is contained in:
Karel Maesen 2015-04-01 22:59:41 +02:00 committed by Steve Ebersole
parent dbfeb16e43
commit 2738d0f5c7
17 changed files with 41 additions and 2755 deletions

View File

@ -26,7 +26,6 @@ dependencies {
compile(project(':hibernate-core'))
compile([group: 'postgresql', name: 'postgresql', version: '8.4-701.jdbc4'])
compile([group: 'org.geolatte', name: 'geolatte-geom', version: '1.0-SNAPSHOT'])
// compile([group: 'com.vividsolutions', name: 'jts', version: '1.12'])
compile(libraries.dom4j) {
transitive = false

View File

@ -1,45 +0,0 @@
/*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for spatial (geographic) data.
*
* Copyright © 2007-2012 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
*/
package org.hibernate.spatial.dialect.oracle;
import java.sql.Connection;
import org.hibernate.spatial.helper.FinderStrategy;
/**
* The <code>ConnectionFinder</code> returns an OracleConnection when given a
* <code>Connection</code> object.
* <p>
* The SDOGeometryType requires access to an <code>OracleConnection</code>
* object when converting a geometry to <code>SDOGeometry</code>, prior to
* setting the geometry attribute in prepared statements. In some environments
* the prepared statements do not return an <code>OracleConnection</code> but
* a wrapper. Implementations of this interface attempt to retrieve the
* <code>OracleConnection</code> from the wrapper in such cases.
* </p>
* <p>Implementations should be thread-safe, and have a default (no-args) constructor.</p>
*
* @author Karel Maesen
*/
public interface ConnectionFinder extends
FinderStrategy<Connection, Connection> {
}

View File

@ -1,112 +0,0 @@
/*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for spatial (geographic) data.
*
* Copyright © 2007-2012 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
*/
package org.hibernate.spatial.dialect.oracle;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import org.hibernate.HibernateException;
import org.hibernate.spatial.helper.FinderException;
/**
* Default <code>ConnectionFinder</code> implementation.
* <p>
* This implementation attempts to retrieve the <code>OracleConnection</code>
* by recursive reflection: it searches for methods that return
* <code>Connection</code> objects, executes these methods and checks the
* result. If the result is of type <code>OracleConnection</code> the object
* is returned, otherwise it recurses on it.
* <p/>
* </p>
*
* @author Karel Maesen
*/
public class DefaultConnectionFinder implements ConnectionFinder {
private static final Class<?> ORACLE_CONNECTION_CLASS;
static {
try {
ORACLE_CONNECTION_CLASS = Class.forName( "oracle.jdbc.driver.OracleConnection" );
}
catch ( ClassNotFoundException e ) {
throw new HibernateException( "Can't find Oracle JDBC Driver on classpath." );
}
}
@Override
public Connection find(Connection con) throws FinderException {
if ( con == null ) {
return null;
}
if ( ORACLE_CONNECTION_CLASS.isInstance( con ) ) {
return con;
}
// try to find the Oracleconnection recursively
for ( Method method : con.getClass().getMethods() ) {
if ( method.getReturnType().isAssignableFrom(
java.sql.Connection.class
)
&& method.getParameterTypes().length == 0 ) {
try {
method.setAccessible( true );
final Connection oc = find( (Connection) ( method.invoke( con, new Object[] { } ) ) );
if ( oc == null ) {
throw new FinderException(
String.format(
"Tried retrieving OracleConnection from %s using method %s, but received null.",
con.getClass().getCanonicalName(),
method.getName()
)
);
}
return oc;
}
catch ( IllegalAccessException e ) {
throw new FinderException(
String.format(
"Illegal access on executing method %s when finding OracleConnection",
method.getName()
)
);
}
catch ( InvocationTargetException e ) {
throw new FinderException(
String.format(
"Invocation exception on executing method %s when finding OracleConnection",
method.getName()
)
);
}
}
}
throw new FinderException(
"Couldn't get at the OracleSpatial Connection object from the PreparedStatement."
);
}
}

View File

@ -1,140 +0,0 @@
/*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for spatial (geographic) data.
*
* Copyright © 2007-2012 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
*/
package org.hibernate.spatial.dialect.oracle;
import java.math.BigDecimal;
import java.sql.Array;
/**
* @author Karel Maesen, Geovise BVBA
* creation-date: Jul 1, 2010
*/
class ElemInfo {
static final String TYPE_NAME = "MDSYS.SDO_ELEM_INFO_ARRAY";
private BigDecimal[] triplets;
public ElemInfo(int size) {
this.triplets = new BigDecimal[3 * size];
}
public ElemInfo(BigDecimal[] elemInfo) {
this.triplets = elemInfo;
}
public ElemInfo(Array array) {
if ( array == null ) {
this.triplets = new BigDecimal[] { };
return;
}
try {
triplets = (BigDecimal[]) array.getArray();
}
catch ( Exception e ) {
throw new RuntimeException( e );
}
}
public BigDecimal[] getElements() {
return this.triplets;
}
public int getSize() {
return this.triplets.length / 3;
}
public int getOrdinatesOffset(int i) {
return this.triplets[i * 3].intValue();
}
public void setOrdinatesOffset(int i, int offset) {
this.triplets[i * 3] = new BigDecimal( offset );
}
public ElementType getElementType(int i) {
final int etype = this.triplets[i * 3 + 1].intValue();
final int interp = this.triplets[i * 3 + 2].intValue();
return ElementType.parseType( etype, interp );
}
public boolean isCompound(int i) {
return getElementType( i ).isCompound();
}
public int getNumCompounds(int i) {
if ( getElementType( i ).isCompound() ) {
return this.triplets[i * 3 + 2].intValue();
}
else {
return 1;
}
}
public void setElement(int i, int ordinatesOffset, ElementType et, int numCompounds) {
if ( i > getSize() ) {
throw new RuntimeException(
"Attempted to set more elements in ElemInfo Array than capacity."
);
}
this.triplets[i * 3] = new BigDecimal( ordinatesOffset );
this.triplets[i * 3 + 1] = new BigDecimal( et.getEType() );
this.triplets[i * 3 + 2] = et.isCompound() ? new BigDecimal( numCompounds ) : new BigDecimal(
et
.getInterpretation()
);
}
public String toString() {
return SDOGeometry.arrayToString( this.triplets );
}
public void addElement(BigDecimal[] element) {
final BigDecimal[] newTriplets = new BigDecimal[this.triplets.length + element.length];
System.arraycopy(
this.triplets, 0, newTriplets, 0,
this.triplets.length
);
System.arraycopy(
element, 0, newTriplets, this.triplets.length,
element.length
);
this.triplets = newTriplets;
}
public void addElement(ElemInfo element) {
this.addElement( element.getElements() );
}
public BigDecimal[] getElement(int i) {
BigDecimal[] ea = null;
if ( this.getElementType( i ).isCompound() ) {
final int numCompounds = this.getNumCompounds( i );
ea = new BigDecimal[numCompounds + 1];
}
else {
ea = new BigDecimal[3];
}
System.arraycopy( this.triplets, 3 * i, ea, 0, ea.length );
return ea;
}
}

View File

@ -1,121 +0,0 @@
/*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for spatial (geographic) data.
*
* Copyright © 2007-2012 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
*/
package org.hibernate.spatial.dialect.oracle;
/**
* @author Karel Maesen, Geovise BVBA
* creation-date: Jul 1, 2010
*/
enum ElementType {
UNSUPPORTED( 0, true ), POINT( 1, 1 ), ORIENTATION( 1, 0 ), POINT_CLUSTER(
1,
true
), LINE_STRAITH_SEGMENTS( 2, 1 ), LINE_ARC_SEGMENTS( 2, 2 ), INTERIOR_RING_STRAIGHT_SEGMENTS(
2003, 1
), EXTERIOR_RING_STRAIGHT_SEGMENTS( 1003, 1 ), INTERIOR_RING_ARC_SEGMENTS(
2003, 2
), EXTERIOR_RING_ARC_SEGMENTS( 1003, 2 ), INTERIOR_RING_RECT(
2003, 3
), EXTERIOR_RING_RECT( 1003, 3 ), INTERIOR_RING_CIRCLE(
2003, 4
), EXTERIOR_RING_CIRCLE( 1003, 4 ), COMPOUND_LINE( 4, true ), COMPOUND_EXTERIOR_RING(
1005, true
), COMPOUND_INTERIOR_RING( 2005, true );
private int etype;
private int interpretation = 2;
private boolean compound;
private ElementType(int etype, int interp) {
this.etype = etype;
this.interpretation = interp;
}
private ElementType(int etype, boolean compound) {
this.etype = etype;
this.compound = compound;
}
public int getEType() {
return this.etype;
}
public int getInterpretation() {
return this.interpretation;
}
/**
* @return true, if the SDO_INTERPRETATION value is the number of points
* or compounds in the element.
*/
public boolean isCompound() {
return this.compound;
}
public boolean isLine() {
return ( etype == 2 || etype == 4 );
}
public boolean isInteriorRing() {
return ( etype == 2003 || etype == 2005 );
}
public boolean isExteriorRing() {
return ( etype == 1003 || etype == 1005 );
}
public boolean isStraightSegment() {
return ( interpretation == 1 );
}
public boolean isArcSegment() {
return ( interpretation == 2 );
}
public boolean isCircle() {
return ( interpretation == 4 );
}
public boolean isRect() {
return ( interpretation == 3 );
}
public static ElementType parseType(int etype, int interpretation) {
for ( ElementType t : values() ) {
if ( t.etype == etype ) {
if ( t.isCompound()
|| t.getInterpretation() == interpretation ) {
return t;
}
}
}
throw new RuntimeException(
"Can't determine ElementType from etype:" + etype
+ " and interp.:" + interpretation
);
}
}

View File

@ -1,224 +0,0 @@
/*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for spatial (geographic) data.
*
* Copyright © 2007-2012 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
*/
package org.hibernate.spatial.dialect.oracle;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Array;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Struct;
import org.hibernate.HibernateException;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.spatial.helper.FinderException;
/**
* Factory for Oracle JDBC extension types (ARRAY, STRUCT, ...).
* <p/>
* This factory creates the Oracle extension types using reflection in order to
* avoid creating compile-time dependencies on the proprietary Oracle driver.
*
* @author Karel Maesen, Geovise BVBA
* creation-date: Jul 3, 2010
*/
public class OracleJDBCTypeFactory implements SQLTypeFactory {
private final Class<?> datumClass;
private final Method structDescriptorCreator;
private final Method arrayDescriptorCreator;
private final Constructor<?> numberConstructor;
private final Constructor<?> arrayConstructor;
private final Constructor<?> structConstructor;
private final ConnectionFinder connectionFinder;
/**
* Constructs an instance.
*
* @param connectionFinder the {@code ConnectionFinder} the use for retrieving the {@code OracleConnection} instance.
*/
public OracleJDBCTypeFactory(ConnectionFinder connectionFinder) {
if ( connectionFinder == null ) {
throw new HibernateException( "ConnectionFinder cannot be null" );
}
this.connectionFinder = connectionFinder;
Object[] obj = findDescriptorCreator( "oracle.sql.StructDescriptor" );
Class<?> structDescriptorClass = (Class<?>) obj[0];
structDescriptorCreator = (Method) obj[1];
obj = findDescriptorCreator( "oracle.sql.ArrayDescriptor" );
Class<?> arrayDescriptorClass = (Class<?>) obj[0];
arrayDescriptorCreator = (Method) obj[1];
datumClass = findClass( "oracle.sql.Datum" );
Class<?> numberClass = findClass( "oracle.sql.NUMBER" );
Class<?> arrayClass = findClass( "oracle.sql.ARRAY" );
Class<?> structClass = findClass( "oracle.sql.STRUCT" );
numberConstructor = findConstructor( numberClass, java.lang.Integer.TYPE );
arrayConstructor = findConstructor( arrayClass, arrayDescriptorClass, Connection.class, Object.class );
structConstructor = findConstructor( structClass, structDescriptorClass, Connection.class, Object[].class );
}
private Constructor<?> findConstructor(Class clazz, Class<?>... arguments) {
try {
return clazz.getConstructor( arguments );
}
catch ( NoSuchMethodException e ) {
throw new HibernateException( "Error finding constructor for oracle.sql type.", e );
}
}
private Class<?> findClass(String name) {
try {
return ReflectHelper.classForName( name );
}
catch ( ClassNotFoundException e ) {
throw new HibernateException( "Class 'oracle.sql.Datum' not found on class path" );
}
}
private Object[] findDescriptorCreator(String className) {
try {
final Class clazz = ReflectHelper.classForName( className );
final Method m = clazz.getMethod( "createDescriptor", String.class, Connection.class );
return new Object[] { clazz, m };
}
catch ( ClassNotFoundException e ) {
throw new HibernateException( "Class 'StructDescriptor' not found on classpath" );
}
catch ( NoSuchMethodException e ) {
throw new HibernateException( "Class 'StructDescriptor' has no method 'createDescriptor(String,Connection)'" );
}
}
@Override
public Struct createStruct(SDOGeometry geom, Connection conn) throws SQLException {
Connection oracleConnection = null;
try {
oracleConnection = connectionFinder.find( conn );
}
catch ( FinderException e ) {
throw new HibernateException( "Problem finding Oracle Connection", e );
}
final Object structDescriptor = createStructDescriptor( SDOGeometry.getTypeName(), oracleConnection );
final Object[] attributes = createDatumArray( 5 );
attributes[0] = createNumber( geom.getGType().intValue() );
if ( geom.getSRID() > 0 ) {
attributes[1] = createNumber( geom.getSRID() );
}
else {
attributes[1] = null;
}
attributes[3] = createElemInfoArray( geom.getInfo(), oracleConnection );
attributes[4] = createOrdinatesArray( geom.getOrdinates(), oracleConnection );
return createStruct( structDescriptor, oracleConnection, attributes );
}
@Override
public Array createElemInfoArray(ElemInfo elemInfo, Connection conn) {
final Object arrayDescriptor = createArrayDescriptor( ElemInfo.TYPE_NAME, conn );
return createArray( arrayDescriptor, conn, elemInfo.getElements() );
}
@Override
public Array createOrdinatesArray(Ordinates ordinates, Connection conn) throws SQLException {
final Object arrayDescriptor = createArrayDescriptor( Ordinates.TYPE_NAME, conn );
return createArray( arrayDescriptor, conn, ordinates.getOrdinateArray() );
}
private Array createArray(Object descriptor, Connection conn, Object[] data) {
try {
return (Array) arrayConstructor.newInstance( descriptor, conn, data );
}
catch ( InstantiationException e ) {
throw new HibernateException( "Problem creating ARRAY.", e );
}
catch ( IllegalAccessException e ) {
throw new HibernateException( "Problem creating ARRAY.", e );
}
catch ( InvocationTargetException e ) {
throw new HibernateException( "Problem creating ARRAY.", e );
}
}
private Struct createStruct(Object descriptor, Connection conn, Object[] attributes) {
try {
return (Struct) structConstructor.newInstance( descriptor, conn, attributes );
}
catch ( InstantiationException e ) {
throw new HibernateException( "Problem creating STRUCT.", e );
}
catch ( IllegalAccessException e ) {
throw new HibernateException( "Problem creating STRUCT.", e );
}
catch ( InvocationTargetException e ) {
throw new HibernateException( "Problem creating STRUCT.", e );
}
}
private Object createStructDescriptor(String sqlType, Connection conn) {
try {
return structDescriptorCreator.invoke( null, sqlType, conn );
}
catch ( IllegalAccessException e ) {
throw new HibernateException( "Error creating oracle STRUCT", e );
}
catch ( InvocationTargetException e ) {
throw new HibernateException( "Error creating oracle STRUCT", e );
}
}
private Object createArrayDescriptor(String name, Connection conn) {
try {
return arrayDescriptorCreator.invoke( null, name, conn );
}
catch ( IllegalAccessException e ) {
throw new HibernateException( "Error creating oracle ARRAY", e );
}
catch ( InvocationTargetException e ) {
throw new HibernateException( "Error creating oracle ARRAY", e );
}
}
private Object[] createDatumArray(int size) {
return (Object[]) java.lang.reflect.Array.newInstance( datumClass, size );
}
private Object createNumber(int obj) {
try {
return numberConstructor.newInstance( obj );
}
catch ( InvocationTargetException e ) {
throw new HibernateException( "Error creating oracle NUMBER", e );
}
catch ( InstantiationException e ) {
throw new HibernateException( "Error creating oracle NUMBER", e );
}
catch ( IllegalAccessException e ) {
throw new HibernateException( "Error creating oracle NUMBER", e );
}
}
}

View File

@ -1,545 +0,0 @@
/*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for spatial (geographic) data.
*
* Copyright © 2007-2012 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
*/
package org.hibernate.spatial.dialect.oracle;
import java.io.Serializable;
import java.sql.Types;
import java.util.List;
import org.hibernate.QueryException;
import org.hibernate.dialect.Oracle10gDialect;
import org.hibernate.dialect.function.StandardSQLFunction;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.spi.TypeContributions;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.spatial.GeolatteGeometryType;
import org.hibernate.spatial.HibernateSpatialConfiguration;
import org.hibernate.spatial.JTSGeometryType;
import org.hibernate.spatial.SpatialAnalysis;
import org.hibernate.spatial.SpatialDialect;
import org.hibernate.spatial.SpatialFunction;
import org.hibernate.spatial.SpatialRelation;
import org.hibernate.spatial.dialect.oracle.criterion.OracleSpatialAggregate;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.Type;
/**
* Spatial Dialect for Oracle10g databases.
*
* @author Karel Maesen
*/
public class OracleSpatial10gDialect extends Oracle10gDialect implements
SpatialDialect, Serializable {
private final boolean isOgcStrict;
private final ConnectionFinder connectionFinder;
/**
* Constructs the dialect with a default configuration
*/
public OracleSpatial10gDialect() {
this( new HibernateSpatialConfiguration() );
}
/**
* Constructs the dialect with the specified configuration
*
* @param config the {@code HibernateSpatialConfiguration} that configures this dialect.
*/
public OracleSpatial10gDialect(HibernateSpatialConfiguration config) {
super();
this.isOgcStrict = config.isOgcStrictMode();
final ConnectionFinder finder = config.getConnectionFinder();
this.connectionFinder = finder == null ? new DefaultConnectionFinder() : finder;
// register geometry type
registerColumnType( Types.STRUCT, "MDSYS.SDO_GEOMETRY" );
// registering OGC functions
// (spec_simplefeatures_sql_99-04.pdf)
// section 2.1.1.1
registerFunction( "dimension", new GetDimensionFunction() );
registerFunction( "geometrytype", new GetGeometryTypeFunction() );
registerFunction( "srid", new SDOObjectProperty( "SDO_SRID", StandardBasicTypes.INTEGER ) );
registerFunction( "envelope", new StandardSQLFunction( "SDO_GEOM.SDO_MBR" ) );
registerFunction( "astext", new AsTextFunction() );
registerFunction( "asbinary", new StandardSQLFunction( "SDO_UTIL.TO_WKBGEOMETRY", StandardBasicTypes.BINARY ) );
registerFunction(
"isempty",
new WrappedOGCFunction( "OGC_ISEMPTY", StandardBasicTypes.BOOLEAN, new boolean[] { true } )
);
registerFunction(
"issimple",
new WrappedOGCFunction( "OGC_ISSIMPLE", StandardBasicTypes.BOOLEAN, new boolean[] { true } )
);
registerFunction( "boundary", new WrappedOGCFunction( "OGC_BOUNDARY", new boolean[] { true } ) );
// registerFunction("area", new AreaFunction());
// Register functions for spatial relation constructs
// section 2.1.1.2
registerFunction( "overlaps", new SpatialRelateFunction( "overlaps", SpatialRelation.OVERLAPS ) );
registerFunction( "intersects", new SpatialRelateFunction( "intersects", SpatialRelation.INTERSECTS ) );
registerFunction( "contains", new SpatialRelateFunction( "contains", SpatialRelation.CONTAINS ) );
registerFunction( "crosses", new SpatialRelateFunction( "crosses", SpatialRelation.CROSSES ) );
registerFunction( "disjoint", new SpatialRelateFunction( "disjoint", SpatialRelation.DISJOINT ) );
registerFunction( "equals", new SpatialRelateFunction( "equals", SpatialRelation.EQUALS ) );
registerFunction( "touches", new SpatialRelateFunction( "touches", SpatialRelation.TOUCHES ) );
registerFunction( "within", new SpatialRelateFunction( "within", SpatialRelation.WITHIN ) );
registerFunction(
"relate",
new WrappedOGCFunction( "OGC_RELATE", StandardBasicTypes.BOOLEAN, new boolean[] { true, true, false } )
);
// Register spatial analysis functions.
// Section 2.1.1.3
registerFunction(
"distance",
new SpatialAnalysisFunction( "distance", StandardBasicTypes.DOUBLE, SpatialAnalysis.DISTANCE )
);
registerFunction( "buffer", new SpatialAnalysisFunction( "buffer", SpatialAnalysis.BUFFER ) );
registerFunction( "convexhull", new SpatialAnalysisFunction( "convexhull", SpatialAnalysis.CONVEXHULL ) );
registerFunction( "difference", new SpatialAnalysisFunction( "difference", SpatialAnalysis.DIFFERENCE ) );
registerFunction( "intersection", new SpatialAnalysisFunction( "intersection", SpatialAnalysis.INTERSECTION ) );
registerFunction(
"symdifference",
new SpatialAnalysisFunction( "symdifference", SpatialAnalysis.SYMDIFFERENCE )
);
registerFunction( "geomunion", new SpatialAnalysisFunction( "union", SpatialAnalysis.UNION ) );
// we rename OGC union to geomunion because union is a reserved SQL
// keyword. (See also postgis documentation).
// portable spatial aggregate functions
registerFunction( "extent", new SpatialAggregationFunction( "extent", false, OracleSpatialAggregate.EXTENT ) );
//other common functions
registerFunction( "transform", new StandardSQLFunction( "SDO_CS.TRANSFORM" ) );
// Oracle specific Aggregate functions
registerFunction(
"centroid",
new SpatialAggregationFunction( "extent", false, OracleSpatialAggregate.CENTROID )
);
registerFunction(
"concat_lines",
new SpatialAggregationFunction( "extent", false, OracleSpatialAggregate.CONCAT_LINES )
);
registerFunction(
"aggr_convexhull",
new SpatialAggregationFunction( "extent", false, OracleSpatialAggregate.CONVEXHULL )
);
registerFunction(
"aggr_union",
new SpatialAggregationFunction( "extent", false, OracleSpatialAggregate.UNION )
);
registerFunction(
"lrs_concat",
new SpatialAggregationFunction( "lrsconcat", false, OracleSpatialAggregate.LRS_CONCAT )
);
}
@Override
public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
super.contributeTypes(
typeContributions,
serviceRegistry
);
final SDOGeometryTypeDescriptor sdoGeometryTypeDescriptor = new SDOGeometryTypeDescriptor(
new OracleJDBCTypeFactory(
this.connectionFinder
)
);
typeContributions.contributeType( new GeolatteGeometryType( sdoGeometryTypeDescriptor ) );
typeContributions.contributeType( new JTSGeometryType( sdoGeometryTypeDescriptor ) );
}
String getNativeSpatialRelateSQL(String arg1, String arg2, int spatialRelation) {
String mask = "";
boolean negate = false;
switch ( spatialRelation ) {
case SpatialRelation.INTERSECTS:
mask = "ANYINTERACT";
break;
case SpatialRelation.CONTAINS:
mask = "CONTAINS+COVERS";
break;
case SpatialRelation.CROSSES:
throw new UnsupportedOperationException(
"Oracle Spatial does't have equivalent CROSSES relationship"
);
case SpatialRelation.DISJOINT:
mask = "ANYINTERACT";
negate = true;
break;
case SpatialRelation.EQUALS:
mask = "EQUAL";
break;
case SpatialRelation.OVERLAPS:
mask = "OVERLAPBDYDISJOINT+OVERLAPBDYINTERSECT";
break;
case SpatialRelation.TOUCHES:
mask = "TOUCH";
break;
case SpatialRelation.WITHIN:
mask = "INSIDE+COVEREDBY";
break;
default:
throw new IllegalArgumentException(
"undefined SpatialRelation passed (" + spatialRelation
+ ")"
);
}
final StringBuffer buffer = new StringBuffer( "CASE SDO_RELATE(" ).append( arg1 )
.append( "," )
.append( arg2 )
.append( ",'mask=" + mask + "') " );
if ( !negate ) {
buffer.append( " WHEN 'TRUE' THEN 1 ELSE 0 END" );
}
else {
buffer.append( " WHEN 'TRUE' THEN 0 ELSE 1 END" );
}
return buffer.toString();
}
String getOGCSpatialRelateSQL(String arg1, String arg2, int spatialRelation) {
final StringBuffer ogcFunction = new StringBuffer( "MDSYS." );
switch ( spatialRelation ) {
case SpatialRelation.INTERSECTS:
ogcFunction.append( "OGC_INTERSECTS" );
break;
case SpatialRelation.CONTAINS:
ogcFunction.append( "OGC_CONTAINS" );
break;
case SpatialRelation.CROSSES:
ogcFunction.append( "OGC_CROSS" );
break;
case SpatialRelation.DISJOINT:
ogcFunction.append( "OGC_DISJOINT" );
break;
case SpatialRelation.EQUALS:
ogcFunction.append( "OGC_EQUALS" );
break;
case SpatialRelation.OVERLAPS:
ogcFunction.append( "OGC_OVERLAP" );
break;
case SpatialRelation.TOUCHES:
ogcFunction.append( "OGC_TOUCH" );
break;
case SpatialRelation.WITHIN:
ogcFunction.append( "OGC_WITHIN" );
break;
default:
throw new IllegalArgumentException(
"Unknown SpatialRelation ("
+ spatialRelation + ")."
);
}
ogcFunction.append( "(" ).append( "MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(" )
.append( arg1 ).append( ")," ).append(
"MDSYS.ST_GEOMETRY.FROM_SDO_GEOM("
).append( arg2 )
.append( ")" ).append( ")" );
return ogcFunction.toString();
}
String getNativeSpatialAggregateSQL(String arg1, int aggregation) {
final StringBuffer aggregateFunction = new StringBuffer();
final SpatialAggregate sa = new SpatialAggregate( aggregation );
if ( sa.getAggregateSyntax() == null ) {
throw new IllegalArgumentException(
"Unknown Spatial Aggregation ("
+ aggregation + ")."
);
}
aggregateFunction.append( sa.getAggregateSyntax() );
aggregateFunction.append( "(" );
if ( sa.isAggregateType() ) {
aggregateFunction.append( "SDOAGGRTYPE(" );
}
aggregateFunction.append( arg1 );
// TODO tolerance must by configurable
if ( sa.isAggregateType() ) {
aggregateFunction.append( ", " ).append( .001 ).append( ")" );
}
aggregateFunction.append( ")" );
return aggregateFunction.toString();
}
private StringBuffer wrapInSTGeometry(String geomColumn, StringBuffer toAdd) {
return toAdd.append( "MDSYS.ST_GEOMETRY(" ).append( geomColumn )
.append( ")" );
}
@Override
public String getSpatialFilterExpression(String columnName) {
final StringBuffer buffer = new StringBuffer( "SDO_FILTER(" );
buffer.append( columnName );
buffer.append( ",?) = 'TRUE' " );
return buffer.toString();
}
@Override
public String getSpatialRelateSQL(String columnName, int spatialRelation) {
String sql = ( isOGCStrict() ?
getOGCSpatialRelateSQL( columnName, "?", spatialRelation ) :
getNativeSpatialRelateSQL( columnName, "?", spatialRelation ) ) + " = 1";
sql += " and " + columnName + " is not null";
return sql;
}
String getSpatialAnalysisSQL(List args, int spatialAnalysisFunction, boolean useFilter) {
return isOGCStrict() ? getOGCSpatialAnalysisSQL( args, spatialAnalysisFunction ) : getNativeSpatialAnalysisSQL(
args,
spatialAnalysisFunction
);
}
@Override
public String getSpatialAggregateSQL(String columnName, int spatialAggregateFunction) {
return getNativeSpatialAggregateSQL( columnName, spatialAggregateFunction );
}
@Override
public String getDWithinSQL(String columnName) {
return "SDO_WITHIN_DISTANCE (" + columnName + ",?, ?) = 'TRUE' ";
}
@Override
public String getHavingSridSQL(String columnName) {
return String.format( " (MDSYS.ST_GEOMETRY(%s).ST_SRID() = ?)", columnName );
}
@Override
public String getIsEmptySQL(String columnName, boolean isEmpty) {
return String.format( "( MDSYS.ST_GEOMETRY(%s).ST_ISEMPTY() = %d )", columnName, isEmpty ? 1 : 0 );
}
private String getOGCSpatialAnalysisSQL(List args, int spatialAnalysisFunction) {
boolean[] geomArgs;
final StringBuffer ogcFunction = new StringBuffer( "MDSYS." );
boolean isGeomReturn = true;
switch ( spatialAnalysisFunction ) {
case SpatialAnalysis.BUFFER:
ogcFunction.append( "OGC_BUFFER" );
geomArgs = new boolean[] { true, false };
break;
case SpatialAnalysis.CONVEXHULL:
ogcFunction.append( "OGC_CONVEXHULL" );
geomArgs = new boolean[] { true };
break;
case SpatialAnalysis.DIFFERENCE:
ogcFunction.append( "OGC_DIFFERENCE" );
geomArgs = new boolean[] { true, true };
break;
case SpatialAnalysis.DISTANCE:
ogcFunction.append( "OGC_DISTANCE" );
geomArgs = new boolean[] { true, true };
isGeomReturn = false;
break;
case SpatialAnalysis.INTERSECTION:
ogcFunction.append( "OGC_INTERSECTION" );
geomArgs = new boolean[] { true, true };
break;
case SpatialAnalysis.SYMDIFFERENCE:
ogcFunction.append( "OGC_SYMMETRICDIFFERENCE" );
geomArgs = new boolean[] { true, true };
break;
case SpatialAnalysis.UNION:
ogcFunction.append( "OGC_UNION" );
geomArgs = new boolean[] { true, true };
break;
default:
throw new IllegalArgumentException(
"Unknown SpatialAnalysisFunction ("
+ spatialAnalysisFunction + ")."
);
}
if ( args.size() < geomArgs.length ) {
throw new QueryException(
"Insufficient arguments for spatial analysis function (function type: "
+ spatialAnalysisFunction + ")."
);
}
ogcFunction.append( "(" );
for ( int i = 0; i < geomArgs.length; i++ ) {
if ( i > 0 ) {
ogcFunction.append( "," );
}
if ( geomArgs[i] ) {
wrapInSTGeometry( (String) args.get( i ), ogcFunction );
}
else {
ogcFunction.append( args.get( i ) );
}
}
ogcFunction.append( ")" );
if ( isGeomReturn ) {
ogcFunction.append( ".geom" );
}
return ogcFunction.toString();
}
private String getNativeSpatialAnalysisSQL(List args, int spatialAnalysis) {
return getOGCSpatialAnalysisSQL( args, spatialAnalysis );
}
/**
* Reports whether this dialect is in OGC_STRICT mode or not.
*
* This method is for testing purposes.
*
* @return true if in OGC_STRICT mode, false otherwise
*/
public boolean isOGCStrict() {
return isOgcStrict;
}
/**
* Reports the ConnectionFinder used by this Dialect (or rather its associated TypeDescriptor).
*
* This method is mainly used for testing purposes.
*
* @return the ConnectionFinder in use
*/
public ConnectionFinder getConnectionFinder() {
return connectionFinder;
}
@Override
public boolean supportsFiltering() {
return true;
}
@Override
public boolean supports(SpatialFunction function) {
return ( getFunctions().get( function.toString() ) != null );
}
/**
* Implementation of the OGC astext function for HQL.
*/
private static class AsTextFunction extends StandardSQLFunction {
private AsTextFunction() {
super( "astext", StandardBasicTypes.STRING );
}
public String render(Type firstArgumentType, final List args, final SessionFactoryImplementor factory) {
final StringBuffer buf = new StringBuffer();
if ( args.isEmpty() ) {
throw new IllegalArgumentException( "First Argument in arglist must be object " + "to which method is applied" );
}
buf.append( "TO_CHAR(SDO_UTIL.TO_WKTGEOMETRY(" ).append( args.get( 0 ) ).append( "))" );
return buf.toString();
}
}
/**
* HQL Spatial relation function.
*/
private class SpatialRelateFunction extends StandardSQLFunction {
private final int relation;
private SpatialRelateFunction(final String name, final int relation) {
super(
name, isOGCStrict() ? StandardBasicTypes.BOOLEAN
: new SDOBooleanType()
);
this.relation = relation;
}
public String render(Type firstArgumentType, final List args, final SessionFactoryImplementor factory) {
if ( args.size() < 2 ) {
throw new QueryException(
"Spatial relate functions require at least two arguments"
);
}
return isOGCStrict() ?
getOGCSpatialRelateSQL(
(String) args.get( 0 ),
(String) args.get( 1 ), this.relation
) :
getNativeSpatialRelateSQL(
(String) args.get( 0 ),
(String) args.get( 1 ), this.relation
);
}
}
private class SpatialAnalysisFunction extends StandardSQLFunction {
private final int analysis;
private SpatialAnalysisFunction(String name, Type returnType, int analysis) {
super( name, returnType );
this.analysis = analysis;
}
private SpatialAnalysisFunction(String name, int analysis) {
this( name, null, analysis );
}
public String render(Type firstArgumentType, List args, SessionFactoryImplementor factory) {
return isOGCStrict() ? getSpatialAnalysisSQL(
args, this.analysis,
false
) : getNativeSpatialAnalysisSQL( args, analysis );
}
}
private class SpatialAggregationFunction extends StandardSQLFunction {
private final int aggregation;
private SpatialAggregationFunction(String name, boolean isProjection, int aggregation) {
super( name );
this.aggregation = aggregation;
}
public String render(Type firstArgumentType, List args, SessionFactoryImplementor factory) {
return getNativeSpatialAggregateSQL(
(String) args.get( 0 ),
this.aggregation
);
}
}
}

View File

@ -1,92 +0,0 @@
/*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for spatial (geographic) data.
*
* Copyright © 2007-2012 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
*/
package org.hibernate.spatial.dialect.oracle;
import java.sql.Array;
/**
* @author Karel Maesen, Geovise BVBA
* creation-date: Jul 1, 2010
*/
class Ordinates {
static final String TYPE_NAME = "MDSYS.SDO_ORDINATE_ARRAY";
private Double[] ordinates;
public Ordinates(Double[] ordinates) {
this.ordinates = ordinates;
}
public Ordinates(Array array) {
if ( array == null ) {
this.ordinates = new Double[] { };
return;
}
try {
final Number[] ords = (Number[]) array.getArray();
this.ordinates = new Double[ords.length];
for ( int i = 0; i < ords.length; i++ ) {
this.ordinates[i] = ords[i] != null ? ords[i].doubleValue()
: Double.NaN;
}
}
catch ( Exception e ) {
throw new RuntimeException( e );
}
}
public Double[] getOrdinateArray() {
return this.ordinates;
}
public Double[] getOrdinatesArray(int startPosition, int endPosition) {
final Double[] a = new Double[endPosition - startPosition];
System.arraycopy( this.ordinates, startPosition - 1, a, 0, a.length );
return a;
}
public Double[] getOrdinatesArray(int startPosition) {
final Double[] a = new Double[this.ordinates.length - ( startPosition - 1 )];
System.arraycopy( this.ordinates, startPosition - 1, a, 0, a.length );
return a;
}
public String toString() {
return SDOGeometry.arrayToString( this.ordinates );
}
public void addOrdinates(Double[] ordinatesToAdd) {
final Double[] newOrdinates = new Double[this.ordinates.length
+ ordinatesToAdd.length];
System.arraycopy(
this.ordinates, 0, newOrdinates, 0,
this.ordinates.length
);
System.arraycopy(
ordinatesToAdd, 0, newOrdinates,
this.ordinates.length, ordinatesToAdd.length
);
this.ordinates = newOrdinates;
}
}

View File

@ -1,131 +0,0 @@
/*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for spatial (geographic) data.
*
* Copyright © 2007-2012 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
*/
package org.hibernate.spatial.dialect.oracle;
/**
* @author Karel Maesen, Geovise BVBA
* creation-date: Jun 30, 2010
*/
class SDOGType {
private int dimension = 2;
private int lrsDimension;
private TypeGeometry typeGeometry = TypeGeometry.UNKNOWN_GEOMETRY;
public SDOGType(int dimension, int lrsDimension,
TypeGeometry typeGeometry) {
setDimension( dimension );
setLrsDimension( lrsDimension );
setTypeGeometry( typeGeometry );
}
public int getDimension() {
return dimension;
}
public void setDimension(int dimension) {
if ( dimension < 2 || dimension > 4 ) {
throw new IllegalArgumentException(
"Dimension can only be 2,3 or 4."
);
}
this.dimension = dimension;
}
public TypeGeometry getTypeGeometry() {
return typeGeometry;
}
public void setTypeGeometry(TypeGeometry typeGeometry) {
this.typeGeometry = typeGeometry;
}
public int getLRSDimension() {
if ( this.lrsDimension > 0 ) {
return this.lrsDimension;
}
else if ( this.lrsDimension == 0 && this.dimension == 4 ) {
return 4;
}
return 0;
}
public int getZDimension() {
if ( this.dimension > 2 ) {
if ( !isLRSGeometry() ) {
return this.dimension;
}
else {
return ( getLRSDimension() < this.dimension ? 4 : 3 );
}
}
return 0;
}
public boolean isLRSGeometry() {
return ( this.lrsDimension > 0 || ( this.lrsDimension == 0 && this.dimension == 4 ) );
}
public void setLrsDimension(int lrsDimension) {
if ( lrsDimension != 0 && lrsDimension > this.dimension ) {
throw new IllegalArgumentException(
"lrsDimension must be 0 or lower or equal to dimenstion."
);
}
this.lrsDimension = lrsDimension;
}
public int intValue() {
int v = this.dimension * 1000;
v += lrsDimension * 100;
v += typeGeometry.intValue();
return v;
}
public static SDOGType parse(int v) {
final int dim = v / 1000;
v -= dim * 1000;
final int lrsDim = v / 100;
v -= lrsDim * 100;
final TypeGeometry typeGeometry = TypeGeometry.parse( v );
return new SDOGType( dim, lrsDim, typeGeometry );
}
public static SDOGType parse(Object datum) {
try {
final int v = ( (Number) datum ).intValue();
return parse( v );
}
catch ( Exception e ) {
throw new RuntimeException( e );
}
}
public String toString() {
return Integer.toString( this.intValue() );
}
}

View File

@ -1,347 +0,0 @@
/*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for spatial (geographic) data.
*
* Copyright © 2007-2012 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
*/
package org.hibernate.spatial.dialect.oracle;
import java.sql.Array;
import java.sql.SQLException;
import java.sql.Struct;
import java.util.ArrayList;
import java.util.List;
/**
* @author Karel Maesen, Geovise BVBA
* creation-date: Jun 30, 2010
*/
class SDOGeometry {
private static final String SQL_TYPE_NAME = "MDSYS.SDO_GEOMETRY";
private SDOGType gtype;
private int srid;
private SDOPoint point;
private ElemInfo info;
private Ordinates ordinates;
public SDOGeometry() {
}
public static String getTypeName() {
return SQL_TYPE_NAME;
}
static String arrayToString(Object array) {
if ( array == null || java.lang.reflect.Array.getLength( array ) == 0 ) {
return "()";
}
final int length = java.lang.reflect.Array.getLength( array );
final StringBuilder stb = new StringBuilder();
stb.append( "(" ).append( java.lang.reflect.Array.get( array, 0 ) );
for ( int i = 1; i < length; i++ ) {
stb.append( "," ).append( java.lang.reflect.Array.get( array, i ) );
}
stb.append( ")" );
return stb.toString();
}
/**
* This joins an array of SDO_GEOMETRIES to a SDOGeometry of type
* COLLECTION
*
* @param sdoElements The SDO_geometries to join into an SDO Geometry Collection
*
* @return The SDO Collection Geometry
*/
public static SDOGeometry join(SDOGeometry[] sdoElements) {
final SDOGeometry sdoCollection = new SDOGeometry();
if ( sdoElements == null || sdoElements.length == 0 ) {
sdoCollection.setGType( new SDOGType( 2, 0, TypeGeometry.COLLECTION ) );
}
else {
final SDOGeometry firstElement = sdoElements[0];
final int dim = firstElement.getGType().getDimension();
final int lrsDim = firstElement.getGType().getLRSDimension();
sdoCollection.setGType( new SDOGType( dim, lrsDim, TypeGeometry.COLLECTION ) );
int ordinatesOffset = 1;
for ( int i = 0; i < sdoElements.length; i++ ) {
final ElemInfo element = sdoElements[i].getInfo();
final Double[] ordinates = sdoElements[i].getOrdinates().getOrdinateArray();
if ( element != null && element.getSize() > 0 ) {
final int shift = ordinatesOffset - element.getOrdinatesOffset( 0 );
shiftOrdinateOffset( element, shift );
sdoCollection.addElement( element );
sdoCollection.addOrdinates( ordinates );
ordinatesOffset += ordinates.length;
}
}
}
return sdoCollection;
}
private static void shiftOrdinateOffset(ElemInfo elemInfo, int offset) {
for ( int i = 0; i < elemInfo.getSize(); i++ ) {
final int newOffset = elemInfo.getOrdinatesOffset( i ) + offset;
elemInfo.setOrdinatesOffset( i, newOffset );
}
}
private static SDOGType deriveGTYPE(ElementType elementType,
SDOGeometry origGeom) {
switch ( elementType ) {
case POINT:
case ORIENTATION:
return new SDOGType(
origGeom.getDimension(), origGeom
.getLRSDimension(), TypeGeometry.POINT
);
case POINT_CLUSTER:
return new SDOGType(
origGeom.getDimension(), origGeom
.getLRSDimension(), TypeGeometry.MULTIPOINT
);
case LINE_ARC_SEGMENTS:
case LINE_STRAITH_SEGMENTS:
case COMPOUND_LINE:
return new SDOGType(
origGeom.getDimension(), origGeom
.getLRSDimension(), TypeGeometry.LINE
);
case COMPOUND_EXTERIOR_RING:
case EXTERIOR_RING_ARC_SEGMENTS:
case EXTERIOR_RING_CIRCLE:
case EXTERIOR_RING_RECT:
case EXTERIOR_RING_STRAIGHT_SEGMENTS:
return new SDOGType(
origGeom.getDimension(), origGeom
.getLRSDimension(), TypeGeometry.POLYGON
);
default:
return null;
}
}
public static SDOGeometry load(Struct struct) {
Object[] data;
try {
data = struct.getAttributes();
}
catch ( SQLException e ) {
throw new RuntimeException( e );
}
final SDOGeometry geom = new SDOGeometry();
geom.setGType( SDOGType.parse( data[0] ) );
geom.setSRID( data[1] );
if ( data[2] != null ) {
geom.setPoint( new SDOPoint( (Struct) data[2] ) );
}
geom.setInfo( new ElemInfo( (Array) data[3] ) );
geom.setOrdinates( new Ordinates( (Array) data[4] ) );
return geom;
}
public ElemInfo getInfo() {
return info;
}
public void setInfo(ElemInfo info) {
this.info = info;
}
public SDOGType getGType() {
return gtype;
}
public void setGType(SDOGType gtype) {
this.gtype = gtype;
}
public Ordinates getOrdinates() {
return ordinates;
}
public void setOrdinates(Ordinates ordinates) {
this.ordinates = ordinates;
}
public SDOPoint getPoint() {
return point;
}
public void setPoint(SDOPoint point) {
this.point = point;
}
public int getSRID() {
return srid;
}
public void setSRID(int srid) {
this.srid = srid;
}
private void setSRID(Object datum) {
if ( datum == null ) {
this.srid = 0;
return;
}
try {
this.srid = ( (Number) datum ).intValue();
}
catch ( Exception e ) {
throw new RuntimeException( e );
}
}
public boolean isLRSGeometry() {
return gtype.isLRSGeometry();
}
public int getDimension() {
return gtype.getDimension();
}
public int getLRSDimension() {
return gtype.getLRSDimension();
}
public int getZDimension() {
return gtype.getZDimension();
}
/**
* Gets the number of elements or compound elements.
* <p/>
* Subelements of a compound element are not counted.
*
* @return the number of elements
*/
public int getNumElements() {
int cnt = 0;
int i = 0;
while ( i < info.getSize() ) {
if ( info.getElementType( i ).isCompound() ) {
final int numCompounds = info.getNumCompounds( i );
i += 1 + numCompounds;
}
else {
i++;
}
cnt++;
}
return cnt;
}
public String toString() {
final StringBuilder stb = new StringBuilder();
stb.append( "(" ).append( gtype ).append( "," ).append( srid ).append( "," )
.append( point ).append( "," ).append( info ).append( "," ).append(
ordinates
).append( ")" );
return stb.toString();
}
public void addOrdinates(Double[] newOrdinates) {
if ( this.ordinates == null ) {
this.ordinates = new Ordinates( newOrdinates );
}
else {
this.ordinates.addOrdinates( newOrdinates );
}
}
public void addElement(ElemInfo element) {
if ( this.info == null ) {
this.info = element;
}
else {
this.info.addElement( element );
}
}
/**
* If this SDOGeometry is a COLLECTION, this method returns an array of
* the SDO_GEOMETRIES that make up the collection. If not a Collection,
* an array containing this SDOGeometry is returned.
*
* @return collection elements as individual SDO_GEOMETRIES
*/
public SDOGeometry[] getElementGeometries() {
if ( getGType().getTypeGeometry() == TypeGeometry.COLLECTION ) {
final List<SDOGeometry> elements = new ArrayList<SDOGeometry>();
int i = 0;
while ( i < this.getNumElements() ) {
final ElementType et = this.getInfo().getElementType( i );
int next = i + 1;
// if the element is an exterior ring, or a compound
// element, then this geometry spans multiple elements.
if ( et.isExteriorRing() ) {
// then next element is the
// first non-interior ring
while ( next < this.getNumElements() ) {
if ( !this.getInfo().getElementType( next )
.isInteriorRing() ) {
break;
}
next++;
}
}
else if ( et.isCompound() ) {
next = i + this.getInfo().getNumCompounds( i ) + 1;
}
final SDOGeometry elemGeom = new SDOGeometry();
final SDOGType elemGtype = deriveGTYPE( this.getInfo().getElementType( i ), this );
elemGeom.setGType( elemGtype );
elemGeom.setSRID( this.getSRID() );
final ElemInfo elemInfo = new ElemInfo( this.getInfo().getElement( i ) );
shiftOrdinateOffset( elemInfo, -elemInfo.getOrdinatesOffset( 0 ) + 1 );
elemGeom.setInfo( elemInfo );
final int startPosition = this.getInfo().getOrdinatesOffset( i );
Ordinates elemOrdinates = null;
if ( next < this.getNumElements() ) {
final int endPosition = this.getInfo().getOrdinatesOffset( next );
elemOrdinates = new Ordinates(
this.getOrdinates()
.getOrdinatesArray( startPosition, endPosition )
);
}
else {
elemOrdinates = new Ordinates(
this.getOrdinates()
.getOrdinatesArray( startPosition )
);
}
elemGeom.setOrdinates( elemOrdinates );
elements.add( elemGeom );
i = next;
}
return elements.toArray( new SDOGeometry[elements.size()] );
}
else {
return new SDOGeometry[] { this };
}
}
}

View File

@ -23,6 +23,7 @@ package org.hibernate.spatial.dialect.oracle;
import java.sql.Types;
import org.geolatte.geom.codec.db.oracle.OracleJDBCTypeFactory;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;

View File

@ -21,22 +21,10 @@
package org.hibernate.spatial.dialect.oracle;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Types;
import com.vividsolutions.jts.algorithm.CGAlgorithms;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryCollection;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.MultiLineString;
import com.vividsolutions.jts.geom.MultiPoint;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;
import org.geolatte.geom.Geometry;
import org.geolatte.geom.codec.db.oracle.Encoders;
import org.geolatte.geom.codec.db.oracle.OracleJDBCTypeFactory;
import org.geolatte.geom.codec.db.oracle.SDOGeometry;
import org.hibernate.HibernateException;
import org.hibernate.spatial.helper.FinderException;
import org.hibernate.type.descriptor.ValueBinder;
@ -44,12 +32,18 @@ import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Types;
/**
* @author Karel Maesen, Geovise BVBA
* creation-date: 8/22/11
*/
class SDOGeometryValueBinder<J> implements ValueBinder<J> {
private static final String SQL_TYPE_NAME = "MDSYS.SDO_GEOMETRY";
private final OracleJDBCTypeFactory typeFactory;
private final JavaTypeDescriptor<J> javaTypeDescriptor;
@ -62,11 +56,11 @@ class SDOGeometryValueBinder<J> implements ValueBinder<J> {
@Override
public void bind(PreparedStatement st, J value, int index, WrapperOptions options) throws SQLException {
if ( value == null ) {
st.setNull( index, Types.STRUCT, SDOGeometry.getTypeName() );
st.setNull( index, Types.STRUCT, SQL_TYPE_NAME );
}
else {
final Geometry jtsGeom = javaTypeDescriptor.unwrap( value, Geometry.class, options );
final Object dbGeom = toNative( jtsGeom, st.getConnection() );
final Geometry geometry = javaTypeDescriptor.unwrap( value, Geometry.class, options );
final Object dbGeom = toNative( geometry, st.getConnection() );
st.setObject( index, dbGeom );
}
}
@ -75,345 +69,20 @@ class SDOGeometryValueBinder<J> implements ValueBinder<J> {
return typeFactory.createStruct( geom, conn );
}
private Object toNative(Geometry jtsGeom, Connection connection) {
final SDOGeometry geom = convertJTSGeometry( jtsGeom );
if ( geom != null ) {
try {
return store( geom, connection );
}
catch ( SQLException e ) {
throw new HibernateException(
"Problem during conversion from JTS to SDOGeometry", e
);
}
catch ( FinderException e ) {
throw new HibernateException(
"OracleConnection could not be retrieved for creating SDOGeometry STRUCT", e
);
}
}
else {
throw new UnsupportedOperationException(
"Conversion of "
+ jtsGeom.getClass().getSimpleName()
+ " to Oracle STRUCT not supported"
);
}
}
private SDOGeometry convertJTSGeometry(Geometry jtsGeom) {
SDOGeometry geom = null;
if ( jtsGeom instanceof Point ) {
geom = convertJTSPoint( (Point) jtsGeom );
}
else if ( jtsGeom instanceof LineString ) {
geom = convertJTSLineString( (LineString) jtsGeom );
}
else if ( jtsGeom instanceof Polygon ) {
geom = convertJTSPolygon( (Polygon) jtsGeom );
}
else if ( jtsGeom instanceof MultiPoint ) {
geom = convertJTSMultiPoint( (MultiPoint) jtsGeom );
}
else if ( jtsGeom instanceof MultiLineString ) {
geom = convertJTSMultiLineString( (MultiLineString) jtsGeom );
}
else if ( jtsGeom instanceof MultiPolygon ) {
geom = convertJTSMultiPolygon( (MultiPolygon) jtsGeom );
}
else if ( jtsGeom instanceof GeometryCollection ) {
geom = convertJTSGeometryCollection( (GeometryCollection) jtsGeom );
}
return geom;
}
private SDOGeometry convertJTSGeometryCollection(
GeometryCollection collection) {
final SDOGeometry[] sdoElements = new SDOGeometry[collection.getNumGeometries()];
for ( int i = 0; i < collection.getNumGeometries(); i++ ) {
final Geometry geom = collection.getGeometryN( i );
sdoElements[i] = convertJTSGeometry( geom );
}
final SDOGeometry ccollect = SDOGeometry.join( sdoElements );
ccollect.setSRID( collection.getSRID() );
return ccollect;
}
private SDOGeometry convertJTSMultiPolygon(MultiPolygon multiPolygon) {
final int dim = getCoordDimension( multiPolygon );
final int lrsPos = getCoordinateLrsPosition( multiPolygon );
final SDOGeometry geom = new SDOGeometry();
geom.setGType( new SDOGType( dim, lrsPos, TypeGeometry.MULTIPOLYGON ) );
geom.setSRID( multiPolygon.getSRID() );
for ( int i = 0; i < multiPolygon.getNumGeometries(); i++ ) {
try {
final Polygon pg = (Polygon) multiPolygon.getGeometryN( i );
addPolygon( geom, pg );
}
catch ( Exception e ) {
throw new RuntimeException(
"Found geometry that was not a geometry in MultiPolygon"
);
}
}
return geom;
}
private SDOGeometry convertJTSLineString(LineString lineString) {
final int dim = getCoordDimension( lineString );
final int lrsPos = getCoordinateLrsPosition( lineString );
final boolean isLrs = lrsPos > 0;
final Double[] ordinates = convertCoordinates( lineString.getCoordinates(), dim, isLrs );
final SDOGeometry geom = new SDOGeometry();
geom.setGType( new SDOGType( dim, lrsPos, TypeGeometry.LINE ) );
geom.setSRID( lineString.getSRID() );
final ElemInfo info = new ElemInfo( 1 );
info.setElement( 0, 1, ElementType.LINE_STRAITH_SEGMENTS, 0 );
geom.setInfo( info );
geom.setOrdinates( new Ordinates( ordinates ) );
return geom;
}
private SDOGeometry convertJTSMultiPoint(MultiPoint multiPoint) {
final int dim = getCoordDimension( multiPoint );
final int lrsDim = getCoordinateLrsPosition( multiPoint );
final boolean isLrs = ( lrsDim != 0 );
final SDOGeometry geom = new SDOGeometry();
geom.setGType( new SDOGType( dim, lrsDim, TypeGeometry.MULTIPOINT ) );
geom.setSRID( multiPoint.getSRID() );
final ElemInfo info = new ElemInfo( multiPoint.getNumPoints() );
int oordinatesOffset = 1;
Double[] ordinates = new Double[] { };
for ( int i = 0; i < multiPoint.getNumPoints(); i++ ) {
info.setElement( i, oordinatesOffset, ElementType.POINT, 0 );
ordinates = convertAddCoordinates(
ordinates, multiPoint
.getGeometryN( i ).getCoordinates(), dim, isLrs
);
oordinatesOffset = ordinates.length + 1;
}
geom.setInfo( info );
geom.setOrdinates( new Ordinates( ordinates ) );
return geom;
}
private SDOGeometry convertJTSPoint(Point jtsGeom) {
final int dim = getCoordDimension( jtsGeom );
final int lrsDim = getCoordinateLrsPosition( jtsGeom );
final boolean isLrs = ( lrsDim != 0 );
final Double[] coord = convertCoordinates( jtsGeom.getCoordinates(), dim, isLrs );
final SDOGeometry geom = new SDOGeometry();
geom.setGType( new SDOGType( dim, lrsDim, TypeGeometry.POINT ) );
geom.setSRID( jtsGeom.getSRID() );
final ElemInfo info = new ElemInfo( 1 );
info.setElement( 0, 1, ElementType.POINT, 1 );
geom.setInfo( info );
geom.setOrdinates( new Ordinates( coord ) );
return geom;
}
private SDOGeometry convertJTSPolygon(Polygon polygon) {
final int dim = getCoordDimension( polygon );
final int lrsPos = getCoordinateLrsPosition( polygon );
final SDOGeometry geom = new SDOGeometry();
geom.setGType( new SDOGType( dim, lrsPos, TypeGeometry.POLYGON ) );
geom.setSRID( polygon.getSRID() );
addPolygon( geom, polygon );
return geom;
}
private void addPolygon(SDOGeometry geom, Polygon polygon) {
final int numInteriorRings = polygon.getNumInteriorRing();
final ElemInfo info = new ElemInfo( numInteriorRings + 1 );
int ordinatesPreviousOffset = 0;
if ( geom.getOrdinates() != null ) {
ordinatesPreviousOffset = geom.getOrdinates().getOrdinateArray().length;
}
int ordinatesOffset = ordinatesPreviousOffset + 1;
Double[] ordinates = new Double[] { };
for ( int i = 0; i < info.getSize(); i++ ) {
ElementType et;
Coordinate[] coords;
if ( i == 0 ) {
et = ElementType.EXTERIOR_RING_STRAIGHT_SEGMENTS;
coords = polygon.getExteriorRing().getCoordinates();
if ( !CGAlgorithms.isCCW( coords ) ) {
coords = reverseRing( coords );
}
}
else {
et = ElementType.INTERIOR_RING_STRAIGHT_SEGMENTS;
coords = polygon.getInteriorRingN( i - 1 ).getCoordinates();
if ( CGAlgorithms.isCCW( coords ) ) {
coords = reverseRing( coords );
}
}
info.setElement( i, ordinatesOffset, et, 0 );
ordinates = convertAddCoordinates(
ordinates, coords, geom
.getDimension(), geom.isLRSGeometry()
);
ordinatesOffset = ordinatesPreviousOffset + ordinates.length + 1;
}
geom.addElement( info );
geom.addOrdinates( ordinates );
}
private SDOGeometry convertJTSMultiLineString(
MultiLineString multiLineString) {
final int dim = getCoordDimension( multiLineString );
final int lrsDim = getCoordinateLrsPosition( multiLineString );
final boolean isLrs = ( lrsDim != 0 );
final SDOGeometry geom = new SDOGeometry();
geom.setGType( new SDOGType( dim, lrsDim, TypeGeometry.MULTILINE ) );
geom.setSRID( multiLineString.getSRID() );
final ElemInfo info = new ElemInfo( multiLineString.getNumGeometries() );
int oordinatesOffset = 1;
Double[] ordinates = new Double[] { };
for ( int i = 0; i < multiLineString.getNumGeometries(); i++ ) {
info.setElement(
i, oordinatesOffset,
ElementType.LINE_STRAITH_SEGMENTS, 0
);
ordinates = convertAddCoordinates(
ordinates, multiLineString
.getGeometryN( i ).getCoordinates(), dim, isLrs
);
oordinatesOffset = ordinates.length + 1;
}
geom.setInfo( info );
geom.setOrdinates( new Ordinates( ordinates ) );
return geom;
}
private Double[] convertAddCoordinates(Double[] ordinates, Coordinate[] coordinates, int dim, boolean isLrs) {
final Double[] no = convertCoordinates( coordinates, dim, isLrs );
final Double[] newordinates = new Double[ordinates.length + no.length];
System.arraycopy( ordinates, 0, newordinates, 0, ordinates.length );
System.arraycopy( no, 0, newordinates, ordinates.length, no.length );
return newordinates;
}
/**
* Convert the coordinates to a double array for purposes of persisting them
* to the database. Note that Double.NaN values are to be converted to null
* values in the array.
*
* @param coordinates Coordinates to be converted to the array
* @param dim Coordinate dimension
* @param isLrs true if the coordinates contain measures
*
* @return
*/
private Double[] convertCoordinates(Coordinate[] coordinates, int dim,
boolean isLrs) {
if ( isLrs ) {
throw new UnsupportedOperationException();
}
if ( dim > 4 ) {
throw new IllegalArgumentException(
"Dim parameter value cannot be greater than 4"
);
}
final Double[] converted = new Double[coordinates.length * dim];
for ( int i = 0; i < coordinates.length; i++ ) {
final Coordinate c = coordinates[i];
// set the X and Y values
converted[i * dim] = toDouble( c.x );
converted[i * dim + 1] = toDouble( c.y );
if ( dim == 3 ) {
converted[i * dim + 2] = toDouble( c.z );
}
// else if ( dim == 4 ) {
// converted[i * dim + 2] = toDouble( c.z );
// converted[i * dim + 3] = toDouble( c.m );
// }
}
return converted;
}
/**
* This method converts a double primitive to a Double wrapper instance, but
* treats a Double.NaN value as null.
*
* @param d the value to be converted
*
* @return A Double instance of d, Null if the parameter is Double.NaN
*/
private Double toDouble(double d) {
return Double.isNaN( d ) ? null : d;
}
/**
* Return the dimension required for building the gType in the SDOGeometry
* object. Has support for LRS type geometries.
*
* @param geom and instance of the Geometry class from which the dimension is
* being extracted.
*
* @return number of dimensions for purposes of creating the
* SDOGeometry.SDOGType
*/
private int getCoordDimension(Geometry geom) {
// This is awkward, I have to create an MCoordinate to discover what the
// dimension is.
// This shall be cleaner if MCoordinate.getOrdinate(int ordinateIndex)
// is moved to the
// Coordinate class
final Coordinate c = geom.getCoordinate();
int d = 0;
if ( c != null ) {
if ( !Double.isNaN( c.x ) ) {
d++;
}
if ( !Double.isNaN( c.y ) ) {
d++;
}
if ( !Double.isNaN( c.z ) ) {
d++;
}
// if ( !Double.isNaN( c.m ) ) {
// d++;
// }
}
return d;
}
/**
* Returns the lrs measure position for purposes of building the gType for
* an oracle geometry. At this point and time, I'll have to assume that the
* measure is always put at the end of the ordinate tuple, even though it
* technically wouldn't have to. This method bases its decision on whether
* the first coordinate has a measure value, as measure are required for the
* very first and last measure in a CoordinateSequence. If there is no
* measure value, 0 is returned.
*
* @param geom and instance of the Geometry class from which the lrs position
* is being extracted.
*
* @return the lrs position for the SDOGeometry.SDOGType
*/
private int getCoordinateLrsPosition(Geometry geom) {
final int measurePos = 0;
// if ( c != null && !Double.isNaN( c.m ) ) {
// measurePos = ( Double.isNaN( c.z ) ) ? 3 : 4;
// }
return measurePos;
}
// reverses ordinates in a coordinate array in-place
private Coordinate[] reverseRing(Coordinate[] ar) {
for ( int i = 0; i < ar.length / 2; i++ ) {
final Coordinate cs = ar[i];
ar[i] = ar[ar.length - 1 - i];
ar[ar.length - 1 - i] = cs;
}
return ar;
}
private Object toNative(Geometry geom, Connection connection) {
final SDOGeometry sdoGeom = Encoders.encode(geom);
if (geom != null) {
try {
return store(sdoGeom, connection);
} catch (SQLException e) {
throw new HibernateException("Problem during conversion from JTS to SDOGeometry", e);
} catch (FinderException e) {
throw new HibernateException("OracleConnection could not be retrieved for creating SDOGeometry " +
"STRUCT", e);
}
} else {
throw new UnsupportedOperationException("Conversion of " + geom.getClass().getSimpleName() + " to Oracle STRUCT not supported");
}
}
}

View File

@ -25,22 +25,11 @@ import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Struct;
import java.util.ArrayList;
import java.util.List;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.CoordinateSequence;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.MultiLineString;
import com.vividsolutions.jts.geom.MultiPoint;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;
import org.hibernate.spatial.jts.Circle;
import org.geolatte.geom.Geometry;
import org.geolatte.geom.codec.db.oracle.Decoders;
import org.geolatte.geom.codec.db.oracle.SDOGeometry;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.sql.BasicExtractor;
@ -57,9 +46,6 @@ import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
*/
public class SDOGeometryValueExtractor<X> extends BasicExtractor<X> {
private static GeometryFactory geometryFactory = new GeometryFactory();
/**
* Creates instance
*
@ -73,25 +59,19 @@ public class SDOGeometryValueExtractor<X> extends BasicExtractor<X> {
@Override
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
final Object geomObj = rs.getObject( name );
return getJavaDescriptor().wrap( toJTS( geomObj ), options );
return getJavaDescriptor().wrap( convert(geomObj), options );
}
@Override
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
final Object geomObj = statement.getObject( index );
return getJavaDescriptor().wrap( toJTS( geomObj ), options );
return getJavaDescriptor().wrap( convert(geomObj), options );
}
@Override
protected X doExtract(CallableStatement statement, String name, WrapperOptions options) throws SQLException {
final Object geomObj = statement.getObject( name );
return getJavaDescriptor().wrap( toJTS( geomObj ), options );
}
//TODO Clean up below this point
protected GeometryFactory getGeometryFactory() {
return geometryFactory;
return getJavaDescriptor().wrap( convert(geomObj), options );
}
/**
@ -101,455 +81,16 @@ public class SDOGeometryValueExtractor<X> extends BasicExtractor<X> {
*
* @return The JTS Geometry value
*/
public Geometry toJTS(Object struct) {
public Geometry convert(Object struct) {
if ( struct == null ) {
return null;
}
final SDOGeometry sdogeom = SDOGeometry.load( (Struct) struct );
return convert2JTS( sdogeom );
return toGeomerty(sdogeom);
}
private Geometry convert2JTS(SDOGeometry sdoGeom) {
final int dim = sdoGeom.getGType().getDimension();
final int lrsDim = sdoGeom.getGType().getLRSDimension();
Geometry result = null;
switch ( sdoGeom.getGType().getTypeGeometry() ) {
case POINT:
result = convertSDOPoint( sdoGeom );
break;
case LINE:
result = convertSDOLine( dim, lrsDim, sdoGeom );
break;
case POLYGON:
result = convertSDOPolygon( dim, lrsDim, sdoGeom );
break;
case MULTIPOINT:
result = convertSDOMultiPoint( dim, lrsDim, sdoGeom );
break;
case MULTILINE:
result = convertSDOMultiLine( dim, lrsDim, sdoGeom );
break;
case MULTIPOLYGON:
result = convertSDOMultiPolygon( dim, lrsDim, sdoGeom );
break;
case COLLECTION:
result = convertSDOCollection( dim, lrsDim, sdoGeom );
break;
default:
throw new IllegalArgumentException(
"Type not supported: "
+ sdoGeom.getGType().getTypeGeometry()
);
}
result.setSRID( sdoGeom.getSRID() );
return result;
}
private Geometry convertSDOCollection(int dim, int lrsDim, SDOGeometry sdoGeom) {
final List<Geometry> geometries = new ArrayList<Geometry>();
for ( SDOGeometry elemGeom : sdoGeom.getElementGeometries() ) {
geometries.add( convert2JTS( elemGeom ) );
}
final Geometry[] geomArray = new Geometry[geometries.size()];
return getGeometryFactory().createGeometryCollection(
geometries.toArray( geomArray )
);
}
private Point convertSDOPoint(SDOGeometry sdoGeom) {
Double[] ordinates = sdoGeom.getOrdinates().getOrdinateArray();
if ( ordinates.length == 0 ) {
if ( sdoGeom.getDimension() == 2 ) {
ordinates = new Double[] {
sdoGeom.getPoint().x,
sdoGeom.getPoint().y
};
}
else {
ordinates = new Double[] {
sdoGeom.getPoint().x,
sdoGeom.getPoint().y, sdoGeom.getPoint().z
};
}
}
final CoordinateSequence cs = convertOrdinateArray( ordinates, sdoGeom );
return getGeometryFactory().createPoint( cs );
}
private MultiPoint convertSDOMultiPoint(int dim, int lrsDim, SDOGeometry sdoGeom) {
final Double[] ordinates = sdoGeom.getOrdinates().getOrdinateArray();
final CoordinateSequence cs = convertOrdinateArray( ordinates, sdoGeom );
final MultiPoint multipoint = getGeometryFactory().createMultiPoint( cs );
return multipoint;
}
private LineString convertSDOLine(int dim, int lrsDim, SDOGeometry sdoGeom) {
final boolean lrs = sdoGeom.isLRSGeometry();
final ElemInfo info = sdoGeom.getInfo();
CoordinateSequence cs = null;
int i = 0;
while ( i < info.getSize() ) {
if ( info.getElementType( i ).isCompound() ) {
final int numCompounds = info.getNumCompounds( i );
cs = add( cs, getCompoundCSeq( i + 1, i + numCompounds, sdoGeom ) );
i += 1 + numCompounds;
}
else {
cs = add( cs, getElementCSeq( i, sdoGeom, false ) );
i++;
}
}
if ( lrs ) {
throw new UnsupportedOperationException();
}
else {
return getGeometryFactory().createLineString( cs );
}
}
private MultiLineString convertSDOMultiLine(int dim, int lrsDim, SDOGeometry sdoGeom) {
final boolean lrs = sdoGeom.isLRSGeometry();
if ( lrs ) {
throw new UnsupportedOperationException();
}
final ElemInfo info = sdoGeom.getInfo();
final LineString[] lines = new LineString[sdoGeom.getInfo().getSize()];
int i = 0;
while ( i < info.getSize() ) {
CoordinateSequence cs = null;
if ( info.getElementType( i ).isCompound() ) {
final int numCompounds = info.getNumCompounds( i );
cs = add( cs, getCompoundCSeq( i + 1, i + numCompounds, sdoGeom ) );
final LineString line = getGeometryFactory().createLineString( cs );
lines[i] = line;
i += 1 + numCompounds;
}
else {
cs = add( cs, getElementCSeq( i, sdoGeom, false ) );
final LineString line = getGeometryFactory().createLineString( cs );
lines[i] = line;
i++;
}
}
return getGeometryFactory().createMultiLineString( lines );
}
private Geometry convertSDOPolygon(int dim, int lrsDim, SDOGeometry sdoGeom) {
LinearRing shell = null;
final LinearRing[] holes = new LinearRing[sdoGeom.getNumElements() - 1];
final ElemInfo info = sdoGeom.getInfo();
int i = 0;
int idxInteriorRings = 0;
while ( i < info.getSize() ) {
CoordinateSequence cs = null;
int numCompounds = 0;
if ( info.getElementType( i ).isCompound() ) {
numCompounds = info.getNumCompounds( i );
cs = add( cs, getCompoundCSeq( i + 1, i + numCompounds, sdoGeom ) );
}
else {
cs = add( cs, getElementCSeq( i, sdoGeom, false ) );
}
if ( info.getElementType( i ).isInteriorRing() ) {
holes[idxInteriorRings] = getGeometryFactory()
.createLinearRing( cs );
idxInteriorRings++;
}
else {
shell = getGeometryFactory().createLinearRing( cs );
}
i += 1 + numCompounds;
}
return getGeometryFactory().createPolygon( shell, holes );
}
private MultiPolygon convertSDOMultiPolygon(int dim, int lrsDim, SDOGeometry sdoGeom) {
List<LinearRing> holes = new ArrayList<LinearRing>();
final List<Polygon> polygons = new ArrayList<Polygon>();
final ElemInfo info = sdoGeom.getInfo();
LinearRing shell = null;
int i = 0;
while ( i < info.getSize() ) {
CoordinateSequence cs = null;
int numCompounds = 0;
if ( info.getElementType( i ).isCompound() ) {
numCompounds = info.getNumCompounds( i );
cs = add( cs, getCompoundCSeq( i + 1, i + numCompounds, sdoGeom ) );
}
else {
cs = add( cs, getElementCSeq( i, sdoGeom, false ) );
}
if ( info.getElementType( i ).isInteriorRing() ) {
final LinearRing lr = getGeometryFactory().createLinearRing( cs );
holes.add( lr );
}
else {
if ( shell != null ) {
final Polygon polygon = getGeometryFactory().createPolygon(
shell,
holes.toArray( new LinearRing[holes.size()] )
);
polygons.add( polygon );
shell = null;
}
shell = getGeometryFactory().createLinearRing( cs );
holes = new ArrayList<LinearRing>();
}
i += 1 + numCompounds;
}
if ( shell != null ) {
final Polygon polygon = getGeometryFactory().createPolygon(
shell,
holes.toArray( new LinearRing[holes.size()] )
);
polygons.add( polygon );
}
return getGeometryFactory().createMultiPolygon( polygons.toArray( new Polygon[polygons.size()] ) );
}
/**
* Gets the CoordinateSequence corresponding to a compound element.
*
* @param idxFirst the first sub-element of the compound element
* @param idxLast the last sub-element of the compound element
* @param sdoGeom the SDOGeometry that holds the compound element.
*
* @return
*/
private CoordinateSequence getCompoundCSeq(int idxFirst, int idxLast, SDOGeometry sdoGeom) {
CoordinateSequence cs = null;
for ( int i = idxFirst; i <= idxLast; i++ ) {
// pop off the last element as it is added with the next
// coordinate sequence
if ( cs != null && cs.size() > 0 ) {
final Coordinate[] coordinates = cs.toCoordinateArray();
final Coordinate[] newCoordinates = new Coordinate[coordinates.length - 1];
System.arraycopy( coordinates, 0, newCoordinates, 0, coordinates.length - 1 );
cs = getGeometryFactory().getCoordinateSequenceFactory().create( newCoordinates );
}
cs = add( cs, getElementCSeq( i, sdoGeom, ( i < idxLast ) ) );
}
return cs;
}
/**
* Gets the CoordinateSequence corresponding to an element.
*
* @param i
* @param sdoGeom
*
* @return
*/
private CoordinateSequence getElementCSeq(int i, SDOGeometry sdoGeom, boolean hasNextSE) {
final ElementType type = sdoGeom.getInfo().getElementType( i );
final Double[] elemOrdinates = extractOrdinatesOfElement( i, sdoGeom, hasNextSE );
CoordinateSequence cs;
if ( type.isStraightSegment() ) {
cs = convertOrdinateArray( elemOrdinates, sdoGeom );
}
else if ( type.isArcSegment() || type.isCircle() ) {
final Coordinate[] linearized = linearize(
elemOrdinates,
sdoGeom.getDimension(),
sdoGeom.isLRSGeometry(),
type.isCircle()
);
cs = getGeometryFactory().getCoordinateSequenceFactory().create( linearized );
}
else if ( type.isRect() ) {
cs = convertOrdinateArray( elemOrdinates, sdoGeom );
final Coordinate ll = cs.getCoordinate( 0 );
final Coordinate ur = cs.getCoordinate( 1 );
final Coordinate lr = new Coordinate( ur.x, ll.y );
final Coordinate ul = new Coordinate( ll.x, ur.y );
if ( type.isExteriorRing() ) {
cs = getGeometryFactory().getCoordinateSequenceFactory()
.create( new Coordinate[] { ll, lr, ur, ul, ll } );
}
else {
cs = getGeometryFactory().getCoordinateSequenceFactory()
.create( new Coordinate[] { ll, ul, ur, lr, ll } );
}
}
else {
throw new RuntimeException(
"Unexpected Element type in compound: "
+ type
);
}
return cs;
}
private CoordinateSequence add(CoordinateSequence seq1, CoordinateSequence seq2) {
if ( seq1 == null ) {
return seq2;
}
if ( seq2 == null ) {
return seq1;
}
final Coordinate[] c1 = seq1.toCoordinateArray();
final Coordinate[] c2 = seq2.toCoordinateArray();
final Coordinate[] c3 = new Coordinate[c1.length + c2.length];
System.arraycopy( c1, 0, c3, 0, c1.length );
System.arraycopy( c2, 0, c3, c1.length, c2.length );
return getGeometryFactory().getCoordinateSequenceFactory().create( c3 );
}
private Double[] extractOrdinatesOfElement(int element, SDOGeometry sdoGeom, boolean hasNextSE) {
final int start = sdoGeom.getInfo().getOrdinatesOffset( element );
if ( element < sdoGeom.getInfo().getSize() - 1 ) {
int end = sdoGeom.getInfo().getOrdinatesOffset( element + 1 );
// if this is a subelement of a compound geometry,
// the last point is the first point of
// the next subelement.
if ( hasNextSE ) {
end += sdoGeom.getDimension();
}
return sdoGeom.getOrdinates().getOrdinatesArray( start, end );
}
else {
return sdoGeom.getOrdinates().getOrdinatesArray( start );
}
}
private CoordinateSequence convertOrdinateArray(Double[] oordinates, SDOGeometry sdoGeom) {
final int dim = sdoGeom.getDimension();
final Coordinate[] coordinates = new Coordinate[oordinates.length / dim];
final int zDim = sdoGeom.getZDimension() - 1;
// final int lrsDim = sdoGeom.getLRSDimension() - 1;
for ( int i = 0; i < coordinates.length; i++ ) {
if ( dim == 2 ) {
coordinates[i] = new Coordinate(
oordinates[i * dim],
oordinates[i * dim + 1]
);
}
else if ( dim == 3 ) {
if ( sdoGeom.isLRSGeometry() ) {
throw new UnsupportedOperationException();
// coordinates[i] = MCoordinate.create2dWithMeasure(
// oordinates[i * dim], // X
// oordinates[i * dim + 1], // Y
// oordinates[i * dim + lrsDim]
// ); // M
}
else {
coordinates[i] = new Coordinate(
//X
oordinates[i * dim],
//Y
oordinates[i * dim + 1],
oordinates[i * dim + zDim]
); // Z
}
}
// else if ( dim == 4 ) {
// // This must be an LRS Geometry
// if ( !SDOGeom.isLRSGeometry() ) {
// throw new HibernateException(
// "4 dimensional Geometries must be LRS geometry"
// );
// }
// coordinates[i] = MCoordinate.create3dWithMeasure(
// oordinates[i
// * dim], // X
// oordinates[i * dim + 1], // Y
// oordinates[i * dim + zDim], // Z
// oordinates[i * dim + lrsDim]
// ); // M
// }
}
return getGeometryFactory().getCoordinateSequenceFactory().create(
coordinates
);
}
/**
* Linearizes arcs and circles.
*
* @param arcOrdinates arc or circle coordinates
* @param dim coordinate dimension
* @param lrs whether this is an lrs geometry
* @param entireCirlce whether the whole arc should be linearized
*
* @return linearized interpolation of arcs or circle
*/
private Coordinate[] linearize(Double[] arcOrdinates, int dim, boolean lrs, boolean entireCirlce) {
Coordinate[] linearizedCoords = new Coordinate[0];
// CoordDim is the dimension that includes only non-measure (X,Y,Z)
// ordinates in its value
final int coordDim = lrs ? dim - 1 : dim;
// this only works with 2-Dimensional geometries, since we use
// JGeometry linearization;
if ( coordDim != 2 ) {
throw new IllegalArgumentException(
"Can only linearize 2D arc segments, but geometry is "
+ dim + "D."
);
}
int numOrd = dim;
while ( numOrd < arcOrdinates.length ) {
numOrd = numOrd - dim;
final double x1 = arcOrdinates[numOrd++];
final double y1 = arcOrdinates[numOrd++];
final double m1 = lrs ? arcOrdinates[numOrd++] : Double.NaN;
final double x2 = arcOrdinates[numOrd++];
final double y2 = arcOrdinates[numOrd++];
final double m2 = lrs ? arcOrdinates[numOrd++] : Double.NaN;
final double x3 = arcOrdinates[numOrd++];
final double y3 = arcOrdinates[numOrd++];
final double m3 = lrs ? arcOrdinates[numOrd++] : Double.NaN;
Coordinate[] coords;
if ( entireCirlce ) {
coords = Circle.linearizeCircle( x1, y1, x2, y2, x3, y3 );
}
else {
coords = Circle.linearizeArc( x1, y1, x2, y2, x3, y3 );
}
// if this is an LRS geometry, fill the measure values into
// the linearized array
if ( lrs ) {
throw new UnsupportedOperationException();
// MCoordinate[] mcoord = new MCoordinate[coords.length];
// int lastIndex = coords.length - 1;
// mcoord[0] = MCoordinate.create2dWithMeasure( x1, y1, m1 );
// mcoord[lastIndex] = MCoordinate.create2dWithMeasure( x3, y3, m3 );
// // convert the middle coordinates to MCoordinate
// for ( int i = 1; i < lastIndex; i++ ) {
// mcoord[i] = MCoordinate.convertCoordinate( coords[i] );
// // if we happen to split on the middle measure, then
// // assign it
// if ( Double.compare( mcoord[i].x, x2 ) == 0
// && Double.compare( mcoord[i].y, y2 ) == 0 ) {
// mcoord[i].m = m2;
// }
// }
// coords = mcoord;
}
// if this is not the first arcsegment, the first linearized
// point is already in linearizedArc, so disregard this.
int resultBegin = 1;
if ( linearizedCoords.length == 0 ) {
resultBegin = 0;
}
final int destPos = linearizedCoords.length;
final Coordinate[] tmpCoords = new Coordinate[linearizedCoords.length + coords.length - resultBegin];
System.arraycopy( linearizedCoords, 0, tmpCoords, 0, linearizedCoords.length );
System.arraycopy( coords, resultBegin, tmpCoords, destPos, coords.length - resultBegin );
linearizedCoords = tmpCoords;
}
return linearizedCoords;
}
private Geometry toGeomerty(SDOGeometry sdoGeom) {
return Decoders.decode(sdoGeom);
}
}

View File

@ -1,60 +0,0 @@
/*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for spatial (geographic) data.
*
* Copyright © 2007-2012 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
*/
package org.hibernate.spatial.dialect.oracle;
import java.sql.SQLException;
import java.sql.Struct;
/**
* @author Karel Maesen, Geovise BVBA
* creation-date: Jul 1, 2010
*/
class SDOPoint {
public double x;
public double y;
public double z = Double.NaN;
public SDOPoint(Struct struct) {
try {
final Object[] data = struct.getAttributes();
this.x = ( (Number) data[0] ).doubleValue();
this.y = ( (Number) data[1] ).doubleValue();
if ( data[2] != null ) {
this.z = ( (Number) data[1] ).doubleValue();
}
}
catch ( SQLException e ) {
throw new RuntimeException( e );
}
}
public String toString() {
final StringBuilder stb = new StringBuilder();
stb.append( "(" ).append( x ).append( "," ).append( y ).append( "," ).append(
z
).append( ")" );
return stb.toString();
}
}

View File

@ -1,51 +0,0 @@
/*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for spatial (geographic) data.
*
* Copyright © 2007-2012 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
*/
package org.hibernate.spatial.dialect.oracle;
import java.sql.Array;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Struct;
//TODO -- remove this interface..
/**
* @author Karel Maesen, Geovise BVBA
* creation-date: Jul 3, 2010
*/
interface SQLTypeFactory {
/**
* Creates a {@code Struct} representing the specified geometry, using the specified Connection.
*
* @param geom The {@code SDOGeometry} object
* @param conn The Oracle {@code Connection} used to create the {@code Struct}
* @return The {@code Struct} representation of the specified SDO Geometry
* @throws SQLException If a Struct object cannot be created.
*/
public abstract Struct createStruct(SDOGeometry geom, Connection conn) throws SQLException;
public abstract Array createElemInfoArray(ElemInfo elemInfo, Connection conn) throws SQLException;
public abstract Array createOrdinatesArray(Ordinates ordinates, Connection conn) throws SQLException;
}

View File

@ -1,56 +0,0 @@
/*
* This file is part of Hibernate Spatial, an extension to the
* hibernate ORM solution for spatial (geographic) data.
*
* Copyright © 2007-2012 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
*/
package org.hibernate.spatial.dialect.oracle;
/**
* @author Karel Maesen, Geovise BVBA
* creation-date: Jul 1, 2010
*/
enum TypeGeometry {
UNKNOWN_GEOMETRY( 0 ), POINT( 1 ), LINE( 2 ), POLYGON( 3 ), COLLECTION( 4 ), MULTIPOINT(
5
), MULTILINE( 6 ), MULTIPOLYGON( 7 ), SOLID( 8 ), MULTISOLID( 9 );
private int gtype;
TypeGeometry(int gtype) {
this.gtype = gtype;
}
int intValue() {
return this.gtype;
}
static TypeGeometry parse(int v) {
for ( TypeGeometry gt : values() ) {
if ( gt.intValue() == v ) {
return gt;
}
}
throw new RuntimeException(
"Value " + v
+ " isn't a valid TypeGeometry value"
);
}
}

View File

@ -266,6 +266,6 @@ public class SDOGeometryExpectationsFactory extends AbstractExpectationsFactory
@Override
protected Geometry decode(Object o) {
return decoder.toJTS( o );
return decoder.convert(o);
}
}