From 89eabb920dda69df83a60fa5d327017b4dbeb5a6 Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Wed, 23 Feb 2011 15:37:37 -0800 Subject: [PATCH 01/19] HHH-5957 : Provide a way for dialects to override a SqlTypeDescriptor --- .../java/org/hibernate/dialect/Dialect.java | 64 ++++++ .../hibernate/dialect/PostgreSQLDialect.java | 39 +++- ...AbstractSingleColumnStandardBasicType.java | 4 + .../type/AbstractStandardBasicType.java | 16 +- .../java/org/hibernate/type/BlobType.java | 2 +- .../type/CharacterArrayClobType.java | 2 +- .../java/org/hibernate/type/ClobType.java | 2 +- .../hibernate/type/MaterializedBlobType.java | 2 +- .../hibernate/type/MaterializedClobType.java | 2 +- .../type/PrimitiveCharacterArrayClobType.java | 2 +- .../hibernate/type/StandardBasicTypes.java | 91 ++++---- .../java/org/hibernate/type/TypeFactory.java | 4 + .../java/org/hibernate/type/TypeResolver.java | 57 ++++- .../type/WrappedMaterializedBlobType.java | 2 +- .../type/descriptor/WrapperOptions.java | 4 + .../descriptor/java/BlobTypeDescriptor.java | 12 +- .../descriptor/java/ClobTypeDescriptor.java | 15 +- .../descriptor/sql/BlobTypeDescriptor.java | 91 ++++++-- .../descriptor/sql/ClobTypeDescriptor.java | 68 ++++-- .../annotations/lob/MaterializedBlobTest.java | 2 +- .../test/typeoverride/Entity.hbm.xml | 39 ++++ .../hibernate/test/typeoverride/Entity.java | 55 +++++ ...ectOverridePrefixedVarcharSqlTypeDesc.java | 41 ++++ .../H2DialectOverrideVarcharSqlCode.java | 42 ++++ .../StoredPrefixedStringType.java | 105 +++++++++ .../test/typeoverride/TypeOverrideTest.java | 208 ++++++++++++++++++ .../sql/StringValueMappingTest.java | 8 +- 27 files changed, 883 insertions(+), 96 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/typeoverride/Entity.hbm.xml create mode 100644 hibernate-core/src/test/java/org/hibernate/test/typeoverride/Entity.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/typeoverride/H2DialectOverridePrefixedVarcharSqlTypeDesc.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/typeoverride/H2DialectOverrideVarcharSqlCode.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/typeoverride/StoredPrefixedStringType.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/typeoverride/TypeOverrideTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java index 2a6023a362..09499f3fc9 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java @@ -67,6 +67,9 @@ import org.hibernate.sql.CaseFragment; import org.hibernate.sql.ForUpdateFragment; import org.hibernate.sql.JoinFragment; import org.hibernate.type.StandardBasicTypes; +import org.hibernate.type.descriptor.sql.BlobTypeDescriptor; +import org.hibernate.type.descriptor.sql.ClobTypeDescriptor; +import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; import org.hibernate.util.ReflectHelper; import org.hibernate.util.StringHelper; @@ -293,6 +296,67 @@ public abstract class Dialect { typeNames.put( code, name ); } + /** + * Allows the dialect to override a {@link SqlTypeDescriptor}. + *

+ * If sqlTypeDescriptor is a "standard basic" SQL type + * descriptor, then this method uses {@link #getSqlTypeDescriptorOverride} + * to get an optional override based on the SQL code returned by + * {@link SqlTypeDescriptor#getSqlType()}. + *

+ * If this dialect does not provide an override, then this method + * simply returns sqlTypeDescriptor + * + * @param sqlTypeDescriptor The {@link SqlTypeDescriptor} to override + * @return The {@link SqlTypeDescriptor} that should be used for this dialect; + * if there is no override, then sqlTypeDescriptor is returned. + * @throws IllegalArgumentException if sqlTypeDescriptor is null. + * + * @see {@link SqlTypeDescriptor} + * @see {@link #getSqlTypeDescriptorOverride} + * @see {@link StandardBasicTypes#isStandardBasicSqlTypeDescriptor(org.hibernate.type.descriptor.sql.SqlTypeDescriptor)} + */ + public SqlTypeDescriptor resolveSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) { + if ( sqlTypeDescriptor == null ) { + throw new IllegalArgumentException( "sqlTypeDescriptor is null" ); + } + SqlTypeDescriptor overrideBySqlCode = null; + if ( StandardBasicTypes.isStandardBasicSqlTypeDescriptor( sqlTypeDescriptor ) ) { + overrideBySqlCode = getSqlTypeDescriptorOverride( sqlTypeDescriptor.getSqlType() ); + } + return overrideBySqlCode == null ? sqlTypeDescriptor : overrideBySqlCode; + } + + /** + * Returns the {@link SqlTypeDescriptor} that should override the + * "standard basic" SQL type descriptor for values of the specified + * column type, or null, if there is no override. + * + * @param sqlCode A {@link Types} constant indicating the SQL column type + * @return The {@link SqlTypeDescriptor} that should override the + * "standard basic" SQL type descriptor, or null, if there is no override. + * + * @see {@link SqlTypeDescriptor} + * @see {@link StandardBasicTypes#isStandardBasicSqlTypeDescriptor(org.hibernate.type.descriptor.sql.SqlTypeDescriptor)} + */ + protected SqlTypeDescriptor getSqlTypeDescriptorOverride(int sqlCode) { + SqlTypeDescriptor descriptor; + switch ( sqlCode ) { + case Types.BLOB: { + descriptor = useInputStreamToInsertBlob() ? BlobTypeDescriptor.STREAM_BINDING : null; + break; + } + case Types.CLOB: { + descriptor = useInputStreamToInsertBlob() ? ClobTypeDescriptor.STREAM_BINDING : null; + break; + } + default: { + descriptor = null; + break; + } + } + return descriptor; + } // hibernate type mapping support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java index 81a3a25e4e..31402deac3 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java @@ -40,6 +40,9 @@ import org.hibernate.exception.JDBCExceptionHelper; import org.hibernate.exception.TemplatedViolatedConstraintNameExtracter; import org.hibernate.exception.ViolatedConstraintNameExtracter; import org.hibernate.id.SequenceGenerator; +import org.hibernate.type.descriptor.sql.BlobTypeDescriptor; +import org.hibernate.type.descriptor.sql.ClobTypeDescriptor; +import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; /** * An SQL dialect for Postgres @@ -144,6 +147,30 @@ public class PostgreSQLDialect extends Dialect { registerFunction( "str", new SQLFunctionTemplate(Hibernate.STRING, "cast(?1 as varchar)") ); getDefaultProperties().setProperty(Environment.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE); + getDefaultProperties().setProperty( Environment.NON_CONTEXTUAL_LOB_CREATION, "true" ); + } + + /** + * {@inheritDoc} + */ + @Override + public SqlTypeDescriptor getSqlTypeDescriptorOverride(int sqlCode) { + SqlTypeDescriptor descriptor; + switch ( sqlCode ) { + case Types.BLOB: { + descriptor = BlobTypeDescriptor.BLOB_BINDING; + break; + } + case Types.CLOB: { + descriptor = ClobTypeDescriptor.CLOB_BINDING; + break; + } + default: { + descriptor = super.getSqlTypeDescriptorOverride( sqlCode ); + break; + } + } + return descriptor; } public String getAddColumnString() { @@ -364,8 +391,18 @@ public class PostgreSQLDialect extends Dialect { return false; } + @Override public boolean supportsExpectedLobUsagePattern() { - // seems to have spotty LOB suppport + return true; + } + + @Override + public boolean supportsLobValueChangePropogation() { + return false; + } + + @Override + public boolean supportsUnboundedLobLocatorMaterialization() { return false; } diff --git a/hibernate-core/src/main/java/org/hibernate/type/AbstractSingleColumnStandardBasicType.java b/hibernate-core/src/main/java/org/hibernate/type/AbstractSingleColumnStandardBasicType.java index b23d343d94..51c6b95122 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/AbstractSingleColumnStandardBasicType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/AbstractSingleColumnStandardBasicType.java @@ -56,6 +56,10 @@ public abstract class AbstractSingleColumnStandardBasicType public LobCreator getLobCreator() { return NonContextualLobCreator.INSTANCE; } + + public SqlTypeDescriptor resolveSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) { + return sqlTypeDescriptor; + } }; public final int sqlType() { diff --git a/hibernate-core/src/main/java/org/hibernate/type/AbstractStandardBasicType.java b/hibernate-core/src/main/java/org/hibernate/type/AbstractStandardBasicType.java index f87a891732..cd10dccbc3 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/AbstractStandardBasicType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/AbstractStandardBasicType.java @@ -244,13 +244,17 @@ public abstract class AbstractStandardBasicType public LobCreator getLobCreator() { return Hibernate.getLobCreator( session ); } + + public SqlTypeDescriptor resolveSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) { + return session.getFactory().getTypeResolver().resolveSqlTypeDescriptor( sqlTypeDescriptor ); + } }; return nullSafeGet( rs, name, options ); } protected final T nullSafeGet(ResultSet rs, String name, WrapperOptions options) throws SQLException { - return sqlTypeDescriptor.getExtractor( javaTypeDescriptor ).extract( rs, name, options ); + return resolveSqlTypeDescriptor( options ).getExtractor( javaTypeDescriptor ).extract( rs, name, options ); } public Object get(ResultSet rs, String name, SessionImplementor session) throws HibernateException, SQLException { @@ -272,6 +276,10 @@ public abstract class AbstractStandardBasicType public LobCreator getLobCreator() { return Hibernate.getLobCreator( session ); } + + public SqlTypeDescriptor resolveSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) { + return session.getFactory().getTypeResolver().resolveSqlTypeDescriptor( sqlTypeDescriptor ); + } }; nullSafeSet( st, value, index, options ); @@ -279,7 +287,11 @@ public abstract class AbstractStandardBasicType @SuppressWarnings({ "unchecked" }) protected final void nullSafeSet(PreparedStatement st, Object value, int index, WrapperOptions options) throws SQLException { - sqlTypeDescriptor.getBinder( javaTypeDescriptor ).bind( st, (T) value, index, options ); + resolveSqlTypeDescriptor( options ).getBinder( javaTypeDescriptor ).bind( st, ( T ) value, index, options ); + } + + private SqlTypeDescriptor resolveSqlTypeDescriptor(WrapperOptions options) { + return options.resolveSqlTypeDescriptor( sqlTypeDescriptor ); } public void set(PreparedStatement st, T value, int index, SessionImplementor session) throws HibernateException, SQLException { diff --git a/hibernate-core/src/main/java/org/hibernate/type/BlobType.java b/hibernate-core/src/main/java/org/hibernate/type/BlobType.java index 86f9ad6012..30f37d425e 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/BlobType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/BlobType.java @@ -37,7 +37,7 @@ public class BlobType extends AbstractSingleColumnStandardBasicType { public static final BlobType INSTANCE = new BlobType(); public BlobType() { - super( org.hibernate.type.descriptor.sql.BlobTypeDescriptor.INSTANCE, BlobTypeDescriptor.INSTANCE ); + super( org.hibernate.type.descriptor.sql.BlobTypeDescriptor.DEFAULT, BlobTypeDescriptor.INSTANCE ); } /** diff --git a/hibernate-core/src/main/java/org/hibernate/type/CharacterArrayClobType.java b/hibernate-core/src/main/java/org/hibernate/type/CharacterArrayClobType.java index 649135dd3e..c772bc4b35 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/CharacterArrayClobType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/CharacterArrayClobType.java @@ -38,7 +38,7 @@ public class CharacterArrayClobType extends AbstractSingleColumnStandardBasicTyp public static final CharacterArrayClobType INSTANCE = new CharacterArrayClobType(); public CharacterArrayClobType() { - super( ClobTypeDescriptor.INSTANCE, CharacterArrayTypeDescriptor.INSTANCE ); + super( ClobTypeDescriptor.DEFAULT, CharacterArrayTypeDescriptor.INSTANCE ); } public String getName() { diff --git a/hibernate-core/src/main/java/org/hibernate/type/ClobType.java b/hibernate-core/src/main/java/org/hibernate/type/ClobType.java index d3bbdb0d2e..4bd706a8c0 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/ClobType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/ClobType.java @@ -37,7 +37,7 @@ public class ClobType extends AbstractSingleColumnStandardBasicType { public static final ClobType INSTANCE = new ClobType(); public ClobType() { - super( org.hibernate.type.descriptor.sql.ClobTypeDescriptor.INSTANCE, ClobTypeDescriptor.INSTANCE ); + super( org.hibernate.type.descriptor.sql.ClobTypeDescriptor.DEFAULT, ClobTypeDescriptor.INSTANCE ); } public String getName() { diff --git a/hibernate-core/src/main/java/org/hibernate/type/MaterializedBlobType.java b/hibernate-core/src/main/java/org/hibernate/type/MaterializedBlobType.java index 980dab9737..ff13815f69 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/MaterializedBlobType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/MaterializedBlobType.java @@ -38,7 +38,7 @@ public class MaterializedBlobType extends AbstractSingleColumnStandardBasicType< public static final MaterializedBlobType INSTANCE = new MaterializedBlobType(); public MaterializedBlobType() { - super( BlobTypeDescriptor.INSTANCE, PrimitiveByteArrayTypeDescriptor.INSTANCE ); + super( BlobTypeDescriptor.DEFAULT, PrimitiveByteArrayTypeDescriptor.INSTANCE ); } public String getName() { diff --git a/hibernate-core/src/main/java/org/hibernate/type/MaterializedClobType.java b/hibernate-core/src/main/java/org/hibernate/type/MaterializedClobType.java index 9dbce2e371..7621e49ad9 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/MaterializedClobType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/MaterializedClobType.java @@ -37,7 +37,7 @@ public class MaterializedClobType extends AbstractSingleColumnStandardBasicType< public static final MaterializedClobType INSTANCE = new MaterializedClobType(); public MaterializedClobType() { - super( ClobTypeDescriptor.INSTANCE, StringTypeDescriptor.INSTANCE ); + super( ClobTypeDescriptor.DEFAULT, StringTypeDescriptor.INSTANCE ); } public String getName() { diff --git a/hibernate-core/src/main/java/org/hibernate/type/PrimitiveCharacterArrayClobType.java b/hibernate-core/src/main/java/org/hibernate/type/PrimitiveCharacterArrayClobType.java index d21bb1e498..3c09a7c8f2 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/PrimitiveCharacterArrayClobType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/PrimitiveCharacterArrayClobType.java @@ -35,7 +35,7 @@ public class PrimitiveCharacterArrayClobType extends AbstractSingleColumnStandar public static final CharacterArrayClobType INSTANCE = new CharacterArrayClobType(); public PrimitiveCharacterArrayClobType() { - super( ClobTypeDescriptor.INSTANCE, PrimitiveCharacterArrayTypeDescriptor.INSTANCE ); + super( ClobTypeDescriptor.DEFAULT, PrimitiveCharacterArrayTypeDescriptor.INSTANCE ); } public String getName() { diff --git a/hibernate-core/src/main/java/org/hibernate/type/StandardBasicTypes.java b/hibernate-core/src/main/java/org/hibernate/type/StandardBasicTypes.java index 5933ac517b..df54e0a18e 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/StandardBasicTypes.java +++ b/hibernate-core/src/main/java/org/hibernate/type/StandardBasicTypes.java @@ -23,6 +23,11 @@ */ package org.hibernate.type; +import java.util.HashSet; +import java.util.Set; + +import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; + /** * Centralizes access to the standard set of basic {@link Type types}. *

@@ -37,108 +42,111 @@ package org.hibernate.type; * @author Steve Ebersole */ public class StandardBasicTypes { + + private static final Set sqlTypeDescriptors = new HashSet(); + /** * The standard Hibernate type for mapping {@link Boolean} to JDBC {@link java.sql.Types#BIT BIT}. * * @see BooleanType */ - public static final BooleanType BOOLEAN = BooleanType.INSTANCE; + public static final BooleanType BOOLEAN = register( BooleanType.INSTANCE ); /** * The standard Hibernate type for mapping {@link Boolean} to JDBC {@link java.sql.Types#INTEGER INTEGER}. * * @see NumericBooleanType */ - public static final NumericBooleanType NUMERIC_BOOLEAN = NumericBooleanType.INSTANCE; + public static final NumericBooleanType NUMERIC_BOOLEAN = register( NumericBooleanType.INSTANCE ); /** * The standard Hibernate type for mapping {@link Boolean} to JDBC {@link java.sql.Types#CHAR CHAR(1)} (using 'T'/'F'). * * @see TrueFalseType */ - public static final TrueFalseType TRUE_FALSE = TrueFalseType.INSTANCE; + public static final TrueFalseType TRUE_FALSE = register( TrueFalseType.INSTANCE ); /** * The standard Hibernate type for mapping {@link Boolean} to JDBC {@link java.sql.Types#CHAR CHAR(1)} (using 'Y'/'N'). * * @see YesNoType */ - public static final YesNoType YES_NO = YesNoType.INSTANCE; + public static final YesNoType YES_NO = register( YesNoType.INSTANCE ); /** * The standard Hibernate type for mapping {@link Byte} to JDBC {@link java.sql.Types#TINYINT TINYINT}. */ - public static final ByteType BYTE = ByteType.INSTANCE; + public static final ByteType BYTE = register( ByteType.INSTANCE ); /** * The standard Hibernate type for mapping {@link Short} to JDBC {@link java.sql.Types#SMALLINT SMALLINT}. * * @see ShortType */ - public static final ShortType SHORT = ShortType.INSTANCE; + public static final ShortType SHORT = register( ShortType.INSTANCE ); /** * The standard Hibernate type for mapping {@link Integer} to JDBC {@link java.sql.Types#INTEGER INTEGER}. * * @see IntegerType */ - public static final IntegerType INTEGER = IntegerType.INSTANCE; + public static final IntegerType INTEGER = register( IntegerType.INSTANCE ); /** * The standard Hibernate type for mapping {@link Long} to JDBC {@link java.sql.Types#BIGINT BIGINT}. * * @see LongType */ - public static final LongType LONG = LongType.INSTANCE; + public static final LongType LONG = register( LongType.INSTANCE ); /** * The standard Hibernate type for mapping {@link Float} to JDBC {@link java.sql.Types#FLOAT FLOAT}. * * @see FloatType */ - public static final FloatType FLOAT = FloatType.INSTANCE; + public static final FloatType FLOAT = register( FloatType.INSTANCE ); /** * The standard Hibernate type for mapping {@link Double} to JDBC {@link java.sql.Types#DOUBLE DOUBLE}. * * @see DoubleType */ - public static final DoubleType DOUBLE = DoubleType.INSTANCE; + public static final DoubleType DOUBLE = register( DoubleType.INSTANCE ); /** * The standard Hibernate type for mapping {@link java.math.BigInteger} to JDBC {@link java.sql.Types#NUMERIC NUMERIC}. * * @see BigIntegerType */ - public static final BigIntegerType BIG_INTEGER = BigIntegerType.INSTANCE; + public static final BigIntegerType BIG_INTEGER = register( BigIntegerType.INSTANCE ); /** * The standard Hibernate type for mapping {@link java.math.BigDecimal} to JDBC {@link java.sql.Types#NUMERIC NUMERIC}. * * @see BigDecimalType */ - public static final BigDecimalType BIG_DECIMAL = BigDecimalType.INSTANCE; + public static final BigDecimalType BIG_DECIMAL = register( BigDecimalType.INSTANCE ); /** * The standard Hibernate type for mapping {@link Character} to JDBC {@link java.sql.Types#CHAR CHAR(1)}. * * @see CharacterType */ - public static final CharacterType CHARACTER = CharacterType.INSTANCE; + public static final CharacterType CHARACTER = register( CharacterType.INSTANCE ); /** * The standard Hibernate type for mapping {@link String} to JDBC {@link java.sql.Types#VARCHAR VARCHAR}. * * @see StringType */ - public static final StringType STRING = StringType.INSTANCE; + public static final StringType STRING = register( StringType.INSTANCE ); /** * The standard Hibernate type for mapping {@link java.net.URL} to JDBC {@link java.sql.Types#VARCHAR VARCHAR}. * * @see UrlType */ - public static final UrlType URL = UrlType.INSTANCE; + public static final UrlType URL = register( UrlType.INSTANCE ); /** * The standard Hibernate type for mapping {@link java.util.Date} ({@link java.sql.Time}) to JDBC @@ -146,7 +154,7 @@ public class StandardBasicTypes { * * @see TimeType */ - public static final TimeType TIME = TimeType.INSTANCE; + public static final TimeType TIME = register( TimeType.INSTANCE ); /** * The standard Hibernate type for mapping {@link java.util.Date} ({@link java.sql.Date}) to JDBC @@ -154,7 +162,7 @@ public class StandardBasicTypes { * * @see TimeType */ - public static final DateType DATE = DateType.INSTANCE; + public static final DateType DATE = register( DateType.INSTANCE ); /** * The standard Hibernate type for mapping {@link java.util.Date} ({@link java.sql.Timestamp}) to JDBC @@ -162,7 +170,7 @@ public class StandardBasicTypes { * * @see TimeType */ - public static final TimestampType TIMESTAMP = TimestampType.INSTANCE; + public static final TimestampType TIMESTAMP = register( TimestampType.INSTANCE ); /** * The standard Hibernate type for mapping {@link java.util.Calendar} to JDBC @@ -170,7 +178,7 @@ public class StandardBasicTypes { * * @see CalendarType */ - public static final CalendarType CALENDAR = CalendarType.INSTANCE; + public static final CalendarType CALENDAR = register( CalendarType.INSTANCE ); /** * The standard Hibernate type for mapping {@link java.util.Calendar} to JDBC @@ -178,63 +186,63 @@ public class StandardBasicTypes { * * @see CalendarDateType */ - public static final CalendarDateType CALENDAR_DATE = CalendarDateType.INSTANCE; + public static final CalendarDateType CALENDAR_DATE = register( CalendarDateType.INSTANCE ); /** * The standard Hibernate type for mapping {@link Class} to JDBC {@link java.sql.Types#VARCHAR VARCHAR}. * * @see ClassType */ - public static final ClassType CLASS = ClassType.INSTANCE; + public static final ClassType CLASS = register( ClassType.INSTANCE ); /** * The standard Hibernate type for mapping {@link java.util.Locale} to JDBC {@link java.sql.Types#VARCHAR VARCHAR}. * * @see LocaleType */ - public static final LocaleType LOCALE = LocaleType.INSTANCE; + public static final LocaleType LOCALE = register( LocaleType.INSTANCE ); /** * The standard Hibernate type for mapping {@link java.util.Currency} to JDBC {@link java.sql.Types#VARCHAR VARCHAR}. * * @see CurrencyType */ - public static final CurrencyType CURRENCY = CurrencyType.INSTANCE; + public static final CurrencyType CURRENCY = register( CurrencyType.INSTANCE ); /** * The standard Hibernate type for mapping {@link java.util.TimeZone} to JDBC {@link java.sql.Types#VARCHAR VARCHAR}. * * @see TimeZoneType */ - public static final TimeZoneType TIMEZONE = TimeZoneType.INSTANCE; + public static final TimeZoneType TIMEZONE = register( TimeZoneType.INSTANCE ); /** * The standard Hibernate type for mapping {@link java.util.UUID} to JDBC {@link java.sql.Types#BINARY BINARY}. * * @see UUIDBinaryType */ - public static final UUIDBinaryType UUID_BINARY = UUIDBinaryType.INSTANCE; + public static final UUIDBinaryType UUID_BINARY = register( UUIDBinaryType.INSTANCE ); /** * The standard Hibernate type for mapping {@link java.util.UUID} to JDBC {@link java.sql.Types#CHAR CHAR}. * * @see UUIDCharType */ - public static final UUIDCharType UUID_CHAR = UUIDCharType.INSTANCE; + public static final UUIDCharType UUID_CHAR = register( UUIDCharType.INSTANCE ); /** * The standard Hibernate type for mapping {@code byte[]} to JDBC {@link java.sql.Types#VARBINARY VARBINARY}. * * @see BinaryType */ - public static final BinaryType BINARY = BinaryType.INSTANCE; + public static final BinaryType BINARY = register( BinaryType.INSTANCE ); /** * The standard Hibernate type for mapping {@link Byte Byte[]} to JDBC {@link java.sql.Types#VARBINARY VARBINARY}. * * @see WrapperBinaryType */ - public static final WrapperBinaryType WRAPPER_BINARY = WrapperBinaryType.INSTANCE; + public static final WrapperBinaryType WRAPPER_BINARY = register( WrapperBinaryType.INSTANCE ); /** * The standard Hibernate type for mapping {@code byte[]} to JDBC {@link java.sql.Types#LONGVARBINARY LONGVARBINARY}. @@ -242,7 +250,7 @@ public class StandardBasicTypes { * @see ImageType * @see #MATERIALIZED_BLOB */ - public static final ImageType IMAGE = ImageType.INSTANCE; + public static final ImageType IMAGE = register( ImageType.INSTANCE ); /** * The standard Hibernate type for mapping {@link java.sql.Blob} to JDBC {@link java.sql.Types#BLOB BLOB}. @@ -250,7 +258,7 @@ public class StandardBasicTypes { * @see BlobType * @see #MATERIALIZED_BLOB */ - public static final BlobType BLOB = BlobType.INSTANCE; + public static final BlobType BLOB = register( BlobType.INSTANCE ); /** * The standard Hibernate type for mapping {@code byte[]} to JDBC {@link java.sql.Types#BLOB BLOB}. @@ -259,14 +267,14 @@ public class StandardBasicTypes { * @see #MATERIALIZED_BLOB * @see #IMAGE */ - public static final MaterializedBlobType MATERIALIZED_BLOB = MaterializedBlobType.INSTANCE; + public static final MaterializedBlobType MATERIALIZED_BLOB = register( MaterializedBlobType.INSTANCE ); /** * The standard Hibernate type for mapping {@code char[]} to JDBC {@link java.sql.Types#VARCHAR VARCHAR}. * * @see CharArrayType */ - public static final CharArrayType CHAR_ARRAY = CharArrayType.INSTANCE; + public static final CharArrayType CHAR_ARRAY = register( CharArrayType.INSTANCE ); /** * The standard Hibernate type for mapping {@link Character Character[]} to JDBC @@ -274,7 +282,7 @@ public class StandardBasicTypes { * * @see CharacterArrayType */ - public static final CharacterArrayType CHARACTER_ARRAY = CharacterArrayType.INSTANCE; + public static final CharacterArrayType CHARACTER_ARRAY = register( CharacterArrayType.INSTANCE ); /** * The standard Hibernate type for mapping {@link String} to JDBC {@link java.sql.Types#LONGVARCHAR LONGVARCHAR}. @@ -283,7 +291,7 @@ public class StandardBasicTypes { * * @see TextType */ - public static final TextType TEXT = TextType.INSTANCE; + public static final TextType TEXT = register( TextType.INSTANCE ); /** * The standard Hibernate type for mapping {@link java.sql.Clob} to JDBC {@link java.sql.Types#CLOB CLOB}. @@ -291,7 +299,7 @@ public class StandardBasicTypes { * @see ClobType * @see #MATERIALIZED_CLOB */ - public static final ClobType CLOB = ClobType.INSTANCE; + public static final ClobType CLOB = register( ClobType.INSTANCE ); /** * The standard Hibernate type for mapping {@link String} to JDBC {@link java.sql.Types#CLOB CLOB}. @@ -300,7 +308,7 @@ public class StandardBasicTypes { * @see #MATERIALIZED_CLOB * @see #TEXT */ - public static final MaterializedClobType MATERIALIZED_CLOB = MaterializedClobType.INSTANCE; + public static final MaterializedClobType MATERIALIZED_CLOB = register( MaterializedClobType.INSTANCE ); /** * The standard Hibernate type for mapping {@link java.io.Serializable} to JDBC {@link java.sql.Types#VARBINARY VARBINARY}. @@ -309,5 +317,14 @@ public class StandardBasicTypes { * * @see SerializableType */ - public static final SerializableType SERIALIZABLE = SerializableType.INSTANCE; + public static final SerializableType SERIALIZABLE = register( SerializableType.INSTANCE ); + + private static T register(T type) { + sqlTypeDescriptors.add( type.getSqlTypeDescriptor() ); + return type; + } + + public static final boolean isStandardBasicSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) { + return sqlTypeDescriptors.contains( sqlTypeDescriptor ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/type/TypeFactory.java b/hibernate-core/src/main/java/org/hibernate/type/TypeFactory.java index 5a08ec00f2..bb4db8e200 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/TypeFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/type/TypeFactory.java @@ -86,6 +86,10 @@ public final class TypeFactory implements Serializable { typeScope.injectSessionFactory( factory ); } + public SessionFactoryImplementor resolveSessionFactory() { + return typeScope.resolveFactory(); + } + public Type byClass(Class clazz, Properties parameters) { if ( Type.class.isAssignableFrom( clazz ) ) { return type( (Class) clazz, parameters ); diff --git a/hibernate-core/src/main/java/org/hibernate/type/TypeResolver.java b/hibernate-core/src/main/java/org/hibernate/type/TypeResolver.java index 83231165a9..3006a643e1 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/TypeResolver.java +++ b/hibernate-core/src/main/java/org/hibernate/type/TypeResolver.java @@ -24,11 +24,17 @@ package org.hibernate.type; import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; import java.util.Properties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import org.hibernate.MappingException; import org.hibernate.classic.Lifecycle; import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; import org.hibernate.usertype.CompositeUserType; import org.hibernate.usertype.UserType; import org.hibernate.util.ReflectHelper; @@ -39,21 +45,31 @@ import org.hibernate.util.ReflectHelper; * @author Steve Ebersole */ public class TypeResolver implements Serializable { + private static final Logger log = LoggerFactory.getLogger( TypeResolver.class ); + private final BasicTypeRegistry basicTypeRegistry; private final TypeFactory typeFactory; + private final Map resolvedSqlTypeDescriptors; public TypeResolver() { - this( new BasicTypeRegistry(), new TypeFactory() ); + this( new BasicTypeRegistry(), new TypeFactory(), null ); } - public TypeResolver(BasicTypeRegistry basicTypeRegistry, TypeFactory typeFactory) { + public TypeResolver(BasicTypeRegistry basicTypeRegistry, + TypeFactory typeFactory, + Map resolvedSqlTypeDescriptors) { this.basicTypeRegistry = basicTypeRegistry; this.typeFactory = typeFactory; + this.resolvedSqlTypeDescriptors = resolvedSqlTypeDescriptors; } public TypeResolver scope(SessionFactoryImplementor factory) { typeFactory.injectSessionFactory( factory ); - return new TypeResolver( basicTypeRegistry.shallowCopy(), typeFactory ); + return new TypeResolver( + basicTypeRegistry.shallowCopy(), + typeFactory, + new HashMap( 25 ) + ); } public void registerTypeOverride(BasicType type) { @@ -135,4 +151,39 @@ public class TypeResolver implements Serializable { return null; } + + public SqlTypeDescriptor resolveSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) { + if ( resolvedSqlTypeDescriptors == null ) { + throw new IllegalStateException( "cannot resolve a SqlTypeDescriptor until the TypeResolver is scoped." ); + } + SqlTypeDescriptor resolvedDescriptor = resolvedSqlTypeDescriptors.get( sqlTypeDescriptor ); + if ( resolvedDescriptor == null ) { + resolvedDescriptor = + typeFactory.resolveSessionFactory().getDialect().resolveSqlTypeDescriptor( sqlTypeDescriptor ); + if ( resolvedDescriptor == null ) { + throw new IllegalStateException( "dialect returned a resolved SqlTypeDescriptor that was null." ); + } + if ( sqlTypeDescriptor != resolvedDescriptor ) { + log.info( + "Adding override for {}: {}", + new String[] { + sqlTypeDescriptor.getClass().getName(), + resolvedDescriptor.getClass().getName(), + } + ); + if ( sqlTypeDescriptor.getSqlType() != resolvedDescriptor.getSqlType() ) { + log.warn( "Resolved SqlTypeDescriptor is for a different SQL code. {} has sqlCode={}; type override {} has sqlCode={}", + new String[] { + sqlTypeDescriptor.getClass().getName(), + String.valueOf( sqlTypeDescriptor.getSqlType() ), + resolvedDescriptor.getClass().getName(), + String.valueOf( resolvedDescriptor.getSqlType() ), + } + ); + } + } + resolvedSqlTypeDescriptors.put( sqlTypeDescriptor, resolvedDescriptor ); + } + return resolvedDescriptor; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/type/WrappedMaterializedBlobType.java b/hibernate-core/src/main/java/org/hibernate/type/WrappedMaterializedBlobType.java index 96f340f4d1..975ffd5a43 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/WrappedMaterializedBlobType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/WrappedMaterializedBlobType.java @@ -36,7 +36,7 @@ public class WrappedMaterializedBlobType extends AbstractSingleColumnStandardBas public static final WrappedMaterializedBlobType INSTANCE = new WrappedMaterializedBlobType(); public WrappedMaterializedBlobType() { - super( BlobTypeDescriptor.INSTANCE, ByteArrayTypeDescriptor.INSTANCE ); + super( BlobTypeDescriptor.DEFAULT, ByteArrayTypeDescriptor.INSTANCE ); } public String getName() { diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/WrapperOptions.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/WrapperOptions.java index 339e8eb8c8..6cc8949804 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/WrapperOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/WrapperOptions.java @@ -23,7 +23,10 @@ */ package org.hibernate.type.descriptor; +import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.LobCreator; +import org.hibernate.type.TypeResolver; +import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; /** * TODO : javadoc @@ -33,4 +36,5 @@ import org.hibernate.engine.jdbc.LobCreator; public interface WrapperOptions { public boolean useStreamForLobBinding(); public LobCreator getLobCreator(); + public SqlTypeDescriptor resolveSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor); } diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/BlobTypeDescriptor.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/BlobTypeDescriptor.java index f834c11934..d7b104657f 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/BlobTypeDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/BlobTypeDescriptor.java @@ -31,6 +31,7 @@ import java.util.Comparator; import org.hibernate.HibernateException; import org.hibernate.engine.jdbc.BlobProxy; import org.hibernate.engine.jdbc.WrappedBlob; +import org.hibernate.type.descriptor.BinaryStream; import org.hibernate.type.descriptor.WrapperOptions; /** @@ -107,7 +108,7 @@ public class BlobTypeDescriptor extends AbstractTypeDescriptor { @SuppressWarnings({ "unchecked" }) public X unwrap(Blob value, Class type, WrapperOptions options) { - if ( !Blob.class.isAssignableFrom( type ) ) { + if ( ! ( Blob.class.isAssignableFrom( type ) || BinaryStream.class.isAssignableFrom( type ) ) ) { throw unknownUnwrap( type ); } @@ -115,6 +116,15 @@ public class BlobTypeDescriptor extends AbstractTypeDescriptor { return null; } + if ( BinaryStream.class.isAssignableFrom( type ) ) { + try { + return (X) new BinaryStreamImpl( DataHelper.extractBytes( value.getBinaryStream() ) ); + } + catch ( SQLException e ) { + throw new HibernateException( "Unable to access blob stream", e ); + } + } + final Blob blob = WrappedBlob.class.isInstance( value ) ? ( (WrappedBlob) value ).getWrappedBlob() : value; diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/ClobTypeDescriptor.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/ClobTypeDescriptor.java index ec10483c49..bbe51382d0 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/ClobTypeDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/ClobTypeDescriptor.java @@ -23,6 +23,7 @@ */ package org.hibernate.type.descriptor.java; +import java.io.Reader; import java.io.Serializable; import java.sql.Clob; import java.sql.SQLException; @@ -31,6 +32,7 @@ import java.util.Comparator; import org.hibernate.HibernateException; import org.hibernate.engine.jdbc.ClobProxy; import org.hibernate.engine.jdbc.WrappedClob; +import org.hibernate.type.descriptor.CharacterStream; import org.hibernate.type.descriptor.WrapperOptions; /** @@ -98,8 +100,8 @@ public class ClobTypeDescriptor extends AbstractTypeDescriptor { } @SuppressWarnings({ "unchecked" }) - public X unwrap(Clob value, Class type, WrapperOptions options) { - if ( !Clob.class.isAssignableFrom( type ) ) { + public X unwrap(final Clob value, Class type, WrapperOptions options) { + if ( ! ( Clob.class.isAssignableFrom( type ) || CharacterStream.class.isAssignableFrom( type ) ) ) { throw unknownUnwrap( type ); } @@ -107,6 +109,15 @@ public class ClobTypeDescriptor extends AbstractTypeDescriptor { return null; } + if ( CharacterStream.class.isAssignableFrom( type ) ) { + try { + return (X) new CharacterStreamImpl( DataHelper.extractString( value.getCharacterStream() ) ); + } + catch ( SQLException e ) { + throw new HibernateException( "Unable to access lob stream", e ); + } + } + final Clob clob = WrappedClob.class.isInstance( value ) ? ( (WrappedClob) value ).getWrappedClob() : value; diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/BlobTypeDescriptor.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/BlobTypeDescriptor.java index c746316bfd..eec639d4a8 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/BlobTypeDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/BlobTypeDescriptor.java @@ -23,7 +23,6 @@ */ package org.hibernate.type.descriptor.sql; -import java.io.InputStream; import java.sql.Blob; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -41,32 +40,72 @@ import org.hibernate.type.descriptor.WrapperOptions; * * @author Steve Ebersole */ -public class BlobTypeDescriptor implements SqlTypeDescriptor { - public static final BlobTypeDescriptor INSTANCE = new BlobTypeDescriptor(); +public abstract class BlobTypeDescriptor implements SqlTypeDescriptor { - public int getSqlType() { - return Types.BLOB; - } + private BlobTypeDescriptor() {} - public ValueBinder getBinder(final JavaTypeDescriptor javaTypeDescriptor) { - return new BasicBinder( javaTypeDescriptor, this ) { - @Override - protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) throws SQLException { - if ( options.useStreamForLobBinding() ) { - final BinaryStream binaryStream = javaTypeDescriptor.unwrap( value, BinaryStream.class, options ); - st.setBinaryStream( index, binaryStream.getInputStream(), binaryStream.getLength() ); + public static final BlobTypeDescriptor DEFAULT = + new BlobTypeDescriptor() { + public BasicBinder getBlobBinder(final JavaTypeDescriptor javaTypeDescriptor) { + return new BasicBinder( javaTypeDescriptor, this ) { + @Override + protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) throws SQLException { + if ( options.useStreamForLobBinding() ) { + STREAM_BINDING.getBlobBinder( javaTypeDescriptor ).doBind( st, value, index, options ); + } + else if ( byte[].class.isInstance( value ) ) { + // performance shortcut for binding BLOB data in byte[] format + PRIMITIVE_ARRAY_BINDING.getBlobBinder( javaTypeDescriptor ).doBind( st, value, index, options ); + } + else { + BLOB_BINDING.getBlobBinder( javaTypeDescriptor ).doBind( st, value, index, options ); + } + } + }; } - else if ( byte[].class.isInstance( value ) ) { - // performance shortcut for binding BLOB data in byte[] format - final byte[] bytes = (byte[]) value; - st.setBytes( index, bytes ); + }; + + public static final BlobTypeDescriptor PRIMITIVE_ARRAY_BINDING = + new BlobTypeDescriptor() { + public BasicBinder getBlobBinder(final JavaTypeDescriptor javaTypeDescriptor) { + return new BasicBinder( javaTypeDescriptor, this ) { + @Override + public void doBind(PreparedStatement st, X value, int index, WrapperOptions options) + throws SQLException { + st.setBytes( index, javaTypeDescriptor.unwrap( value, byte[].class, options ) ); + } + }; } - else { - st.setBlob( index, javaTypeDescriptor.unwrap( value, Blob.class, options ) ); + }; + + public static final BlobTypeDescriptor BLOB_BINDING = + new BlobTypeDescriptor() { + public BasicBinder getBlobBinder(final JavaTypeDescriptor javaTypeDescriptor) { + return new BasicBinder( javaTypeDescriptor, this ) { + @Override + protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) + throws SQLException { + st.setBlob( index, javaTypeDescriptor.unwrap( value, Blob.class, options ) ); + } + }; } - } - }; - } + }; + + public static final BlobTypeDescriptor STREAM_BINDING = + new BlobTypeDescriptor() { + public BasicBinder getBlobBinder(final JavaTypeDescriptor javaTypeDescriptor) { + return new BasicBinder( javaTypeDescriptor, this ) { + @Override + protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) + throws SQLException { + final BinaryStream binaryStream = javaTypeDescriptor.unwrap( value, BinaryStream.class, options ); + st.setBinaryStream( index, binaryStream.getInputStream(), binaryStream.getLength() ); + } + }; + } + }; + + protected abstract BasicBinder getBlobBinder(final JavaTypeDescriptor javaTypeDescriptor); public ValueExtractor getExtractor(final JavaTypeDescriptor javaTypeDescriptor) { return new BasicExtractor( javaTypeDescriptor, this ) { @@ -76,4 +115,12 @@ public class BlobTypeDescriptor implements SqlTypeDescriptor { } }; } + + public int getSqlType() { + return Types.BLOB; + } + + public ValueBinder getBinder(final JavaTypeDescriptor javaTypeDescriptor) { + return getBlobBinder( javaTypeDescriptor ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/ClobTypeDescriptor.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/ClobTypeDescriptor.java index 218e9e9a99..a0913e97a0 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/ClobTypeDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/ClobTypeDescriptor.java @@ -41,28 +41,62 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor; * * @author Steve Ebersole */ -public class ClobTypeDescriptor implements SqlTypeDescriptor { - public static final ClobTypeDescriptor INSTANCE = new ClobTypeDescriptor(); +public abstract class ClobTypeDescriptor implements SqlTypeDescriptor { + + public static final ClobTypeDescriptor DEFAULT = + new ClobTypeDescriptor() { + public BasicBinder getClobBinder(final JavaTypeDescriptor javaTypeDescriptor) { + return new BasicBinder( javaTypeDescriptor, this ) { + @Override + protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) throws SQLException { + if ( options.useStreamForLobBinding() ) { + STREAM_BINDING.getClobBinder( javaTypeDescriptor ).doBind( st, value, index, options ); + } + else { + CLOB_BINDING.getClobBinder( javaTypeDescriptor ).doBind( st, value, index, options ); + } + } + }; + } + }; + + public static final ClobTypeDescriptor CLOB_BINDING = + new ClobTypeDescriptor() { + public BasicBinder getClobBinder(final JavaTypeDescriptor javaTypeDescriptor) { + return new BasicBinder( javaTypeDescriptor, this ) { + @Override + protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) + throws SQLException { + st.setClob( index, javaTypeDescriptor.unwrap( value, Clob.class, options ) ); + } + }; + } + }; + + public static final ClobTypeDescriptor STREAM_BINDING = + new ClobTypeDescriptor() { + public BasicBinder getClobBinder(final JavaTypeDescriptor javaTypeDescriptor) { + return new BasicBinder( javaTypeDescriptor, this ) { + @Override + protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) + throws SQLException { + final CharacterStream characterStream = javaTypeDescriptor.unwrap( value, CharacterStream.class, options ); + st.setCharacterStream( index, characterStream.getReader(), characterStream.getLength() ); + } + }; + } + }; + + protected abstract BasicBinder getClobBinder(final JavaTypeDescriptor javaTypeDescriptor); + + public ValueBinder getBinder(final JavaTypeDescriptor javaTypeDescriptor) { + return getClobBinder( javaTypeDescriptor ); + } public int getSqlType() { return Types.CLOB; } - public ValueBinder getBinder(final JavaTypeDescriptor javaTypeDescriptor) { - return new BasicBinder( javaTypeDescriptor, this ) { - @Override - protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) throws SQLException { - if ( options.useStreamForLobBinding() ) { - final CharacterStream characterStream = javaTypeDescriptor.unwrap( value, CharacterStream.class, options ); - st.setCharacterStream( index, characterStream.getReader(), characterStream.getLength() ); - } - else { - st.setClob( index, javaTypeDescriptor.unwrap( value, Clob.class, options ) ); - } - } - }; - } - public ValueExtractor getExtractor(final JavaTypeDescriptor javaTypeDescriptor) { return new BasicExtractor( javaTypeDescriptor, this ) { @Override diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/lob/MaterializedBlobTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/lob/MaterializedBlobTest.java index dcecebd8e0..de19373961 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/lob/MaterializedBlobTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/lob/MaterializedBlobTest.java @@ -28,7 +28,7 @@ import java.util.Arrays; import org.hibernate.Session; import org.hibernate.cfg.AnnotationConfiguration; import org.hibernate.cfg.Configuration; -import org.hibernate.cfg.Environment; +import org.hibernate.dialect.PostgreSQLDialect; import org.hibernate.test.annotations.TestCase; import org.hibernate.testing.junit.DialectChecks; import org.hibernate.testing.junit.RequiresDialectFeature; diff --git a/hibernate-core/src/test/java/org/hibernate/test/typeoverride/Entity.hbm.xml b/hibernate-core/src/test/java/org/hibernate/test/typeoverride/Entity.hbm.xml new file mode 100644 index 0000000000..84386ea601 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/typeoverride/Entity.hbm.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + diff --git a/hibernate-core/src/test/java/org/hibernate/test/typeoverride/Entity.java b/hibernate-core/src/test/java/org/hibernate/test/typeoverride/Entity.java new file mode 100644 index 0000000000..e1f1f3e884 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/typeoverride/Entity.java @@ -0,0 +1,55 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program 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 distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.test.typeoverride; + +/** + * @author Gail Badner + */ +public class Entity { + private long id; + private String name; + + public Entity() { + } + + public Entity(String name) { + this.name = name; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/typeoverride/H2DialectOverridePrefixedVarcharSqlTypeDesc.java b/hibernate-core/src/test/java/org/hibernate/test/typeoverride/H2DialectOverridePrefixedVarcharSqlTypeDesc.java new file mode 100644 index 0000000000..b6ec851395 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/typeoverride/H2DialectOverridePrefixedVarcharSqlTypeDesc.java @@ -0,0 +1,41 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program 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 distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.test.typeoverride; + +import org.hibernate.dialect.H2Dialect; +import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; +import org.hibernate.type.descriptor.sql.VarcharTypeDescriptor; + +/** + * + * @author Gail Badner + */ +public class H2DialectOverridePrefixedVarcharSqlTypeDesc extends H2Dialect { + public SqlTypeDescriptor resolveSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) { + return sqlTypeDescriptor == StoredPrefixedStringType.INSTANCE.getSqlTypeDescriptor() ? + VarcharTypeDescriptor.INSTANCE : + super.resolveSqlTypeDescriptor( sqlTypeDescriptor ); + } +} + diff --git a/hibernate-core/src/test/java/org/hibernate/test/typeoverride/H2DialectOverrideVarcharSqlCode.java b/hibernate-core/src/test/java/org/hibernate/test/typeoverride/H2DialectOverrideVarcharSqlCode.java new file mode 100644 index 0000000000..7e2be2b90d --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/typeoverride/H2DialectOverrideVarcharSqlCode.java @@ -0,0 +1,42 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program 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 distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.test.typeoverride; + +import java.sql.Types; + +import org.hibernate.dialect.H2Dialect; +import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; + +/** + * + * @author Gail Badner + */ +public class H2DialectOverrideVarcharSqlCode extends H2Dialect { + public SqlTypeDescriptor getSqlTypeDescriptorOverride(int sqlCode) { + return sqlCode == Types.VARCHAR ? + StoredPrefixedStringType.INSTANCE.getSqlTypeDescriptor() : + super.getSqlTypeDescriptorOverride( sqlCode ); + } +} + diff --git a/hibernate-core/src/test/java/org/hibernate/test/typeoverride/StoredPrefixedStringType.java b/hibernate-core/src/test/java/org/hibernate/test/typeoverride/StoredPrefixedStringType.java new file mode 100644 index 0000000000..e00fb49984 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/typeoverride/StoredPrefixedStringType.java @@ -0,0 +1,105 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program 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 distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.test.typeoverride; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +import org.hibernate.AssertionFailure; +import org.hibernate.dialect.Dialect; +import org.hibernate.type.AbstractSingleColumnStandardBasicType; +import org.hibernate.type.DiscriminatorType; +import org.hibernate.type.StringType; +import org.hibernate.type.descriptor.ValueBinder; +import org.hibernate.type.descriptor.ValueExtractor; +import org.hibernate.type.descriptor.WrapperOptions; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; +import org.hibernate.type.descriptor.sql.BasicBinder; +import org.hibernate.type.descriptor.sql.BasicExtractor; +import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; +import org.hibernate.type.descriptor.sql.VarcharTypeDescriptor; + +/** + * + * @author Gail Badner + */ +public class StoredPrefixedStringType + extends AbstractSingleColumnStandardBasicType + implements DiscriminatorType { + public static final String PREFIX = "PRE:"; + private static final SqlTypeDescriptor PREFIXED_VARCHAR_TYPE_DESCRIPTOR = + new VarcharTypeDescriptor() { + public ValueBinder getBinder(final JavaTypeDescriptor javaTypeDescriptor) { + return new BasicBinder( javaTypeDescriptor, this ) { + @Override + protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) throws SQLException { + String stringValue = javaTypeDescriptor.unwrap( value, String.class, options ); + st.setString( index, PREFIX + stringValue ); + } + }; + } + + public ValueExtractor getExtractor(final JavaTypeDescriptor javaTypeDescriptor) { + return new BasicExtractor( javaTypeDescriptor, this ) { + @Override + protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException { + String stringValue = rs.getString( name ); + if ( ! stringValue.startsWith( PREFIX ) ) { + throw new AssertionFailure( "Value read from resultset does not have prefix." ); + } + return javaTypeDescriptor.wrap( stringValue.substring( PREFIX.length() ), options ); + } + }; + } + }; + + + public static final StoredPrefixedStringType INSTANCE = new StoredPrefixedStringType(); + + public StoredPrefixedStringType() { + super( PREFIXED_VARCHAR_TYPE_DESCRIPTOR, StringType.INSTANCE.getJavaTypeDescriptor() ); + } + + public String getName() { + return StringType.INSTANCE.getName(); + } + + @Override + protected boolean registerUnderJavaType() { + return true; + } + + public String objectToSQLString(String value, Dialect dialect) throws Exception { + return StringType.INSTANCE.objectToSQLString( value, dialect ); + } + + public String stringToObject(String xml) throws Exception { + return StringType.INSTANCE.stringToObject( xml ); + } + + public String toString(String value) { + return StringType.INSTANCE.toString( value ); + } +} \ No newline at end of file diff --git a/hibernate-core/src/test/java/org/hibernate/test/typeoverride/TypeOverrideTest.java b/hibernate-core/src/test/java/org/hibernate/test/typeoverride/TypeOverrideTest.java new file mode 100644 index 0000000000..f15f158df6 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/typeoverride/TypeOverrideTest.java @@ -0,0 +1,208 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program 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 distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.test.typeoverride; + +import org.hibernate.Session; +import org.hibernate.cfg.Configuration; +import org.hibernate.dialect.PostgreSQLDialect; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.engine.SessionImplementor; +import org.hibernate.testing.junit.functional.FunctionalTestCase; +import org.hibernate.type.StandardBasicTypes; +import org.hibernate.type.descriptor.sql.BlobTypeDescriptor; +import org.hibernate.type.descriptor.sql.ClobTypeDescriptor; +import org.hibernate.type.descriptor.sql.IntegerTypeDescriptor; +import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; +import org.hibernate.type.descriptor.sql.VarcharTypeDescriptor; + +/** + * + * @author Gail Badner + */ +public class TypeOverrideTest extends FunctionalTestCase { + + public TypeOverrideTest(String string) { + super( string ); + } + + public String[] getMappings() { + return new String[] { "typeoverride/Entity.hbm.xml" }; + } + + @Override + public void configure(Configuration cfg) { + cfg.registerTypeOverride( StoredPrefixedStringType.INSTANCE ); + } + + public void testStandardBasicSqlTypeDescriptor() { + // no override + assertTrue( StandardBasicTypes.isStandardBasicSqlTypeDescriptor( IntegerTypeDescriptor.INSTANCE ) ); + assertSame( IntegerTypeDescriptor.INSTANCE, getResolvedSqlTypeDescriptor( IntegerTypeDescriptor.INSTANCE ) ); + + // override depends on Dialect.useInputStreamToInsertBlob(); + // Postgresql explicitly overrides BlobTypeDescriptor.DEFAULT + assertTrue( StandardBasicTypes.isStandardBasicSqlTypeDescriptor( BlobTypeDescriptor.DEFAULT ) ); + if ( getDialect().useInputStreamToInsertBlob() ) { + assertSame( + BlobTypeDescriptor.STREAM_BINDING, + getDialect().resolveSqlTypeDescriptor( BlobTypeDescriptor.DEFAULT ) + ); + } + else if ( PostgreSQLDialect.class.isInstance( getDialect() ) ) { + assertSame( + BlobTypeDescriptor.BLOB_BINDING, + getDialect().resolveSqlTypeDescriptor( BlobTypeDescriptor.DEFAULT ) + ); + } + else { + assertSame( + BlobTypeDescriptor.DEFAULT, + getDialect().resolveSqlTypeDescriptor( BlobTypeDescriptor.DEFAULT ) + ); + } + } + + public void testNonStandardSqlTypeDescriptor() { + // no override + SqlTypeDescriptor sqlTypeDescriptor = new IntegerTypeDescriptor(); + assertFalse( StandardBasicTypes.isStandardBasicSqlTypeDescriptor( sqlTypeDescriptor ) ); + assertSame( sqlTypeDescriptor, getResolvedSqlTypeDescriptor( sqlTypeDescriptor ) ); + + // no override; (ClobTypeDescriptor.DEFAULT is overridden + // if Dialect.useInputStreamToInsertBlob() is true) + assertFalse( StandardBasicTypes.isStandardBasicSqlTypeDescriptor( ClobTypeDescriptor.CLOB_BINDING ) ); + assertSame( ClobTypeDescriptor.CLOB_BINDING, getResolvedSqlTypeDescriptor( ClobTypeDescriptor.CLOB_BINDING ) ); + } + + public void testDialectWithNonStandardSqlTypeDescriptor() { + assertNotSame( VarcharTypeDescriptor.INSTANCE, StoredPrefixedStringType.INSTANCE.getSqlTypeDescriptor() ); + if ( H2DialectOverridePrefixedVarcharSqlTypeDesc.class.isInstance( getDialect() ) ) { + // TODO: dialect is currently a global; how can this be tested in the testsuite? + assertSame( + VarcharTypeDescriptor.INSTANCE, + getResolvedSqlTypeDescriptor( StoredPrefixedStringType.INSTANCE.getSqlTypeDescriptor() ) + ); + } + else { + assertSame( + StoredPrefixedStringType.INSTANCE.getSqlTypeDescriptor(), + getResolvedSqlTypeDescriptor( StoredPrefixedStringType.INSTANCE.getSqlTypeDescriptor() ) + ); + } + + if ( H2DialectOverrideVarcharSqlCode.class.isInstance( getDialect() ) ) { + // TODO: dialect is currently a global; how can this be tested in the testsuite? + assertSame( + StoredPrefixedStringType.INSTANCE.getSqlTypeDescriptor(), + getResolvedSqlTypeDescriptor( VarcharTypeDescriptor.INSTANCE ) + ); + } + else { + assertSame( + VarcharTypeDescriptor.INSTANCE, + getResolvedSqlTypeDescriptor( VarcharTypeDescriptor.INSTANCE ) + ); + } + } + + private SqlTypeDescriptor getResolvedSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) { + return ( ( SessionFactoryImplementor ) getSessions() ) + .getTypeResolver() + .resolveSqlTypeDescriptor( sqlTypeDescriptor ); + } + + public void testInsert() { + Session s = openSession(); + s.getTransaction().begin(); + Entity e = new Entity( "name" ); + s.save( e ); + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.getTransaction().begin(); + e = ( Entity ) s.get( Entity.class, e.getId() ); + assertFalse( e.getName().startsWith( StoredPrefixedStringType.PREFIX ) ); + assertEquals( "name", e.getName() ); + s.delete( e ); + s.getTransaction().commit(); + s.close(); + } + + public void testRegisteredFunction() { + Session s = openSession(); + s.getTransaction().begin(); + Entity e = new Entity( "name " ); + s.save( e ); + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.getTransaction().begin(); + e = ( Entity ) s.get( Entity.class, e.getId() ); + assertFalse( e.getName().startsWith( StoredPrefixedStringType.PREFIX ) ); + assertEquals( "name ", e.getName() ); + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.getTransaction().begin(); + String trimmedName = ( String ) s.createQuery( "select trim( TRAILING from e.name ) from Entity e" ).uniqueResult(); + // trim(...) is a "standard" DB function returning VarcharTypeDescriptor.INSTANCE, + // so the prefix will not be removed unless + // 1) getDialect().getSqlTypeDescriptorOverride( VarcharTypeDescriptor.INSTANCE ) + // returns StoredPrefixedStringType.INSTANCE.getSqlTypeDescriptor() + // (H2DialectOverrideVarcharSqlCode does this) + // or 2) getDialect().getSqlTypeDescriptorOverride( StoredPrefixedStringType.INSTANCE.getSqlTypeDescriptor() ) + // returns VarcharTypeDescriptor.INSTANCE + // (H2DialectOverridePrefixedVarcharSqlTypeDesc does this) + // TODO: dialect is currently a global; how can this be tested in the testsuite? + assertNotSame( VarcharTypeDescriptor.INSTANCE, StoredPrefixedStringType.INSTANCE.getSqlTypeDescriptor() ); + if ( getDialect().resolveSqlTypeDescriptor( VarcharTypeDescriptor.INSTANCE ) == + StoredPrefixedStringType.INSTANCE.getSqlTypeDescriptor() || + getDialect().resolveSqlTypeDescriptor( StoredPrefixedStringType.INSTANCE.getSqlTypeDescriptor() ) == + VarcharTypeDescriptor.INSTANCE ) { + assertFalse( trimmedName.startsWith( StoredPrefixedStringType.PREFIX ) ); + assertEquals( "name", trimmedName ); + } + else { + assertSame( + VarcharTypeDescriptor.INSTANCE, + ( ( SessionFactoryImplementor ) getSessions() ) + .getTypeResolver() + .resolveSqlTypeDescriptor( VarcharTypeDescriptor.INSTANCE ) + ); + assertTrue( trimmedName.startsWith( StoredPrefixedStringType.PREFIX ) ); + assertEquals( StoredPrefixedStringType.PREFIX + "name", trimmedName ); + } + s.delete( e ); + s.getTransaction().commit(); + s.close(); + } +} + + + + + diff --git a/hibernate-core/src/test/java/org/hibernate/type/descriptor/sql/StringValueMappingTest.java b/hibernate-core/src/test/java/org/hibernate/type/descriptor/sql/StringValueMappingTest.java index 7e870dc8d8..3fd78a2f03 100644 --- a/hibernate-core/src/test/java/org/hibernate/type/descriptor/sql/StringValueMappingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/type/descriptor/sql/StringValueMappingTest.java @@ -36,8 +36,6 @@ import org.hibernate.type.descriptor.ValueBinder; import org.hibernate.type.descriptor.ValueExtractor; import org.hibernate.type.descriptor.WrapperOptions; import org.hibernate.type.descriptor.java.StringTypeDescriptor; -import org.hibernate.type.descriptor.sql.ClobTypeDescriptor; -import org.hibernate.type.descriptor.sql.VarcharTypeDescriptor; /** * TODO : javadoc @@ -48,7 +46,7 @@ public class StringValueMappingTest extends TestCase { private final StringTypeDescriptor stringJavaDescriptor = new StringTypeDescriptor(); private final VarcharTypeDescriptor varcharSqlDescriptor = new VarcharTypeDescriptor(); - private final ClobTypeDescriptor clobSqlDescriptor = new ClobTypeDescriptor(); + private final ClobTypeDescriptor clobSqlDescriptor = ClobTypeDescriptor.DEFAULT; private final WrapperOptions wrapperOptions = new WrapperOptions() { public boolean useStreamForLobBinding() { @@ -58,6 +56,10 @@ public class StringValueMappingTest extends TestCase { public LobCreator getLobCreator() { return NonContextualLobCreator.INSTANCE; } + + public SqlTypeDescriptor resolveSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) { + return sqlTypeDescriptor; + } }; public static final String COLUMN_NAME = "n/a"; From 7243d04541f5bb81f409d7f1033a133fc79e90ea Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Fri, 25 Feb 2011 16:29:09 -0800 Subject: [PATCH 02/19] HHH-5941 : remove deprecated set(), nullSafeSet(), get(), nullSafeGet() methods and add SessionImplementer argument to UserType.nullSafeGet()/nullSafeSet() --- ...AbstractSingleColumnStandardBasicType.java | 43 ------------------- .../java/org/hibernate/type/CustomType.java | 6 +-- .../java/org/hibernate/type/EnumType.java | 5 ++- .../org/hibernate/type/SingleColumnType.java | 30 ------------- .../org/hibernate/type/StringClobType.java | 5 ++- .../java/org/hibernate/usertype/UserType.java | 12 ++++-- .../annotations/entity/CasterStringType.java | 5 ++- .../entity/MonetaryAmountUserType.java | 8 ++-- .../annotations/entity/PhoneNumberType.java | 5 ++- .../test/annotations/generics/StateType.java | 5 ++- .../test/annotations/type/MyOidType.java | 16 +++---- .../test/cut/MonetoryAmountUserType.java | 8 ++-- .../test/hql/ClassificationType.java | 9 ++-- .../instrument/domain/CustomBlobType.java | 9 ++-- .../org/hibernate/test/rowid/RowIdType.java | 5 ++- .../test/sql/hand/MonetaryAmountUserType.java | 5 ++- .../DefaultValueIntegerType.java | 5 ++- .../hibernate/type/BasicTypeRegistryTest.java | 6 +-- .../envers/entities/RevisionTypeType.java | 29 ++++++------- .../customtype/ParametrizedTestUserType.java | 12 +++--- .../test/entities/ids/CustomEnumUserType.java | 6 ++- 21 files changed, 87 insertions(+), 147 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/type/AbstractSingleColumnStandardBasicType.java b/hibernate-core/src/main/java/org/hibernate/type/AbstractSingleColumnStandardBasicType.java index 51c6b95122..131f636fa1 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/AbstractSingleColumnStandardBasicType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/AbstractSingleColumnStandardBasicType.java @@ -48,38 +48,10 @@ public abstract class AbstractSingleColumnStandardBasicType super( sqlTypeDescriptor, javaTypeDescriptor ); } - private static WrapperOptions NO_OPTIONS = new WrapperOptions() { - public boolean useStreamForLobBinding() { - return false; - } - - public LobCreator getLobCreator() { - return NonContextualLobCreator.INSTANCE; - } - - public SqlTypeDescriptor resolveSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) { - return sqlTypeDescriptor; - } - }; - public final int sqlType() { return getSqlTypeDescriptor().getSqlType(); } - /** - * {@inheritDoc} - */ - public T nullSafeGet(ResultSet rs, String name) throws HibernateException, SQLException { - return nullSafeGet( rs, name, NO_OPTIONS ); - } - - /** - * {@inheritDoc} - */ - public Object get(ResultSet rs, String name) throws HibernateException, SQLException { - return nullSafeGet( rs, name ); - } - /** * {@inheritDoc} */ @@ -89,19 +61,4 @@ public abstract class AbstractSingleColumnStandardBasicType nullSafeSet( st, value, index, session ); } } - - /** - * {@inheritDoc} - */ - public void nullSafeSet(PreparedStatement st, T value, int index) throws HibernateException, SQLException { - nullSafeSet( st, value, index, NO_OPTIONS ); - } - - /** - * {@inheritDoc} - */ - public void set(PreparedStatement st, T value, int index) throws HibernateException, SQLException { - nullSafeSet( st, value, index ); - } - } \ No newline at end of file diff --git a/hibernate-core/src/main/java/org/hibernate/type/CustomType.java b/hibernate-core/src/main/java/org/hibernate/type/CustomType.java index 123ad4e757..73834769b7 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/CustomType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/CustomType.java @@ -106,7 +106,7 @@ public class CustomType extends AbstractType implements IdentifierType, Discrimi public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException { - return userType.nullSafeGet(rs, names, owner); + return userType.nullSafeGet(rs, names, session, owner); } public Object nullSafeGet(ResultSet rs, String columnName, SessionImplementor session, Object owner) @@ -137,13 +137,13 @@ public class CustomType extends AbstractType implements IdentifierType, Discrimi public void nullSafeSet(PreparedStatement st, Object value, int index, boolean[] settable, SessionImplementor session) throws HibernateException, SQLException { if ( settable[0] ) { - userType.nullSafeSet( st, value, index ); + userType.nullSafeSet( st, value, index, session ); } } public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException { - userType.nullSafeSet( st, value, index ); + userType.nullSafeSet( st, value, index, session ); } @SuppressWarnings({ "UnusedDeclaration" }) diff --git a/hibernate-core/src/main/java/org/hibernate/type/EnumType.java b/hibernate-core/src/main/java/org/hibernate/type/EnumType.java index b30571ad2a..a2afb739fb 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/EnumType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/EnumType.java @@ -34,6 +34,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.hibernate.HibernateException; +import org.hibernate.engine.SessionImplementor; import org.hibernate.usertype.EnhancedUserType; import org.hibernate.usertype.ParameterizedType; import org.hibernate.util.ReflectHelper; @@ -97,7 +98,7 @@ public class EnumType implements EnhancedUserType, ParameterizedType, Serializab } - public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException { + public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException { Object object = rs.getObject( names[0] ); if ( rs.wasNull() ) { if ( IS_VALUE_TRACING_ENABLED ) { @@ -130,7 +131,7 @@ public class EnumType implements EnhancedUserType, ParameterizedType, Serializab } } - public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { + public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException { if ( value == null ) { if ( IS_VALUE_TRACING_ENABLED ) { log().debug( "Binding null to parameter: {}", index ); diff --git a/hibernate-core/src/main/java/org/hibernate/type/SingleColumnType.java b/hibernate-core/src/main/java/org/hibernate/type/SingleColumnType.java index c93fdad579..247a749ca7 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/SingleColumnType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/SingleColumnType.java @@ -46,12 +46,6 @@ public interface SingleColumnType extends Type { public T fromStringValue(String xml) throws HibernateException; - /** - * @deprecated Use {@link #nullSafeGet(ResultSet, String, SessionImplementor)} instead - */ - @SuppressWarnings({ "JavaDoc" }) - public T nullSafeGet(ResultSet rs, String name) throws HibernateException, SQLException; - /** * Get a column value from a result set by name. * @@ -66,14 +60,6 @@ public interface SingleColumnType extends Type { */ public T nullSafeGet(ResultSet rs, String name, SessionImplementor session) throws HibernateException, SQLException; - /** - * DO NOT USER THIS FORM! - * - * @deprecated Use {@link #get(ResultSet, String, SessionImplementor)} instead. - */ - @SuppressWarnings({ "JavaDoc" }) - public Object get(ResultSet rs, String name) throws HibernateException, SQLException; - /** * Get a column value from a result set, without worrying about the possibility of null values. * @@ -88,22 +74,6 @@ public interface SingleColumnType extends Type { */ public Object get(ResultSet rs, String name, SessionImplementor session) throws HibernateException, SQLException; - /** - * DO NOT USE THIS FORM! - * - * @deprecated Use {@link #nullSafeSet(PreparedStatement, Object, int, SessionImplementor)} instead. - */ - @SuppressWarnings({ "JavaDoc" }) - public void nullSafeSet(PreparedStatement st, T value, int index) throws HibernateException, SQLException; - - /** - * DO NOT USE THIS FORM! - * - * @deprecated Use {@link #set(PreparedStatement, Object, int, SessionImplementor)} instead. - */ - @SuppressWarnings({ "JavaDoc" }) - public void set(PreparedStatement st, T value, int index) throws HibernateException, SQLException; - /** * Set a parameter value without worrying about the possibility of null * values. Called from {@link #nullSafeSet} after nullness checks have diff --git a/hibernate-core/src/main/java/org/hibernate/type/StringClobType.java b/hibernate-core/src/main/java/org/hibernate/type/StringClobType.java index 6926186538..a233d019b2 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/StringClobType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/StringClobType.java @@ -33,6 +33,7 @@ import java.sql.SQLException; import java.sql.Types; import org.hibernate.HibernateException; +import org.hibernate.engine.SessionImplementor; import org.hibernate.usertype.UserType; /** @@ -59,7 +60,7 @@ public class StringClobType implements UserType, Serializable { return x.hashCode(); } - public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException { + public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException { Reader reader = rs.getCharacterStream( names[0] ); if ( reader == null ) return null; StringBuilder result = new StringBuilder( 4096 ); @@ -75,7 +76,7 @@ public class StringClobType implements UserType, Serializable { return result.toString(); } - public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { + public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException { if ( value != null ) { String string = (String) value; StringReader reader = new StringReader( string ); diff --git a/hibernate-core/src/main/java/org/hibernate/usertype/UserType.java b/hibernate-core/src/main/java/org/hibernate/usertype/UserType.java index d993bc13eb..9e538ae3c9 100644 --- a/hibernate-core/src/main/java/org/hibernate/usertype/UserType.java +++ b/hibernate-core/src/main/java/org/hibernate/usertype/UserType.java @@ -30,6 +30,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import org.hibernate.HibernateException; +import org.hibernate.engine.SessionImplementor; /** * This interface should be implemented by user-defined "types". @@ -100,27 +101,30 @@ public interface UserType { * Retrieve an instance of the mapped class from a JDBC resultset. Implementors * should handle possibility of null values. * + * * @param rs a JDBC result set * @param names the column names - * @param owner the containing entity - * @return Object + * @param session + *@param owner the containing entity @return Object * @throws HibernateException * @throws SQLException */ - public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException; + public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException; /** * Write an instance of the mapped class to a prepared statement. Implementors * should handle possibility of null values. A multi-column type should be written * to parameters starting from index. * + * * @param st a JDBC prepared statement * @param value the object to write * @param index statement parameter index + * @param session * @throws HibernateException * @throws SQLException */ - public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException; + public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException; /** * Return a deep copy of the persistent state, stopping at entities and at diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/entity/CasterStringType.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/entity/CasterStringType.java index 6c145b78eb..cdd058f35f 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/entity/CasterStringType.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/entity/CasterStringType.java @@ -9,6 +9,7 @@ import java.sql.Types; import java.util.Properties; import org.hibernate.HibernateException; +import org.hibernate.engine.SessionImplementor; import org.hibernate.usertype.ParameterizedType; import org.hibernate.usertype.UserType; @@ -37,7 +38,7 @@ public class CasterStringType implements UserType, ParameterizedType { return x.hashCode(); } - public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException { + public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException { String result = rs.getString( names[0] ); if ( rs.wasNull() ) return null; if ( parameters.getProperty( CAST ).equals( "lower" ) ) { @@ -48,7 +49,7 @@ public class CasterStringType implements UserType, ParameterizedType { } } - public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { + public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException { if ( value == null ) { st.setNull( index, sqlTypes()[0] ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/entity/MonetaryAmountUserType.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/entity/MonetaryAmountUserType.java index 8925958438..670704a919 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/entity/MonetaryAmountUserType.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/entity/MonetaryAmountUserType.java @@ -62,8 +62,8 @@ public class MonetaryAmountUserType implements CompositeUserType { public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException { - BigDecimal amt = (BigDecimal) Hibernate.BIG_DECIMAL.nullSafeGet( rs, names[0] ); - Currency cur = (Currency) Hibernate.CURRENCY.nullSafeGet( rs, names[1] ); + BigDecimal amt = (BigDecimal) Hibernate.BIG_DECIMAL.nullSafeGet( rs, names[0], session); + Currency cur = (Currency) Hibernate.CURRENCY.nullSafeGet( rs, names[1], session ); if ( amt == null ) return null; return new MonetaryAmount( amt, cur ); } @@ -75,8 +75,8 @@ public class MonetaryAmountUserType implements CompositeUserType { MonetaryAmount ma = (MonetaryAmount) value; BigDecimal amt = ma == null ? null : ma.getAmount(); Currency cur = ma == null ? null : ma.getCurrency(); - Hibernate.BIG_DECIMAL.nullSafeSet( st, amt, index ); - Hibernate.CURRENCY.nullSafeSet( st, cur, index + 1 ); + Hibernate.BIG_DECIMAL.nullSafeSet( st, amt, index, session ); + Hibernate.CURRENCY.nullSafeSet( st, cur, index + 1, session ); } public Object deepCopy(Object value) throws HibernateException { diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/entity/PhoneNumberType.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/entity/PhoneNumberType.java index 0c642ed694..87180b0621 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/entity/PhoneNumberType.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/entity/PhoneNumberType.java @@ -29,6 +29,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; import org.hibernate.HibernateException; +import org.hibernate.engine.SessionImplementor; import org.hibernate.usertype.UserType; /** @@ -54,7 +55,7 @@ public class PhoneNumberType implements UserType { return x.hashCode(); } - public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException { + public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException { String result = rs.getString( names[0] ); if ( rs.wasNull() ) return null; @@ -66,7 +67,7 @@ public class PhoneNumberType implements UserType { } } - public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { + public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException { if ( value == null ) { st.setNull( index, sqlTypes()[0] ); return; diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/generics/StateType.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/generics/StateType.java index 88e1d4c7db..1ac9929ad2 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/generics/StateType.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/generics/StateType.java @@ -7,6 +7,7 @@ import java.sql.SQLException; import java.sql.PreparedStatement; import java.sql.Types; +import org.hibernate.engine.SessionImplementor; import org.hibernate.usertype.UserType; import org.hibernate.HibernateException; @@ -32,13 +33,13 @@ public class StateType implements UserType { return x.hashCode(); } - public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException { + public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException { int result = rs.getInt( names[0] ); if ( rs.wasNull() ) return null; return State.values()[result]; } - public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { + public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException { if (value == null) { st.setNull( index, Types.INTEGER ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/type/MyOidType.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/type/MyOidType.java index 608ace2c4c..8717a91965 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/type/MyOidType.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/type/MyOidType.java @@ -93,10 +93,10 @@ public class MyOidType implements CompositeUserType { public Object nullSafeGet( ResultSet aResultSet, String[] names, SessionImplementor aSessionImplementor, Object aObject ) throws HibernateException, SQLException { - Integer highval = (Integer) Hibernate.INTEGER.nullSafeGet( aResultSet, names[0] ); - Integer midval = (Integer) Hibernate.INTEGER.nullSafeGet( aResultSet, names[1] ); - Integer lowval = (Integer) Hibernate.INTEGER.nullSafeGet( aResultSet, names[2] ); - Integer other = (Integer) Hibernate.INTEGER.nullSafeGet( aResultSet, names[3] ); + Integer highval = (Integer) Hibernate.INTEGER.nullSafeGet( aResultSet, names[0], aSessionImplementor ); + Integer midval = (Integer) Hibernate.INTEGER.nullSafeGet( aResultSet, names[1], aSessionImplementor ); + Integer lowval = (Integer) Hibernate.INTEGER.nullSafeGet( aResultSet, names[2], aSessionImplementor ); + Integer other = (Integer) Hibernate.INTEGER.nullSafeGet( aResultSet, names[3], aSessionImplementor ); return new MyOid( highval, midval, lowval, other ); } @@ -113,10 +113,10 @@ public class MyOidType implements CompositeUserType { c = (MyOid) value; } - Hibernate.INTEGER.nullSafeSet( aPreparedStatement, c.getHigh(), index ); - Hibernate.INTEGER.nullSafeSet( aPreparedStatement, c.getMiddle(), index + 1 ); - Hibernate.INTEGER.nullSafeSet( aPreparedStatement, c.getLow(), index + 2 ); - Hibernate.INTEGER.nullSafeSet( aPreparedStatement, c.getOther(), index + 3 ); + Hibernate.INTEGER.nullSafeSet( aPreparedStatement, c.getHigh(), index, aSessionImplementor ); + Hibernate.INTEGER.nullSafeSet( aPreparedStatement, c.getMiddle(), index + 1, aSessionImplementor ); + Hibernate.INTEGER.nullSafeSet( aPreparedStatement, c.getLow(), index + 2, aSessionImplementor ); + Hibernate.INTEGER.nullSafeSet( aPreparedStatement, c.getOther(), index + 3, aSessionImplementor ); } public Object deepCopy(Object aObject) throws HibernateException { diff --git a/hibernate-core/src/test/java/org/hibernate/test/cut/MonetoryAmountUserType.java b/hibernate-core/src/test/java/org/hibernate/test/cut/MonetoryAmountUserType.java index 891544f141..220aa8252d 100755 --- a/hibernate-core/src/test/java/org/hibernate/test/cut/MonetoryAmountUserType.java +++ b/hibernate-core/src/test/java/org/hibernate/test/cut/MonetoryAmountUserType.java @@ -62,8 +62,8 @@ public class MonetoryAmountUserType implements CompositeUserType { public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException { - BigDecimal amt = (BigDecimal) Hibernate.BIG_DECIMAL.nullSafeGet( rs, names[0] ); - Currency cur = (Currency) Hibernate.CURRENCY.nullSafeGet( rs, names[1] ); + BigDecimal amt = (BigDecimal) Hibernate.BIG_DECIMAL.nullSafeGet( rs, names[0], session ); + Currency cur = (Currency) Hibernate.CURRENCY.nullSafeGet( rs, names[1], session ); if (amt==null) return null; return new MonetoryAmount(amt, cur); } @@ -73,8 +73,8 @@ public class MonetoryAmountUserType implements CompositeUserType { MonetoryAmount ma = (MonetoryAmount) value; BigDecimal amt = ma == null ? null : ma.getAmount(); Currency cur = ma == null ? null : ma.getCurrency(); - Hibernate.BIG_DECIMAL.nullSafeSet(st, amt, index); - Hibernate.CURRENCY.nullSafeSet(st, cur, index+1); + Hibernate.BIG_DECIMAL.nullSafeSet(st, amt, index, session); + Hibernate.CURRENCY.nullSafeSet(st, cur, index+1, session); } public Object deepCopy(Object value) throws HibernateException { diff --git a/hibernate-core/src/test/java/org/hibernate/test/hql/ClassificationType.java b/hibernate-core/src/test/java/org/hibernate/test/hql/ClassificationType.java index 945b14ad53..a4ee9282a7 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/hql/ClassificationType.java +++ b/hibernate-core/src/test/java/org/hibernate/test/hql/ClassificationType.java @@ -1,5 +1,6 @@ package org.hibernate.test.hql; +import org.hibernate.engine.SessionImplementor; import org.hibernate.type.IntegerType; import org.hibernate.usertype.EnhancedUserType; import org.hibernate.HibernateException; @@ -46,14 +47,14 @@ public class ClassificationType implements EnhancedUserType { return x.hashCode(); } - public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException { - Integer ordinal = ( Integer ) IntegerType.INSTANCE.nullSafeGet( rs, names[0] ); + public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException { + Integer ordinal = ( Integer ) IntegerType.INSTANCE.nullSafeGet( rs, names[0], session ); return Classification.valueOf( ordinal ); } - public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { + public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException { Integer ordinal = value == null ? null : new Integer( ( ( Classification ) value ).ordinal() ); - Hibernate.INTEGER.nullSafeSet( st, ordinal, index ); + Hibernate.INTEGER.nullSafeSet( st, ordinal, index, session ); } public Object deepCopy(Object value) throws HibernateException { diff --git a/hibernate-core/src/test/java/org/hibernate/test/instrument/domain/CustomBlobType.java b/hibernate-core/src/test/java/org/hibernate/test/instrument/domain/CustomBlobType.java index a4ab267cd4..a16dd72c2e 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/instrument/domain/CustomBlobType.java +++ b/hibernate-core/src/test/java/org/hibernate/test/instrument/domain/CustomBlobType.java @@ -9,6 +9,7 @@ import java.util.Arrays; import org.hibernate.HibernateException; import org.hibernate.Hibernate; +import org.hibernate.engine.SessionImplementor; import org.hibernate.usertype.UserType; /** @@ -18,17 +19,17 @@ public class CustomBlobType implements UserType { /** * {@inheritDoc} */ - public Object nullSafeGet(ResultSet rs, String names[], Object owner) throws SQLException { + public Object nullSafeGet(ResultSet rs, String names[], SessionImplementor session, Object owner) throws SQLException { // cast just to make sure... - return ( byte[] ) Hibernate.BINARY.nullSafeGet( rs, names[0] ); + return ( byte[] ) Hibernate.BINARY.nullSafeGet( rs, names[0], session ); } /** * {@inheritDoc} */ - public void nullSafeSet(PreparedStatement ps, Object value, int index) throws SQLException, HibernateException { + public void nullSafeSet(PreparedStatement ps, Object value, int index, SessionImplementor session) throws SQLException, HibernateException { // cast just to make sure... - Hibernate.BINARY.nullSafeSet( ps, ( byte[] ) value, index ); + Hibernate.BINARY.nullSafeSet( ps, ( byte[] ) value, index, session ); } /** diff --git a/hibernate-core/src/test/java/org/hibernate/test/rowid/RowIdType.java b/hibernate-core/src/test/java/org/hibernate/test/rowid/RowIdType.java index dabed44826..4384a852fd 100755 --- a/hibernate-core/src/test/java/org/hibernate/test/rowid/RowIdType.java +++ b/hibernate-core/src/test/java/org/hibernate/test/rowid/RowIdType.java @@ -8,6 +8,7 @@ import java.sql.SQLException; import java.sql.Types; import org.hibernate.HibernateException; +import org.hibernate.engine.SessionImplementor; import org.hibernate.usertype.UserType; /** @@ -31,12 +32,12 @@ public class RowIdType implements UserType { return x.hashCode(); } - public Object nullSafeGet(ResultSet rs, String[] names, Object owner) + public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException { return rs.getObject( names[0] ); } - public void nullSafeSet(PreparedStatement st, Object value, int index) + public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException { throw new UnsupportedOperationException(); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/sql/hand/MonetaryAmountUserType.java b/hibernate-core/src/test/java/org/hibernate/test/sql/hand/MonetaryAmountUserType.java index b548945aab..14ec4ed2f0 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/sql/hand/MonetaryAmountUserType.java +++ b/hibernate-core/src/test/java/org/hibernate/test/sql/hand/MonetaryAmountUserType.java @@ -9,6 +9,7 @@ import java.sql.Types; import java.util.Currency; import org.hibernate.HibernateException; +import org.hibernate.engine.SessionImplementor; import org.hibernate.usertype.UserType; /** @@ -40,7 +41,7 @@ public class MonetaryAmountUserType public Object nullSafeGet(ResultSet resultSet, String[] names, - Object owner) + SessionImplementor session, Object owner) throws HibernateException, SQLException { BigDecimal value = resultSet.getBigDecimal(names[0]); @@ -53,7 +54,7 @@ public class MonetaryAmountUserType public void nullSafeSet(PreparedStatement statement, Object value, - int index) + int index, SessionImplementor session) throws HibernateException, SQLException { if (value == null) { diff --git a/hibernate-core/src/test/java/org/hibernate/test/typeparameters/DefaultValueIntegerType.java b/hibernate-core/src/test/java/org/hibernate/test/typeparameters/DefaultValueIntegerType.java index 33eae97252..ad4662e610 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/typeparameters/DefaultValueIntegerType.java +++ b/hibernate-core/src/test/java/org/hibernate/test/typeparameters/DefaultValueIntegerType.java @@ -9,6 +9,7 @@ import java.util.Properties; import org.slf4j.LoggerFactory; import org.hibernate.HibernateException; +import org.hibernate.engine.SessionImplementor; import org.hibernate.usertype.ParameterizedType; import org.hibernate.usertype.UserType; @@ -34,12 +35,12 @@ public class DefaultValueIntegerType implements UserType, ParameterizedType, Ser return x.equals(y); } - public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException { + public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException { Number result = (Number) rs.getObject(names[0]); return result==null ? defaultValue : new Integer(result.intValue()); } - public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { + public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException { if (value == null || defaultValue.equals(value) ) { LoggerFactory.getLogger( getClass() ).trace("binding null to parameter: " + index); st.setNull(index, Types.INTEGER); diff --git a/hibernate-core/src/test/java/org/hibernate/type/BasicTypeRegistryTest.java b/hibernate-core/src/test/java/org/hibernate/type/BasicTypeRegistryTest.java index a757dbfc6f..d43a5f049a 100644 --- a/hibernate-core/src/test/java/org/hibernate/type/BasicTypeRegistryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/type/BasicTypeRegistryTest.java @@ -24,7 +24,6 @@ package org.hibernate.type; import java.io.Serializable; -import java.net.Socket; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; @@ -35,7 +34,6 @@ import junit.framework.TestCase; import org.hibernate.HibernateException; import org.hibernate.engine.SessionImplementor; import org.hibernate.type.descriptor.java.StringTypeDescriptor; -import org.hibernate.type.descriptor.java.UrlTypeDescriptor; import org.hibernate.type.descriptor.sql.VarcharTypeDescriptor; import org.hibernate.usertype.CompositeUserType; import org.hibernate.usertype.UserType; @@ -132,11 +130,11 @@ public class BasicTypeRegistryTest extends TestCase { return 0; } - public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException { + public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException { return null; } - public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { + public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException { } public Object deepCopy(Object value) throws HibernateException { diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/entities/RevisionTypeType.java b/hibernate-envers/src/main/java/org/hibernate/envers/entities/RevisionTypeType.java index c97d538f6c..8829106ec7 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/entities/RevisionTypeType.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/entities/RevisionTypeType.java @@ -29,9 +29,11 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; +import org.hibernate.engine.SessionImplementor; import org.hibernate.envers.RevisionType; import org.hibernate.HibernateException; +import org.hibernate.type.IntegerType; import org.hibernate.usertype.UserType; /** @@ -49,23 +51,20 @@ public class RevisionTypeType implements UserType { return RevisionType.class; } - public RevisionType nullSafeGet(ResultSet resultSet, String[] names, Object owner) throws HibernateException, SQLException { - byte representation = (byte) resultSet.getInt(names[0]); - RevisionType result = null; - - if (!resultSet.wasNull()) { - result = RevisionType.fromRepresentation(representation); - } - - return result; + public RevisionType nullSafeGet(ResultSet resultSet, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException { + Integer representationInt = IntegerType.INSTANCE.nullSafeGet( resultSet, names[0], session ); + return representationInt == null ? + null : + RevisionType.fromRepresentation( representationInt.byteValue() ); } - public void nullSafeSet(PreparedStatement preparedStatement, Object value, int index) throws HibernateException, SQLException { - if (null == value) { - preparedStatement.setNull(index, Types.TINYINT); - } else { - preparedStatement.setInt(index, ((RevisionType) value).getRepresentation()); - } + public void nullSafeSet(PreparedStatement preparedStatement, Object value, int index, SessionImplementor session) throws HibernateException, SQLException { + IntegerType.INSTANCE.nullSafeSet( + preparedStatement, + ( value == null ? null : ((RevisionType) value).getRepresentation().intValue() ), + index, + session + ); } public Object deepCopy(Object value) throws HibernateException{ diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/entities/customtype/ParametrizedTestUserType.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/entities/customtype/ParametrizedTestUserType.java index 83bc29b0e1..2a2825173c 100644 --- a/hibernate-envers/src/test/java/org/hibernate/envers/test/entities/customtype/ParametrizedTestUserType.java +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/entities/customtype/ParametrizedTestUserType.java @@ -30,8 +30,8 @@ import java.sql.SQLException; import java.sql.Types; import java.util.Properties; -import org.hibernate.Hibernate; import org.hibernate.HibernateException; +import org.hibernate.engine.SessionImplementor; import org.hibernate.type.StringType; import org.hibernate.usertype.ParameterizedType; import org.hibernate.usertype.UserType; @@ -54,11 +54,11 @@ public class ParametrizedTestUserType implements UserType, ParameterizedType { return String.class; } - public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException { - return StringType.INSTANCE.nullSafeGet( rs, names[0] ); + public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException { + return StringType.INSTANCE.nullSafeGet( rs, names[0], session ); } - public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { + public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException { if (value != null) { String v = (String) value; if (!v.startsWith(param1)) { @@ -67,10 +67,10 @@ public class ParametrizedTestUserType implements UserType, ParameterizedType { if (!v.endsWith(param2)) { v = v + param2; } - StringType.INSTANCE.nullSafeSet(st, v, index); + StringType.INSTANCE.nullSafeSet(st, v, index, session); } else { - StringType.INSTANCE.nullSafeSet( st, null, index ); + StringType.INSTANCE.nullSafeSet( st, null, index, session ); } } diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/entities/ids/CustomEnumUserType.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/entities/ids/CustomEnumUserType.java index 69c590052c..2f39c24146 100644 --- a/hibernate-envers/src/test/java/org/hibernate/envers/test/entities/ids/CustomEnumUserType.java +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/entities/ids/CustomEnumUserType.java @@ -30,6 +30,8 @@ import java.sql.SQLException; import java.sql.Types; import org.hibernate.HibernateException; +import org.hibernate.engine.SessionImplementor; +import org.hibernate.type.StringType; import org.hibernate.usertype.UserType; /** @@ -60,7 +62,7 @@ public class CustomEnumUserType implements UserType { return (x == null) ? 0 : x.hashCode(); } - public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException { + public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException { String name = rs.getString(names[0]); if (rs.wasNull()) { return null; @@ -68,7 +70,7 @@ public class CustomEnumUserType implements UserType { return CustomEnum.fromYesNo(name); } - public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { + public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException { CustomEnum val = (CustomEnum) value; if (val == null) { st.setNull(index, Types.VARCHAR); From 08d9fe2117a1afc60ad15cb1b6124b057b6eae32 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Wed, 2 Mar 2011 15:57:28 -0600 Subject: [PATCH 03/19] HHH-5949 - Migrate, complete and integrate TransactionFactory as a service --- build.gradle | 8 +- .../org/hibernate/HibernateException.java | 12 +- ...okup.java => ResourceClosedException.java} | 22 +- .../java/org/hibernate/SessionFactory.java | 3 +- .../main/java/org/hibernate/Transaction.java | 167 +++-- .../java/org/hibernate/cfg/Configuration.java | 14 +- .../java/org/hibernate/cfg/Environment.java | 5 +- .../main/java/org/hibernate/cfg/Settings.java | 46 +- .../org/hibernate/cfg/SettingsFactory.java | 52 +- .../hibernate/context/JTASessionContext.java | 14 +- .../context/ThreadLocalSessionContext.java | 14 +- .../PessimisticReadSelectLockingStrategy.java | 2 +- .../PessimisticReadUpdateLockingStrategy.java | 2 +- ...PessimisticWriteSelectLockingStrategy.java | 2 +- ...PessimisticWriteUpdateLockingStrategy.java | 2 +- .../dialect/lock/SelectLockingStrategy.java | 2 +- .../dialect/lock/UpdateLockingStrategy.java | 2 +- .../org/hibernate/engine/ActionQueue.java | 2 +- .../engine/SessionFactoryImplementor.java | 9 +- .../hibernate/engine/SessionImplementor.java | 27 +- .../hibernate/engine/TransactionHelper.java | 34 +- .../batch/internal/AbstractBatchImpl.java | 134 ++-- .../jdbc/batch/internal/BasicBatchKey.java | 89 +++ ...atchBuilder.java => BatchBuilderImpl.java} | 49 +- .../batch/internal/BatchBuilderInitiator.java | 69 ++ .../jdbc/batch/internal/BatchingBatch.java | 197 ++---- .../jdbc/batch/internal/NonBatchingBatch.java | 54 +- .../engine/jdbc/batch/spi/Batch.java | 23 +- .../engine/jdbc/batch/spi/BatchBuilder.java | 45 ++ .../jdbc/batch/spi/BatchKey.java} | 39 +- .../jdbc/internal/ConnectionManagerImpl.java | 611 ------------------ .../engine/jdbc/internal/JDBCContextImpl.java | 369 ----------- .../jdbc/internal/JdbcCoordinatorImpl.java | 236 +++++++ .../jdbc/internal/LogicalConnectionImpl.java | 309 ++++----- .../jdbc/internal/StatementPreparer.java | 276 -------- .../jdbc/internal/StatementPreparerImpl.java | 223 +++++++ .../proxy/ConnectionProxyHandler.java | 36 +- .../engine/jdbc/spi/ConnectionObserver.java | 5 + .../jdbc/spi/ConnectionObserverAdapter.java} | 89 +-- .../engine/jdbc/spi/JDBCContext.java | 83 --- .../jdbc/spi/JdbcContext.java} | 47 +- .../engine/jdbc/spi/JdbcCoordinator.java | 96 +++ .../engine/jdbc/spi/JdbcResourceRegistry.java | 3 +- .../engine/jdbc/spi/LogicalConnection.java | 21 +- .../spi/LogicalConnectionImplementor.java | 38 +- .../spi/NonDurableConnectionObserver.java} | 23 +- .../engine/jdbc/spi/SQLExceptionHelper.java | 3 +- .../engine/jdbc/spi/StatementPreparer.java | 97 +++ .../engine/query/NativeSQLQueryPlan.java | 2 +- .../engine/transaction/Isolater.java | 307 --------- .../NullSynchronizationException.java | 4 +- .../SynchronizationRegistryImpl.java} | 42 +- .../internal/TransactionCoordinatorImpl.java | 348 ++++++++++ .../internal/TransactionFactoryInitiator.java | 96 +++ .../internal/jdbc/JdbcIsolationDelegate.java | 123 ++++ .../internal/jdbc/JdbcTransaction.java | 208 ++++++ .../internal/jdbc/JdbcTransactionFactory.java | 71 ++ .../internal/jta/CMTTransaction.java | 154 +++++ .../internal/jta}/CMTTransactionFactory.java | 66 +- .../internal/jta/JtaIsolationDelegate.java | 185 ++++++ .../internal}/jta/JtaStatusHelper.java | 25 +- .../internal/jta/JtaTransaction.java | 276 ++++++++ .../internal/jta/JtaTransactionFactory.java | 109 ++++ .../spi/AbstractTransactionImpl.java | 237 +++++++ .../transaction/spi/IsolationDelegate.java | 44 ++ .../transaction/spi/JoinStatus.java} | 15 +- .../engine/transaction/spi/LocalStatus.java | 52 ++ .../spi/SynchronizationRegistry.java | 57 ++ .../transaction/spi/TransactionContext.java | 105 +++ .../spi/TransactionCoordinator.java | 139 ++++ .../spi/TransactionEnvironment.java | 63 ++ .../transaction/spi/TransactionFactory.java | 93 +++ .../spi/TransactionImplementor.java | 67 ++ .../transaction/spi/TransactionObserver.java | 57 ++ .../internal/RegisteredSynchronization.java} | 26 +- ...nchronizationCallbackCoordinatorImpl.java} | 117 ++-- .../spi/AfterCompletionAction.java | 38 ++ .../synchronization/spi}/ExceptionMapper.java | 12 +- .../spi/ManagedFlushChecker.java} | 26 +- .../SynchronizationCallbackCoordinator.java | 35 + .../def/AbstractFlushingEventListener.java | 4 +- .../event/def/AbstractSaveEventListener.java | 2 +- .../exception/SQLExceptionConverter.java | 5 +- .../ast/exec/AbstractStatementExecutor.java | 181 +++--- .../hibernate/hql/ast/exec/BasicExecutor.java | 2 +- .../ast/exec/MultiTableDeleteExecutor.java | 4 +- .../ast/exec/MultiTableUpdateExecutor.java | 4 +- .../java/org/hibernate/id/GUIDGenerator.java | 2 +- .../org/hibernate/id/IdentityGenerator.java | 10 +- .../org/hibernate/id/IncrementGenerator.java | 2 +- .../org/hibernate/id/SequenceGenerator.java | 2 +- .../id/SequenceIdentityGenerator.java | 2 +- .../id/enhanced/SequenceStructure.java | 2 +- .../id/insert/AbstractSelectingDelegate.java | 10 +- .../hibernate/impl/AbstractSessionImpl.java | 9 +- .../impl/ConnectionObserverStatsBridge.java | 59 ++ .../hibernate/impl/SessionFactoryImpl.java | 134 ++-- .../java/org/hibernate/impl/SessionImpl.java | 307 ++++----- .../hibernate/impl/StatelessSessionImpl.java | 88 +-- .../impl/TransactionEnvironmentImpl.java | 67 ++ .../jdbc/BorrowedConnectionProxy.java | 138 ---- .../org/hibernate/jmx/HibernateService.java | 42 +- .../hibernate/jmx/HibernateServiceMBean.java | 35 +- .../java/org/hibernate/loader/Loader.java | 22 +- .../AbstractCollectionPersister.java | 143 ++-- .../collection/BasicCollectionPersister.java | 26 +- .../collection/OneToManyPersister.java | 108 ++-- .../entity/AbstractEntityPersister.java | 207 +++--- .../service/internal/ServiceInitializer.java | 20 +- .../service/internal/ServiceRegistryImpl.java | 3 +- .../DriverManagerConnectionProviderImpl.java | 13 +- .../internal/AbstractJtaPlatform.java | 133 ++++ .../internal/BitronixJtaPlatform.java} | 133 ++-- .../BorlandEnterpriseServerJtaPlatform.java | 52 ++ .../internal/JBossAppServerPlatform.java | 64 +- .../internal/JBossStandAloneJtaPlatform.java | 70 ++ .../platform/internal/JOTMJtaPlatform.java | 63 ++ .../platform/internal/JOnASJtaPlatform.java} | 50 +- .../platform/internal/JRun4JtaPlatform.java | 55 ++ .../internal/JtaPlatformInitiator.java | 130 +++- .../internal/JtaSynchronizationStrategy.java | 48 ++ .../jta/platform/internal/NoJtaPlatform.java} | 72 +-- .../platform/internal/OC4JJtaPlatform.java | 55 ++ .../platform/internal/OrionJtaPlatform.java | 55 ++ .../platform/internal/ResinJtaPlatform.java | 55 ++ .../platform/internal/SunOneJtaPlatform.java | 57 ++ .../SynchronizationRegistryAccess.java | 42 ++ ...nRegistryBasedSynchronizationStrategy.java | 56 ++ .../internal/TransactionManagerAccess.java} | 26 +- ...onManagerBasedSynchronizationStrategy.java | 58 ++ .../TransactionManagerLookupBridge.java | 67 ++ .../WebSphereExtendedJtaPlatform.java} | 168 ++--- .../internal/WebSphereJtaPlatform.java | 103 +++ .../internal/WeblogicJtaPlatform.java | 55 ++ .../service/jta/platform/spi/JtaPlatform.java | 41 +- .../platform/spi/JtaPlatformException.java} | 25 +- .../org/hibernate/service/spi/Service.java | 6 +- .../spi/StandardServiceInitiators.java | 5 +- .../BESTransactionManagerLookup.java | 42 -- .../hibernate/transaction/CMTTransaction.java | 224 ------- .../transaction/CacheSynchronization.java | 134 ---- ...sTSStandaloneTransactionManagerLookup.java | 66 -- .../transaction/JDBCTransaction.java | 275 -------- .../transaction/JDBCTransactionFactory.java | 96 --- .../JNDITransactionManagerLookup.java | 77 --- .../hibernate/transaction/JTATransaction.java | 359 ---------- .../transaction/JTATransactionFactory.java | 254 -------- .../SunONETransactionManagerLookup.java | 50 -- .../transaction/TransactionFactory.java | 124 ---- .../TransactionFactoryFactory.java | 88 --- .../TransactionManagerLookupFactory.java | 97 --- .../WebSphereTransactionManagerLookup.java | 111 ---- .../org/hibernate/type/DbTimestampType.java | 22 +- .../java/org/hibernate/util/JTAHelper.java | 3 +- .../manytomany/ManyToManyTest.java | 42 +- .../polymorphism/PolymorphismTest.java | 1 - .../annotations/subselect/SubselectTest.java | 3 +- .../test/common/JournalingBatchObserver.java | 57 ++ .../common/JournalingConnectionObserver.java | 74 +++ .../JournalingTransactionObserver.java} | 52 +- .../test/common/TransactionContextImpl.java | 95 +++ .../common/TransactionEnvironmentImpl.java | 63 ++ .../AtomikosDataSourceConnectionProvider.java | 82 +++ .../test/common/jta/AtomikosJtaPlatform.java | 129 ++++ .../connections/AggressiveReleaseTest.java | 81 ++- .../CurrentSessionConnectionTest.java | 5 + .../exception/SQLExceptionConversionTest.java | 10 +- .../insertordering/InsertOrderingTest.java | 64 +- .../jdbc/proxies/AggressiveReleaseTest.java | 115 ++-- .../proxies/BasicConnectionProxyTest.java | 9 +- .../test/jdbc/proxies/BatchingTest.java | 213 ++++++ .../batchload/BatchedManyToManyTest.java | 47 +- .../AbstractOperationTestCase.java | 2 +- .../org/hibernate/test/ops/CreateTest.java | 2 +- .../test/readonly/ReadOnlyProxyTest.java | 2 - .../java/org/hibernate/test/tm/CMTTest.java | 193 +++--- .../transaction/jdbc/TestExpectedUsage.java | 139 ++++ .../transaction/jta/BasicDrivingTest.java | 162 +++++ .../transaction/jta/ManagedDrivingTest.java | 178 +++++ .../cache/BaseCacheProviderTestCase.java | 4 +- .../src/test/resources/log4j.properties | 1 + 181 files changed, 8187 insertions(+), 5961 deletions(-) rename hibernate-core/src/main/java/org/hibernate/{transaction/JRun4TransactionManagerLookup.java => ResourceClosedException.java} (66%) create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BasicBatchKey.java rename hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/{BatchBuilder.java => BatchBuilderImpl.java} (59%) create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchBuilderInitiator.java create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/spi/BatchBuilder.java rename hibernate-core/src/main/java/org/hibernate/{transaction/ResinTransactionManagerLookup.java => engine/jdbc/batch/spi/BatchKey.java} (59%) delete mode 100644 hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/ConnectionManagerImpl.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/JDBCContextImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/JdbcCoordinatorImpl.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/StatementPreparer.java create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/StatementPreparerImpl.java rename hibernate-core/src/main/java/org/hibernate/{jdbc/ConnectionWrapper.java => engine/jdbc/spi/ConnectionObserverAdapter.java} (66%) delete mode 100644 hibernate-core/src/main/java/org/hibernate/engine/jdbc/spi/JDBCContext.java rename hibernate-core/src/main/java/org/hibernate/{transaction/OrionTransactionManagerLookup.java => engine/jdbc/spi/JdbcContext.java} (55%) create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/jdbc/spi/JdbcCoordinator.java rename hibernate-core/src/main/java/org/hibernate/{transaction/JBossTransactionManagerLookup.java => engine/jdbc/spi/NonDurableConnectionObserver.java} (65%) create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/jdbc/spi/StatementPreparer.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/engine/transaction/Isolater.java rename hibernate-core/src/main/java/org/hibernate/engine/transaction/{ => internal}/NullSynchronizationException.java (89%) rename hibernate-core/src/main/java/org/hibernate/engine/transaction/{SynchronizationRegistry.java => internal/SynchronizationRegistryImpl.java} (75%) create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/transaction/internal/TransactionCoordinatorImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/transaction/internal/TransactionFactoryInitiator.java create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/transaction/internal/jdbc/JdbcIsolationDelegate.java create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/transaction/internal/jdbc/JdbcTransaction.java create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/transaction/internal/jdbc/JdbcTransactionFactory.java create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/transaction/internal/jta/CMTTransaction.java rename hibernate-core/src/main/java/org/hibernate/{transaction => engine/transaction/internal/jta}/CMTTransactionFactory.java (50%) mode change 100755 => 100644 create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/transaction/internal/jta/JtaIsolationDelegate.java rename hibernate-core/src/main/java/org/hibernate/{internal/util => engine/transaction/internal}/jta/JtaStatusHelper.java (89%) create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/transaction/internal/jta/JtaTransaction.java create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/transaction/internal/jta/JtaTransactionFactory.java create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/transaction/spi/AbstractTransactionImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/transaction/spi/IsolationDelegate.java rename hibernate-core/src/main/java/org/hibernate/{transaction/synchronization/AfterCompletionAction.java => engine/transaction/spi/JoinStatus.java} (77%) create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/transaction/spi/LocalStatus.java create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/transaction/spi/SynchronizationRegistry.java create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/transaction/spi/TransactionContext.java create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/transaction/spi/TransactionCoordinator.java create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/transaction/spi/TransactionEnvironment.java create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/transaction/spi/TransactionFactory.java create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/transaction/spi/TransactionImplementor.java create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/transaction/spi/TransactionObserver.java rename hibernate-core/src/main/java/org/hibernate/{transaction/synchronization/HibernateSynchronizationImpl.java => engine/transaction/synchronization/internal/RegisteredSynchronization.java} (60%) rename hibernate-core/src/main/java/org/hibernate/{transaction/synchronization/CallbackCoordinator.java => engine/transaction/synchronization/internal/SynchronizationCallbackCoordinatorImpl.java} (53%) create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/transaction/synchronization/spi/AfterCompletionAction.java rename hibernate-core/src/main/java/org/hibernate/{transaction/synchronization => engine/transaction/synchronization/spi}/ExceptionMapper.java (79%) rename hibernate-core/src/main/java/org/hibernate/{transaction/synchronization/BeforeCompletionManagedFlushChecker.java => engine/transaction/synchronization/spi/ManagedFlushChecker.java} (58%) create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/transaction/synchronization/spi/SynchronizationCallbackCoordinator.java create mode 100644 hibernate-core/src/main/java/org/hibernate/impl/ConnectionObserverStatsBridge.java create mode 100644 hibernate-core/src/main/java/org/hibernate/impl/TransactionEnvironmentImpl.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/jdbc/BorrowedConnectionProxy.java create mode 100644 hibernate-core/src/main/java/org/hibernate/service/jta/platform/internal/AbstractJtaPlatform.java rename hibernate-core/src/main/java/org/hibernate/{transaction/BTMTransactionManagerLookup.java => service/jta/platform/internal/BitronixJtaPlatform.java} (51%) create mode 100644 hibernate-core/src/main/java/org/hibernate/service/jta/platform/internal/BorlandEnterpriseServerJtaPlatform.java create mode 100644 hibernate-core/src/main/java/org/hibernate/service/jta/platform/internal/JBossStandAloneJtaPlatform.java create mode 100644 hibernate-core/src/main/java/org/hibernate/service/jta/platform/internal/JOTMJtaPlatform.java rename hibernate-core/src/main/java/org/hibernate/{transaction/JOnASTransactionManagerLookup.java => service/jta/platform/internal/JOnASJtaPlatform.java} (55%) create mode 100644 hibernate-core/src/main/java/org/hibernate/service/jta/platform/internal/JRun4JtaPlatform.java create mode 100644 hibernate-core/src/main/java/org/hibernate/service/jta/platform/internal/JtaSynchronizationStrategy.java rename hibernate-core/src/main/java/org/hibernate/{transaction/JOTMTransactionManagerLookup.java => service/jta/platform/internal/NoJtaPlatform.java} (53%) create mode 100644 hibernate-core/src/main/java/org/hibernate/service/jta/platform/internal/OC4JJtaPlatform.java create mode 100644 hibernate-core/src/main/java/org/hibernate/service/jta/platform/internal/OrionJtaPlatform.java create mode 100644 hibernate-core/src/main/java/org/hibernate/service/jta/platform/internal/ResinJtaPlatform.java create mode 100644 hibernate-core/src/main/java/org/hibernate/service/jta/platform/internal/SunOneJtaPlatform.java create mode 100644 hibernate-core/src/main/java/org/hibernate/service/jta/platform/internal/SynchronizationRegistryAccess.java create mode 100644 hibernate-core/src/main/java/org/hibernate/service/jta/platform/internal/SynchronizationRegistryBasedSynchronizationStrategy.java rename hibernate-core/src/main/java/org/hibernate/{engine/transaction/IsolatedWork.java => service/jta/platform/internal/TransactionManagerAccess.java} (61%) create mode 100644 hibernate-core/src/main/java/org/hibernate/service/jta/platform/internal/TransactionManagerBasedSynchronizationStrategy.java create mode 100644 hibernate-core/src/main/java/org/hibernate/service/jta/platform/internal/TransactionManagerLookupBridge.java rename hibernate-core/src/main/java/org/hibernate/{transaction/WebSphereExtendedJTATransactionLookup.java => service/jta/platform/internal/WebSphereExtendedJtaPlatform.java} (73%) mode change 100755 => 100644 create mode 100644 hibernate-core/src/main/java/org/hibernate/service/jta/platform/internal/WebSphereJtaPlatform.java create mode 100644 hibernate-core/src/main/java/org/hibernate/service/jta/platform/internal/WeblogicJtaPlatform.java rename hibernate-core/src/main/java/org/hibernate/{transaction/OC4JTransactionManagerLookup.java => service/jta/platform/spi/JtaPlatformException.java} (65%) delete mode 100644 hibernate-core/src/main/java/org/hibernate/transaction/BESTransactionManagerLookup.java delete mode 100755 hibernate-core/src/main/java/org/hibernate/transaction/CMTTransaction.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/transaction/CacheSynchronization.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/transaction/JBossTSStandaloneTransactionManagerLookup.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/transaction/JDBCTransaction.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/transaction/JDBCTransactionFactory.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/transaction/JNDITransactionManagerLookup.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/transaction/JTATransaction.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/transaction/JTATransactionFactory.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/transaction/SunONETransactionManagerLookup.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/transaction/TransactionFactory.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/transaction/TransactionFactoryFactory.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/transaction/TransactionManagerLookupFactory.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/transaction/WebSphereTransactionManagerLookup.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/common/JournalingBatchObserver.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/common/JournalingConnectionObserver.java rename hibernate-core/src/{main/java/org/hibernate/transaction/WeblogicTransactionManagerLookup.java => test/java/org/hibernate/test/common/JournalingTransactionObserver.java} (50%) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/common/TransactionContextImpl.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/common/TransactionEnvironmentImpl.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/common/jta/AtomikosDataSourceConnectionProvider.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/common/jta/AtomikosJtaPlatform.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/jdbc/proxies/BatchingTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/transaction/jdbc/TestExpectedUsage.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/transaction/jta/BasicDrivingTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/transaction/jta/ManagedDrivingTest.java diff --git a/build.gradle b/build.gradle index efada05429..5d250557a0 100644 --- a/build.gradle +++ b/build.gradle @@ -67,6 +67,7 @@ libraries = [ jcl: 'commons-logging:commons-logging:99.0-does-not-exist', // testing + atomikos: 'com.atomikos:transactions-jdbc:3.6.4', junit: 'junit:junit:3.8.2', testng: 'org.testng:testng:5.8:jdk15', jpa_modelgen: 'org.hibernate:hibernate-jpamodelgen:1.1.0.Final', @@ -106,6 +107,7 @@ subprojects { subProject -> dependencies { compile( libraries.slf4j_api ) testCompile( libraries.junit ) + testCompile( libraries.atomikos ) testRuntime( libraries.slf4j_simple ) testRuntime( libraries.jcl_slf4j ) testRuntime( libraries.jcl_api ) @@ -151,12 +153,8 @@ subprojects { subProject -> sourceCompatibility = "1.6" ideaModule { - // treat our "provided" configuration dependencies as "Compile" scope dependencies in IntelliJ + // treat our "provided" configuration dependencies as "compile" scope dependencies in IntelliJ scopes.COMPILE.plus.add( configurations.provided ) - // Use explicitly separate compilation output directories for Gradle and IntelliJ - File baseDirectory = new File( subProject.buildDir, "idea/classes" ) - outputDir = new File( baseDirectory, "main" ) - testOutputDir = new File( baseDirectory, "test" ) whenConfigured { module -> module.dependencies*.exported = true } diff --git a/hibernate-core/src/main/java/org/hibernate/HibernateException.java b/hibernate-core/src/main/java/org/hibernate/HibernateException.java index 4699d28dc7..5e75777632 100644 --- a/hibernate-core/src/main/java/org/hibernate/HibernateException.java +++ b/hibernate-core/src/main/java/org/hibernate/HibernateException.java @@ -1,10 +1,10 @@ /* * Hibernate, Relational Persistence for Idiomatic Java * - * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as + * Copyright (c) 2007-2011, Red Hat Inc. or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are - * distributed under license by Red Hat Middleware LLC. + * distributed under license by Red Hat Inc. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU @@ -20,7 +20,6 @@ * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA - * */ package org.hibernate; @@ -35,6 +34,9 @@ package org.hibernate; * @author Gavin King */ public class HibernateException extends RuntimeException { + public HibernateException(String s) { + super(s); + } public HibernateException(Throwable root) { super(root); @@ -43,10 +45,6 @@ public class HibernateException extends RuntimeException { public HibernateException(String string, Throwable root) { super(string, root); } - - public HibernateException(String s) { - super(s); - } } diff --git a/hibernate-core/src/main/java/org/hibernate/transaction/JRun4TransactionManagerLookup.java b/hibernate-core/src/main/java/org/hibernate/ResourceClosedException.java similarity index 66% rename from hibernate-core/src/main/java/org/hibernate/transaction/JRun4TransactionManagerLookup.java rename to hibernate-core/src/main/java/org/hibernate/ResourceClosedException.java index 5f0bf15fd0..800d478cf0 100644 --- a/hibernate-core/src/main/java/org/hibernate/transaction/JRun4TransactionManagerLookup.java +++ b/hibernate-core/src/main/java/org/hibernate/ResourceClosedException.java @@ -1,10 +1,10 @@ /* * Hibernate, Relational Persistence for Idiomatic Java * - * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as + * Copyright (c) 2011, Red Hat Inc. or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are - * distributed under license by Red Hat Middleware LLC. + * distributed under license by Red Hat Inc. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU @@ -20,22 +20,20 @@ * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA - * */ -package org.hibernate.transaction; +package org.hibernate; /** - * {@link TransactionManagerLookup} strategy for JRun4 AS + * Indicates an attempt was made to use a closed resource (Session, SessionFactory, etc). * - * @author Joseph Bissen + * @author Steve Ebersole */ -public class JRun4TransactionManagerLookup extends JNDITransactionManagerLookup { - - protected String getName() { - return "java:/TransactionManager"; +public class ResourceClosedException extends HibernateException { + public ResourceClosedException(String s) { + super( s ); } - public String getUserTransactionName() { - return "java:comp/UserTransaction"; + public ResourceClosedException(String string, Throwable root) { + super( string, root ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/SessionFactory.java b/hibernate-core/src/main/java/org/hibernate/SessionFactory.java index af193fc35e..c097bfb29f 100644 --- a/hibernate-core/src/main/java/org/hibernate/SessionFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/SessionFactory.java @@ -119,8 +119,7 @@ public interface SessionFactory extends Referenceable, Serializable { * for use. *

* Note that for backwards compatibility, if a {@link org.hibernate.context.CurrentSessionContext} - * is not configured but a JTA {@link org.hibernate.transaction.TransactionManagerLookup} - * is configured this will default to the {@link org.hibernate.context.JTASessionContext} + * is not configured but JTA is configured this will default to the {@link org.hibernate.context.JTASessionContext} * impl. * * @return The current session. diff --git a/hibernate-core/src/main/java/org/hibernate/Transaction.java b/hibernate-core/src/main/java/org/hibernate/Transaction.java index 38635007c1..cbed4ea957 100644 --- a/hibernate-core/src/main/java/org/hibernate/Transaction.java +++ b/hibernate-core/src/main/java/org/hibernate/Transaction.java @@ -1,10 +1,10 @@ /* * Hibernate, Relational Persistence for Idiomatic Java * - * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as + * Copyright (c) 2007-2011, Red Hat Inc. or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are - * distributed under license by Red Hat Middleware LLC. + * distributed under license by Red Hat Inc. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU @@ -20,109 +20,140 @@ * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA - * */ package org.hibernate; +import org.hibernate.engine.transaction.spi.LocalStatus; + import javax.transaction.Synchronization; /** - * Allows the application to define units of work, while - * maintaining abstraction from the underlying transaction - * implementation (eg. JTA, JDBC).
- *
- * A transaction is associated with a Session and is - * usually instantiated by a call to Session.beginTransaction(). - * A single session might span multiple transactions since - * the notion of a session (a conversation between the application - * and the datastore) is of coarser granularity than the notion of - * a transaction. However, it is intended that there be at most one - * uncommitted Transaction associated with a particular - * Session at any time.
- *
- * Implementors are not intended to be threadsafe. + * Defines the contract for abstracting applications from the configured underlying means of transaction management. + * Allows the application to define units of work, while maintaining abstraction from the underlying transaction + * implementation (eg. JTA, JDBC). + *

+ * A transaction is associated with a {@link Session} and is usually initiated by a call to + * {@link org.hibernate.Session#beginTransaction()}. A single session might span multiple transactions since + * the notion of a session (a conversation between the application and the datastore) is of coarser granularity than + * the notion of a transaction. However, it is intended that there be at most one uncommitted transaction associated + * with a particular {@link Session} at any time. + *

+ * Implementers are not intended to be thread-safe. * - * @see Session#beginTransaction() - * @see org.hibernate.transaction.TransactionFactory * @author Anton van Straaten + * @author Steve Ebersole */ public interface Transaction { - /** - * Begin a new transaction. + * Is this transaction the initiator of any underlying transaction? + * + * @return {@literal true} if this transaction initiated the underlying transaction; {@literal false} otherwise. */ - public void begin() throws HibernateException; + public boolean isInitiator(); /** - * Flush the associated Session and end the unit of work (unless - * we are in {@link FlushMode#MANUAL}. - *

- * This method will commit the underlying transaction if and only - * if the underlying transaction was initiated by this object. + * Begin this transaction. No-op if the transaction has already been begun. Note that this is not necessarily + * symmetrical since usually multiple calls to {@link #commit} or {@link #rollback} will error. * - * @throws HibernateException + * @throws HibernateException Indicates a problem beginning the transaction. */ - public void commit() throws HibernateException; + public void begin(); /** - * Force the underlying transaction to roll back. + * Commit this transaction. This might entail a number of things depending on the context: * - * @throws HibernateException + * @throws HibernateException Indicates a problem committing the transaction. */ - public void rollback() throws HibernateException; + public void commit(); + + /** + * Rollback this transaction. Either rolls back the underlying transaction or ensures it cannot later commit + * (depending on the actual underlying strategy). + * + * @throws HibernateException Indicates a problem rolling back the transaction. + */ + public void rollback(); + + /** + * Get the current local status of this transaction. + *

+ * This only accounts for the local view of the transaction status. In other words it does not check the status + * of the actual underlying transaction. + * + * @return The current local status. + */ + public LocalStatus getLocalStatus(); + + /** + * Is this transaction still active? + *

+ * Answers on a best effort basis. For example, in the case of JDBC based transactions we cannot know that a + * transaction is active when it is initiated directly through the JDBC {@link java.sql.Connection}, only when + * it is initiated from here. + * + * @return {@literal true} if the transaction is still active; {@literal false} otherwise. + * + * @throws HibernateException Indicates a problem checking the transaction status. + */ + public boolean isActive(); + + /** + * Was this transaction committed? + *

+ * Answers on a best effort basis. For example, in the case of JDBC based transactions we cannot know that a + * transaction was committed when the commit was performed directly through the JDBC {@link java.sql.Connection}, + * only when the commit was done from this. + * + * @return {@literal true} if the transaction is rolled back; {@literal false} otherwise. + * + * @throws HibernateException Indicates a problem checking the transaction status. + */ + public boolean wasCommitted(); /** * Was this transaction rolled back or set to rollback only? *

- * This only accounts for actions initiated from this local transaction. - * If, for example, the underlying transaction is forced to rollback via - * some other means, this method still reports false because the rollback - * was not initiated from here. + * Answers on a best effort basis. For example, in the case of JDBC based transactions we cannot know that a + * transaction was rolled back when rollback was performed directly through the JDBC {@link java.sql.Connection}, + * only when it was rolled back from here. * - * @return boolean True if the transaction was rolled back via this - * local transaction; false otherwise. - * @throws HibernateException - */ - public boolean wasRolledBack() throws HibernateException; - - /** - * Check if this transaction was successfully committed. - *

- * This method could return false even after successful invocation - * of {@link #commit}. As an example, JTA based strategies no-op on - * {@link #commit} calls if they did not start the transaction; in that case, - * they also report {@link #wasCommitted} as false. + * @return {@literal true} if the transaction is rolled back; {@literal false} otherwise. * - * @return boolean True if the transaction was (unequivocally) committed - * via this local transaction; false otherwise. - * @throws HibernateException + * @throws HibernateException Indicates a problem checking the transaction status. */ - public boolean wasCommitted() throws HibernateException; - - /** - * Is this transaction still active? - *

- * Again, this only returns information in relation to the - * local transaction, not the actual underlying transaction. - * - * @return boolean Treu if this local transaction is still active. - */ - public boolean isActive() throws HibernateException; + public boolean wasRolledBack(); /** * Register a user synchronization callback for this transaction. * * @param synchronization The Synchronization callback to register. - * @throws HibernateException + * + * @throws HibernateException Indicates a problem registering the synchronization. */ - public void registerSynchronization(Synchronization synchronization) - throws HibernateException; + public void registerSynchronization(Synchronization synchronization) throws HibernateException; /** - * Set the transaction timeout for any transaction started by - * a subsequent call to begin() on this instance. + * Set the transaction timeout for any transaction started by a subsequent call to {@link #begin} on this instance. * * @param seconds The number of seconds before a timeout. */ public void setTimeout(int seconds); + + /** + * Retrieve the transaction timeout set for this transaction. A negative indicates no timeout has been set. + * + * @return The timeout, in seconds. + */ + public int getTimeout(); } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java b/hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java index 2e71eab331..ba64ce4900 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java @@ -1842,7 +1842,7 @@ public class Configuration implements Serializable { Properties copy = new Properties(); copy.putAll( properties ); ConfigurationHelper.resolvePlaceHolders( copy ); - Settings settings = buildSettings( copy, serviceRegistry.getService( JdbcServices.class ) ); + Settings settings = buildSettings( copy, serviceRegistry ); return new SessionFactoryImpl( this, @@ -2825,18 +2825,18 @@ public class Configuration implements Serializable { * * @return The build settings */ - public Settings buildSettings(JdbcServices jdbcServices) { + public Settings buildSettings(ServiceRegistry serviceRegistry) { Properties clone = ( Properties ) properties.clone(); ConfigurationHelper.resolvePlaceHolders( clone ); - return buildSettingsInternal( clone, jdbcServices ); + return buildSettingsInternal( clone, serviceRegistry ); } - public Settings buildSettings(Properties props, JdbcServices jdbcServices) throws HibernateException { - return buildSettingsInternal( props, jdbcServices ); + public Settings buildSettings(Properties props, ServiceRegistry serviceRegistry) throws HibernateException { + return buildSettingsInternal( props, serviceRegistry ); } - private Settings buildSettingsInternal(Properties props, JdbcServices jdbcServices) { - final Settings settings = settingsFactory.buildSettings( props, jdbcServices ); + private Settings buildSettingsInternal(Properties props, ServiceRegistry serviceRegistry) { + final Settings settings = settingsFactory.buildSettings( props, serviceRegistry ); settings.setEntityTuplizerFactory( this.getEntityTuplizerFactory() ); // settings.setComponentTuplizerFactory( this.getComponentTuplizerFactory() ); return settings; diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/Environment.java b/hibernate-core/src/main/java/org/hibernate/cfg/Environment.java index e2e670501c..51a7628170 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/Environment.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/Environment.java @@ -164,7 +164,7 @@ import org.hibernate.util.ConfigHelper; * * hibernate.transaction.factory_class * the factory to use for instantiating Transactions. - * (Defaults to JDBCTransactionFactory.) + * (Defaults to JdbcTransactionFactory.) * * * hibernate.query.substitutionsquery language token substitutions @@ -376,7 +376,8 @@ public final class Environment { */ public static final String CURRENT_SESSION_CONTEXT_CLASS = "hibernate.current_session_context_class"; /** - * TransactionFactory implementor to use for creating Transactions + * Names the implementation of {@link org.hibernate.engine.transaction.spi.TransactionContext} to use for + * creating {@link org.hibernate.Transaction} instances */ public static final String TRANSACTION_STRATEGY = "hibernate.transaction.factory_class"; /** diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/Settings.java b/hibernate-core/src/main/java/org/hibernate/cfg/Settings.java index 5e8056a6b5..fbc5e31eac 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/Settings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/Settings.java @@ -23,20 +23,18 @@ */ package org.hibernate.cfg; -import java.util.Map; - import org.hibernate.ConnectionReleaseMode; import org.hibernate.EntityMode; import org.hibernate.cache.QueryCacheFactory; import org.hibernate.cache.RegionFactory; import org.hibernate.engine.jdbc.JdbcSupport; -import org.hibernate.engine.jdbc.batch.internal.BatchBuilder; import org.hibernate.hql.QueryTranslatorFactory; import org.hibernate.jdbc.util.SQLStatementLogger; -import org.hibernate.transaction.TransactionFactory; -import org.hibernate.transaction.TransactionManagerLookup; +import org.hibernate.service.jta.platform.spi.JtaPlatform; import org.hibernate.tuple.entity.EntityTuplizerFactory; +import java.util.Map; + /** * Settings that affect the behaviour of Hibernate at runtime. * @@ -75,9 +73,6 @@ public final class Settings { private ConnectionReleaseMode connectionReleaseMode; private RegionFactory regionFactory; private QueryCacheFactory queryCacheFactory; - private TransactionFactory transactionFactory; - private TransactionManagerLookup transactionManagerLookup; - private BatchBuilder batchBuilder; private QueryTranslatorFactory queryTranslatorFactory; private boolean wrapResultSetsEnabled; private boolean orderUpdatesEnabled; @@ -94,6 +89,8 @@ public final class Settings { private JdbcSupport jdbcSupport; private String importFiles; + private JtaPlatform jtaPlatform; + /** * Package protected constructor */ @@ -162,10 +159,6 @@ public final class Settings { return jdbcFetchSize; } - public TransactionFactory getTransactionFactory() { - return transactionFactory; - } - public String getSessionFactoryName() { return sessionFactoryName; } @@ -190,10 +183,6 @@ public final class Settings { return regionFactory; } - public TransactionManagerLookup getTransactionManagerLookup() { - return transactionManagerLookup; - } - public boolean isQueryCacheEnabled() { return queryCacheEnabled; } @@ -226,10 +215,6 @@ public final class Settings { return flushBeforeCompletionEnabled; } - public BatchBuilder getBatchBuilder() { - return batchBuilder; - } - public boolean isAutoCloseSessionEnabled() { return autoCloseSessionEnabled; } @@ -349,10 +334,6 @@ public final class Settings { jdbcFetchSize = integer; } - void setTransactionFactory(TransactionFactory factory) { - transactionFactory = factory; - } - void setSessionFactoryName(String string) { sessionFactoryName = string; } @@ -377,10 +358,6 @@ public final class Settings { this.regionFactory = regionFactory; } - void setTransactionManagerLookup(TransactionManagerLookup lookup) { - transactionManagerLookup = lookup; - } - void setQueryCacheEnabled(boolean b) { queryCacheEnabled = b; } @@ -413,10 +390,6 @@ public final class Settings { this.flushBeforeCompletionEnabled = flushBeforeCompletionEnabled; } - void setBatcherBuilder(BatchBuilder batchBuilder) { - this.batchBuilder = batchBuilder; - } - void setAutoCloseSessionEnabled(boolean autoCloseSessionEnabled) { this.autoCloseSessionEnabled = autoCloseSessionEnabled; } @@ -496,4 +469,13 @@ public final class Settings { // void setBytecodeProvider(BytecodeProvider bytecodeProvider) { // this.bytecodeProvider = bytecodeProvider; // } + + + public JtaPlatform getJtaPlatform() { + return jtaPlatform; + } + + void setJtaPlatform(JtaPlatform jtaPlatform) { + this.jtaPlatform = jtaPlatform; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/SettingsFactory.java b/hibernate-core/src/main/java/org/hibernate/cfg/SettingsFactory.java index ca2a34f396..73801f2b98 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/SettingsFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/SettingsFactory.java @@ -39,16 +39,14 @@ import org.hibernate.cache.QueryCacheFactory; import org.hibernate.cache.RegionFactory; import org.hibernate.cache.impl.NoCachingRegionFactory; import org.hibernate.cache.impl.bridge.RegionFactoryCacheProviderBridge; -import org.hibernate.engine.jdbc.batch.internal.BatchBuilder; import org.hibernate.engine.jdbc.spi.ExtractedDatabaseMetaData; import org.hibernate.engine.jdbc.spi.JdbcServices; +import org.hibernate.engine.transaction.spi.TransactionFactory; import org.hibernate.hql.QueryTranslatorFactory; import org.hibernate.internal.util.config.ConfigurationHelper; import org.hibernate.jdbc.util.SQLStatementLogger; -import org.hibernate.transaction.TransactionFactory; -import org.hibernate.transaction.TransactionFactoryFactory; -import org.hibernate.transaction.TransactionManagerLookup; -import org.hibernate.transaction.TransactionManagerLookupFactory; +import org.hibernate.service.jta.platform.spi.JtaPlatform; +import org.hibernate.service.spi.ServiceRegistry; import org.hibernate.util.ReflectHelper; import org.hibernate.util.StringHelper; @@ -66,7 +64,8 @@ public class SettingsFactory implements Serializable { protected SettingsFactory() { } - public Settings buildSettings(Properties props, JdbcServices jdbcServices) { + public Settings buildSettings(Properties props, ServiceRegistry serviceRegistry) { + final JdbcServices jdbcServices = serviceRegistry.getService( JdbcServices.class ); Settings settings = new Settings(); //SessionFactory name: @@ -90,10 +89,7 @@ public class SettingsFactory implements Serializable { settings.setJdbcSupport( new JdbcSupport( ! ConfigurationHelper.getBoolean( Environment.NON_CONTEXTUAL_LOB_CREATION, properties ) ) ); // Transaction settings: - - TransactionFactory transactionFactory = createTransactionFactory(properties); - settings.setTransactionFactory(transactionFactory); - settings.setTransactionManagerLookup( createTransactionManagerLookup(properties) ); + settings.setJtaPlatform( serviceRegistry.getService( JtaPlatform.class ) ); boolean flushBeforeCompletion = ConfigurationHelper.getBoolean(Environment.FLUSH_BEFORE_COMPLETION, properties); log.info("Automatic flush during beforeCompletion(): " + enabledDisabled(flushBeforeCompletion) ); @@ -112,7 +108,6 @@ public class SettingsFactory implements Serializable { boolean jdbcBatchVersionedData = ConfigurationHelper.getBoolean(Environment.BATCH_VERSIONED_DATA, properties, false); if (batchSize>0) log.info("JDBC batch updates for versioned data: " + enabledDisabled(jdbcBatchVersionedData) ); settings.setJdbcBatchVersionedData(jdbcBatchVersionedData); - settings.setBatcherBuilder( createBatchBuilder(properties, batchSize) ); boolean useScrollableResultSets = ConfigurationHelper.getBoolean(Environment.USE_SCROLLABLE_RESULTSET, properties, meta.supportsScrollableResults()); log.info("Scrollable result sets: " + enabledDisabled(useScrollableResultSets) ); @@ -134,7 +129,7 @@ public class SettingsFactory implements Serializable { log.info( "Connection release mode: " + releaseModeName ); ConnectionReleaseMode releaseMode; if ( "auto".equals(releaseModeName) ) { - releaseMode = transactionFactory.getDefaultReleaseMode(); + releaseMode = serviceRegistry.getService( TransactionFactory.class ).getDefaultReleaseMode(); } else { releaseMode = ConnectionReleaseMode.parse( releaseModeName ); @@ -301,7 +296,9 @@ public class SettingsFactory implements Serializable { } public static RegionFactory createRegionFactory(Properties properties, boolean cachingEnabled) { - String regionFactoryClassName = ConfigurationHelper.getString( Environment.CACHE_REGION_FACTORY, properties, null ); + String regionFactoryClassName = ConfigurationHelper.getString( + Environment.CACHE_REGION_FACTORY, properties, null + ); if ( regionFactoryClassName == null && cachingEnabled ) { String providerClassName = ConfigurationHelper.getString( Environment.CACHE_PROVIDER, properties, null ); if ( providerClassName != null ) { @@ -346,33 +343,4 @@ public class SettingsFactory implements Serializable { } } - protected BatchBuilder createBatchBuilder(Properties properties, int batchSize) { - String batchBuilderClass = properties.getProperty(Environment.BATCH_STRATEGY); - BatchBuilder batchBuilder; - if (batchBuilderClass==null) { - batchBuilder = batchSize > 0 - ? new BatchBuilder( batchSize ) - : new BatchBuilder(); - } - else { - log.info("Batch factory: " + batchBuilderClass); - try { - batchBuilder = (BatchBuilder) ReflectHelper.classForName(batchBuilderClass).newInstance(); - } - catch (Exception cnfe) { - throw new HibernateException("could not instantiate BatchBuilder: " + batchBuilderClass, cnfe); - } - } - batchBuilder.setJdbcBatchSize( batchSize ); - return batchBuilder; - } - - protected TransactionFactory createTransactionFactory(Properties properties) { - return TransactionFactoryFactory.buildTransactionFactory(properties); - } - - protected TransactionManagerLookup createTransactionManagerLookup(Properties properties) { - return TransactionManagerLookupFactory.getTransactionManagerLookup(properties); - } - } diff --git a/hibernate-core/src/main/java/org/hibernate/context/JTASessionContext.java b/hibernate-core/src/main/java/org/hibernate/context/JTASessionContext.java index 7b7f7fc7e8..058882c5cc 100644 --- a/hibernate-core/src/main/java/org/hibernate/context/JTASessionContext.java +++ b/hibernate-core/src/main/java/org/hibernate/context/JTASessionContext.java @@ -28,7 +28,8 @@ import org.hibernate.HibernateException; import org.hibernate.ConnectionReleaseMode; import org.hibernate.classic.Session; import org.hibernate.engine.SessionFactoryImplementor; -import org.hibernate.util.JTAHelper; +import org.hibernate.engine.transaction.internal.jta.JtaStatusHelper; +import org.hibernate.service.jta.platform.spi.JtaPlatform; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -76,7 +77,8 @@ public class JTASessionContext implements CurrentSessionContext { * {@inheritDoc} */ public Session currentSession() throws HibernateException { - TransactionManager transactionManager = factory.getTransactionManager(); + final JtaPlatform jtaPlatform = factory.getServiceRegistry().getService( JtaPlatform.class ); + final TransactionManager transactionManager = jtaPlatform.retrieveTransactionManager(); if ( transactionManager == null ) { throw new HibernateException( "No TransactionManagerLookup specified" ); } @@ -87,9 +89,9 @@ public class JTASessionContext implements CurrentSessionContext { if ( txn == null ) { throw new HibernateException( "Unable to locate current JTA transaction" ); } - if ( !JTAHelper.isInProgress( txn.getStatus() ) ) { + if ( !JtaStatusHelper.isActive( txn.getStatus() ) ) { // We could register the session against the transaction even though it is - // not started, but we'd have no guarentee of ever getting the map + // not started, but we'd have no guarantee of ever getting the map // entries cleaned up (aside from spawning threads). throw new HibernateException( "Current transaction is not in progress" ); } @@ -101,9 +103,7 @@ public class JTASessionContext implements CurrentSessionContext { throw new HibernateException( "Problem locating/validating JTA transaction", t ); } - final Object txnIdentifier = factory.getSettings().getTransactionManagerLookup() == null - ? txn - : factory.getSettings().getTransactionManagerLookup().getTransactionIdentifier( txn ); + final Object txnIdentifier = jtaPlatform.getTransactionIdentifier( txn ); Session currentSession = ( Session ) currentSessionMap.get( txnIdentifier ); diff --git a/hibernate-core/src/main/java/org/hibernate/context/ThreadLocalSessionContext.java b/hibernate-core/src/main/java/org/hibernate/context/ThreadLocalSessionContext.java index a0613d8a6f..f3bbe79cd9 100644 --- a/hibernate-core/src/main/java/org/hibernate/context/ThreadLocalSessionContext.java +++ b/hibernate-core/src/main/java/org/hibernate/context/ThreadLocalSessionContext.java @@ -43,6 +43,10 @@ import org.hibernate.HibernateException; import org.hibernate.SessionFactory; import org.hibernate.classic.Session; import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.engine.SessionImplementor; +import org.hibernate.engine.jdbc.LobCreationContext; +import org.hibernate.engine.transaction.spi.TransactionContext; +import org.hibernate.event.EventSource; /** * A {@link CurrentSessionContext} impl which scopes the notion of current @@ -74,11 +78,11 @@ public class ThreadLocalSessionContext implements CurrentSessionContext { private static final Logger log = LoggerFactory.getLogger( ThreadLocalSessionContext.class ); private static final Class[] SESSION_PROXY_INTERFACES = new Class[] { - org.hibernate.classic.Session.class, - org.hibernate.engine.SessionImplementor.class, - org.hibernate.engine.jdbc.spi.JDBCContext.Context.class, - org.hibernate.event.EventSource.class, - org.hibernate.engine.jdbc.LobCreationContext.class + Session.class, + SessionImplementor.class, + EventSource.class, + TransactionContext.class, + LobCreationContext.class }; /** diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/lock/PessimisticReadSelectLockingStrategy.java b/hibernate-core/src/main/java/org/hibernate/dialect/lock/PessimisticReadSelectLockingStrategy.java index 12e7b4c575..d8db93be62 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/lock/PessimisticReadSelectLockingStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/lock/PessimisticReadSelectLockingStrategy.java @@ -78,7 +78,7 @@ public class PessimisticReadSelectLockingStrategy extends AbstractSelectLockingS final String sql = determineSql( timeout ); SessionFactoryImplementor factory = session.getFactory(); try { - PreparedStatement st = session.getJDBCContext().getConnectionManager().prepareSelectStatement( sql ); + PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql ); try { getLockable().getIdentifierType().nullSafeSet( st, id, 1, session ); if ( getLockable().isVersioned() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/lock/PessimisticReadUpdateLockingStrategy.java b/hibernate-core/src/main/java/org/hibernate/dialect/lock/PessimisticReadUpdateLockingStrategy.java index 9d473ca9b9..19976b0898 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/lock/PessimisticReadUpdateLockingStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/lock/PessimisticReadUpdateLockingStrategy.java @@ -94,7 +94,7 @@ public class PessimisticReadUpdateLockingStrategy implements LockingStrategy { } SessionFactoryImplementor factory = session.getFactory(); try { - PreparedStatement st = session.getJDBCContext().getConnectionManager().prepareSelectStatement( sql ); + PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql ); try { lockable.getVersionType().nullSafeSet( st, version, 1, session ); int offset = 2; diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/lock/PessimisticWriteSelectLockingStrategy.java b/hibernate-core/src/main/java/org/hibernate/dialect/lock/PessimisticWriteSelectLockingStrategy.java index d7cd8e96c2..a280a88526 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/lock/PessimisticWriteSelectLockingStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/lock/PessimisticWriteSelectLockingStrategy.java @@ -78,7 +78,7 @@ public class PessimisticWriteSelectLockingStrategy extends AbstractSelectLocking final String sql = determineSql( timeout ); SessionFactoryImplementor factory = session.getFactory(); try { - PreparedStatement st = session.getJDBCContext().getConnectionManager().prepareSelectStatement( sql ); + PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql ); try { getLockable().getIdentifierType().nullSafeSet( st, id, 1, session ); if ( getLockable().isVersioned() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/lock/PessimisticWriteUpdateLockingStrategy.java b/hibernate-core/src/main/java/org/hibernate/dialect/lock/PessimisticWriteUpdateLockingStrategy.java index 47d9af492c..d59c619e24 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/lock/PessimisticWriteUpdateLockingStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/lock/PessimisticWriteUpdateLockingStrategy.java @@ -94,7 +94,7 @@ public class PessimisticWriteUpdateLockingStrategy implements LockingStrategy { } SessionFactoryImplementor factory = session.getFactory(); try { - PreparedStatement st = session.getJDBCContext().getConnectionManager().prepareSelectStatement( sql ); + PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql ); try { lockable.getVersionType().nullSafeSet( st, version, 1, session ); int offset = 2; diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/lock/SelectLockingStrategy.java b/hibernate-core/src/main/java/org/hibernate/dialect/lock/SelectLockingStrategy.java index 65e563f76b..dbca19411f 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/lock/SelectLockingStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/lock/SelectLockingStrategy.java @@ -73,7 +73,7 @@ public class SelectLockingStrategy extends AbstractSelectLockingStrategy { final String sql = determineSql( timeout ); SessionFactoryImplementor factory = session.getFactory(); try { - PreparedStatement st = session.getJDBCContext().getConnectionManager().prepareSelectStatement( sql ); + PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql ); try { getLockable().getIdentifierType().nullSafeSet( st, id, 1, session ); if ( getLockable().isVersioned() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/lock/UpdateLockingStrategy.java b/hibernate-core/src/main/java/org/hibernate/dialect/lock/UpdateLockingStrategy.java index a8c7e2b47d..d68b79b0a7 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/lock/UpdateLockingStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/lock/UpdateLockingStrategy.java @@ -92,7 +92,7 @@ public class UpdateLockingStrategy implements LockingStrategy { // todo : should we additionally check the current isolation mode explicitly? SessionFactoryImplementor factory = session.getFactory(); try { - PreparedStatement st = session.getJDBCContext().getConnectionManager().prepareSelectStatement( sql ); + PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql ); try { lockable.getVersionType().nullSafeSet( st, version, 1, session ); int offset = 2; diff --git a/hibernate-core/src/main/java/org/hibernate/engine/ActionQueue.java b/hibernate-core/src/main/java/org/hibernate/engine/ActionQueue.java index 56b5bcb939..92c8709fa5 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/ActionQueue.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/ActionQueue.java @@ -265,7 +265,7 @@ public class ActionQueue { execute( ( Executable ) list.get( i ) ); } list.clear(); - session.getJDBCContext().getConnectionManager().executeBatch(); + session.getTransactionCoordinator().getJdbcCoordinator().executeBatch(); } public void execute(Executable executable) { diff --git a/hibernate-core/src/main/java/org/hibernate/engine/SessionFactoryImplementor.java b/hibernate-core/src/main/java/org/hibernate/engine/SessionFactoryImplementor.java index 4a8eba6789..a72b2aee50 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/SessionFactoryImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/SessionFactoryImplementor.java @@ -52,6 +52,7 @@ import org.hibernate.dialect.Dialect; import org.hibernate.dialect.function.SQLFunctionRegistry; import org.hibernate.exception.SQLExceptionConverter; import org.hibernate.id.IdentifierGenerator; +import org.hibernate.service.spi.ServiceRegistry; import org.hibernate.stat.StatisticsImplementor; import org.hibernate.type.Type; import org.hibernate.type.TypeResolver; @@ -145,13 +146,6 @@ public interface SessionFactoryImplementor extends Mapping, SessionFactory { */ public String getImportedClassName(String name); - - /** - * Get the JTA transaction manager - */ - public TransactionManager getTransactionManager(); - - /** * Get the default query cache */ @@ -262,4 +256,5 @@ public interface SessionFactoryImplementor extends Mapping, SessionFactory { */ public FetchProfile getFetchProfile(String name); + public ServiceRegistry getServiceRegistry(); } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/SessionImplementor.java b/hibernate-core/src/main/java/org/hibernate/engine/SessionImplementor.java index ca3a585439..a566ce401c 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/SessionImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/SessionImplementor.java @@ -39,9 +39,9 @@ import org.hibernate.Query; import org.hibernate.ScrollMode; import org.hibernate.ScrollableResults; import org.hibernate.Transaction; -import org.hibernate.engine.jdbc.spi.JDBCContext; import org.hibernate.engine.query.sql.NativeSQLQuerySpecification; import org.hibernate.collection.PersistentCollection; +import org.hibernate.engine.transaction.spi.TransactionCoordinator; import org.hibernate.event.EventListeners; import org.hibernate.impl.CriteriaImpl; import org.hibernate.loader.custom.CustomQuery; @@ -157,20 +157,6 @@ public interface SessionImplementor extends Serializable { */ public Object getEntityUsingInterceptor(EntityKey key) throws HibernateException; - /** - * Notify the session that the transaction completed, so we no longer - * own the old locks. (Also we should release cache softlocks.) May - * be called multiple times during the transaction completion process. - * Also called after an autocommit, in which case the second argument - * is null. - */ - public void afterTransactionCompletion(boolean successful, Transaction tx); - - /** - * Notify the session that the transaction is about to complete - */ - public void beforeTransactionCompletion(Transaction tx); - /** * Return the identifier of the persistent object, or null if * not associated with the session @@ -340,11 +326,16 @@ public interface SessionImplementor extends Serializable { */ public void setFetchProfile(String name); - public JDBCContext getJDBCContext(); + /** + * Retrieve access to the session's transaction coordinator. + * + * @return The transaction coordinator. + */ + public TransactionCoordinator getTransactionCoordinator(); /** - * Determine whether the session is closed. Provided seperately from - * {@link #isOpen()} as this method does not attempt any JTA synch + * Determine whether the session is closed. Provided separately from + * {@link #isOpen()} as this method does not attempt any JTA synchronization * registration, where as {@link #isOpen()} does; which makes this one * nicer to use for most internal purposes. * diff --git a/hibernate-core/src/main/java/org/hibernate/engine/TransactionHelper.java b/hibernate-core/src/main/java/org/hibernate/engine/TransactionHelper.java index 0c7df45cdc..d820594a9a 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/TransactionHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/TransactionHelper.java @@ -1,10 +1,10 @@ /* * Hibernate, Relational Persistence for Idiomatic Java * - * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as + * Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are - * distributed under license by Red Hat Middleware LLC. + * distributed under license by Red Hat Inc. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU @@ -20,19 +20,16 @@ * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA - * */ package org.hibernate.engine; +import org.hibernate.HibernateException; +import org.hibernate.jdbc.Work; + import java.io.Serializable; import java.sql.Connection; import java.sql.SQLException; -import org.hibernate.HibernateException; -import org.hibernate.engine.transaction.IsolatedWork; -import org.hibernate.engine.transaction.Isolater; -import org.hibernate.exception.JDBCExceptionHelper; - /** * Allows work to be done outside the current transaction, by suspending it, * and performing work in a new transaction @@ -41,7 +38,7 @@ import org.hibernate.exception.JDBCExceptionHelper; */ public abstract class TransactionHelper { - // todo : remove this and just have subclasses use Isolater/IsolatedWork directly... + // todo : remove this and just have subclasses use IsolationDelegate directly... /** * The work to be done @@ -51,26 +48,27 @@ public abstract class TransactionHelper { /** * Suspend the current transaction and perform work in a new transaction */ - public Serializable doWorkInNewTransaction(final SessionImplementor session) - throws HibernateException { - class Work implements IsolatedWork { + public Serializable doWorkInNewTransaction(final SessionImplementor session) throws HibernateException { + class WorkToDo implements Work { Serializable generatedValue; - public void doWork(Connection connection) throws HibernateException { + + @Override + public void execute(Connection connection) throws SQLException { String sql = null; try { generatedValue = doWorkInCurrentTransaction( connection, sql ); } - catch( SQLException sqle ) { + catch( SQLException e ) { throw session.getFactory().getSQLExceptionHelper().convert( - sqle, + e, "could not get or update next value", sql - ); + ); } } } - Work work = new Work(); - Isolater.doIsolatedWork( work, session ); + WorkToDo work = new WorkToDo(); + session.getTransactionCoordinator().getTransaction().createIsolationDelegate().delegateWork( work, true ); return work.generatedValue; } } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/AbstractBatchImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/AbstractBatchImpl.java index 5d171f4a38..a0c4bd2b97 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/AbstractBatchImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/AbstractBatchImpl.java @@ -23,19 +23,20 @@ */ package org.hibernate.engine.jdbc.batch.internal; +import org.hibernate.engine.jdbc.batch.spi.Batch; +import org.hibernate.engine.jdbc.batch.spi.BatchKey; +import org.hibernate.engine.jdbc.batch.spi.BatchObserver; +import org.hibernate.engine.jdbc.spi.JdbcCoordinator; +import org.hibernate.engine.jdbc.spi.SQLExceptionHelper; +import org.hibernate.engine.jdbc.spi.SQLStatementLogger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.LinkedHashMap; import java.util.LinkedHashSet; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.hibernate.engine.jdbc.batch.spi.Batch; -import org.hibernate.engine.jdbc.batch.spi.BatchObserver; -import org.hibernate.engine.jdbc.spi.SQLExceptionHelper; -import org.hibernate.engine.jdbc.spi.SQLStatementLogger; - /** * Convenience base class for implementors of the Batch interface. * @@ -44,21 +45,20 @@ import org.hibernate.engine.jdbc.spi.SQLStatementLogger; public abstract class AbstractBatchImpl implements Batch { private static final Logger log = LoggerFactory.getLogger( AbstractBatchImpl.class ); - private final SQLStatementLogger statementLogger; - private final SQLExceptionHelper exceptionHelper; - private Object key; + private final BatchKey key; + private final JdbcCoordinator jdbcCoordinator; private LinkedHashMap statements = new LinkedHashMap(); private LinkedHashSet observers = new LinkedHashSet(); - protected AbstractBatchImpl(Object key, - SQLStatementLogger statementLogger, - SQLExceptionHelper exceptionHelper) { - if ( key == null || statementLogger == null || exceptionHelper == null ) { - throw new IllegalArgumentException( "key, statementLogger, and exceptionHelper must be non-null." ); + protected AbstractBatchImpl(BatchKey key, JdbcCoordinator jdbcCoordinator) { + if ( key == null ) { + throw new IllegalArgumentException( "batch key cannot be null" ); + } + if ( jdbcCoordinator == null ) { + throw new IllegalArgumentException( "JDBC coordinator cannot be null" ); } this.key = key; - this.statementLogger = statementLogger; - this.exceptionHelper = exceptionHelper; + this.jdbcCoordinator = jdbcCoordinator; } /** @@ -74,8 +74,12 @@ public abstract class AbstractBatchImpl implements Batch { * * @return The underlying SQLException helper. */ - protected SQLExceptionHelper getSqlExceptionHelper() { - return exceptionHelper; + protected SQLExceptionHelper sqlExceptionHelper() { + return jdbcCoordinator.getTransactionCoordinator() + .getTransactionContext() + .getTransactionEnvironment() + .getJdbcServices() + .getSqlExceptionHelper(); } /** @@ -83,8 +87,12 @@ public abstract class AbstractBatchImpl implements Batch { * * @return The underlying JDBC services. */ - protected SQLStatementLogger getSqlStatementLogger() { - return statementLogger; + protected SQLStatementLogger sqlStatementLogger() { + return jdbcCoordinator.getTransactionCoordinator() + .getTransactionContext() + .getTransactionEnvironment() + .getJdbcServices() + .getSqlStatementLogger(); } /** @@ -96,62 +104,49 @@ public abstract class AbstractBatchImpl implements Batch { return statements; } - /** - * {@inheritDoc} - */ - public final Object getKey() { + @Override + public final BatchKey getKey() { return key; } - /** - * {@inheritDoc} - */ + @Override public void addObserver(BatchObserver observer) { observers.add( observer ); } - /** - * {@inheritDoc} - */ - public final PreparedStatement getBatchStatement(Object key, String sql) { - checkConsistentBatchKey( key ); + @Override + public PreparedStatement getBatchStatement(String sql, boolean callable) { if ( sql == null ) { throw new IllegalArgumentException( "sql must be non-null." ); } PreparedStatement statement = statements.get( sql ); - if ( statement != null ) { - log.debug( "reusing prepared statement" ); - statementLogger.logStatement( sql ); - } + if ( statement == null ) { + statement = buildBatchStatement( sql, callable ); + statements.put( sql, statement ); + } + else { + log.debug( "reusing batch statement" ); + sqlStatementLogger().logStatement( sql ); + } return statement; } - /** - * {@inheritDoc} - */ - // TODO: should this be final??? + private PreparedStatement buildBatchStatement(String sql, boolean callable) { + try { + if ( callable ) { + return jdbcCoordinator.getLogicalConnection().getShareableConnectionProxy().prepareCall( sql ); + } + else { + return jdbcCoordinator.getLogicalConnection().getShareableConnectionProxy().prepareStatement( sql ); + } + } + catch ( SQLException sqle ) { + log.error( "sqlexception escaped proxy", sqle ); + throw sqlExceptionHelper().convert( sqle, "could not prepare batch statement", sql ); + } + } + @Override - public void addBatchStatement(Object key, String sql, PreparedStatement preparedStatement) { - checkConsistentBatchKey( key ); - if ( sql == null ) { - throw new IllegalArgumentException( "sql must be non-null." ); - } - if ( statements.put( sql, preparedStatement ) != null ) { - log.error( "PreparedStatement was already in the batch, [" + sql + "]." ); - } - } - - protected void checkConsistentBatchKey(Object key) { - if ( ! this.key.equals( key ) ) { - throw new IllegalStateException( - "specified key ["+ key + "] is different from internal batch key [" + this.key + "]." - ); - } - } - - /** - * {@inheritDoc} - */ public final void execute() { notifyObserversExplicitExecution(); if ( statements.isEmpty() ) { @@ -162,7 +157,7 @@ public abstract class AbstractBatchImpl implements Batch { doExecuteBatch(); } finally { - release(); + releaseStatements(); } } finally { @@ -176,14 +171,16 @@ public abstract class AbstractBatchImpl implements Batch { statement.close(); } catch ( SQLException e ) { - log.error( "unable to release batch statement..." ); - log.error( "sqlexception escaped proxy", e ); + log.error( "unable to release batch statement; sqlexception escaped proxy", e ); } } getStatements().clear(); } - private void notifyObserversExplicitExecution() { + /** + * Convenience method to notify registered observers of an explicit execution of this batch. + */ + protected final void notifyObserversExplicitExecution() { for ( BatchObserver observer : observers ) { observer.batchExplicitlyExecuted(); } @@ -192,12 +189,13 @@ public abstract class AbstractBatchImpl implements Batch { /** * Convenience method to notify registered observers of an implicit execution of this batch. */ - protected void notifyObserversImplicitExecution() { + protected final void notifyObserversImplicitExecution() { for ( BatchObserver observer : observers ) { observer.batchImplicitlyExecuted(); } } + @Override public void release() { if ( getStatements() != null && !getStatements().isEmpty() ) { log.info( "On release of batch it still contained JDBC statements" ); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BasicBatchKey.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BasicBatchKey.java new file mode 100644 index 0000000000..0cff7e330a --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BasicBatchKey.java @@ -0,0 +1,89 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program 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 distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.engine.jdbc.batch.internal; + +import org.hibernate.engine.jdbc.batch.spi.BatchKey; +import org.hibernate.jdbc.Expectation; + +/** + * @author Steve Ebersole + */ +public class BasicBatchKey implements BatchKey { + private final String comparison; + private final int statementCount; + private final Expectation expectation; + +// public BasicBatchKey(String comparison, int statementCount, Expectation expectation) { +// this.comparison = comparison; +// this.statementCount = statementCount; +// this.expectations = new Expectation[statementCount]; +// Arrays.fill( this.expectations, expectation ); +// } +// +// public BasicBatchKey(String comparison, Expectation... expectations) { +// this.comparison = comparison; +// this.statementCount = expectations.length; +// this.expectations = expectations; +// } + + public BasicBatchKey(String comparison, Expectation expectation) { + this.comparison = comparison; + this.statementCount = 1; + this.expectation = expectation; + } + + @Override + public Expectation getExpectation() { + return expectation; + } + + @Override + public int getBatchedStatementCount() { + return statementCount; + } + + @Override + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + + BasicBatchKey that = (BasicBatchKey) o; + + if ( !comparison.equals( that.comparison ) ) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + return comparison.hashCode(); + } + +} diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchBuilder.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchBuilderImpl.java similarity index 59% rename from hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchBuilder.java rename to hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchBuilderImpl.java index e01a7047b3..71157a798f 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchBuilderImpl.java @@ -23,28 +23,37 @@ */ package org.hibernate.engine.jdbc.batch.internal; +import org.hibernate.cfg.Environment; +import org.hibernate.engine.jdbc.batch.spi.Batch; +import org.hibernate.engine.jdbc.batch.spi.BatchBuilder; +import org.hibernate.engine.jdbc.batch.spi.BatchKey; +import org.hibernate.engine.jdbc.spi.JdbcCoordinator; +import org.hibernate.internal.util.config.ConfigurationHelper; +import org.hibernate.service.spi.Configurable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.hibernate.engine.jdbc.batch.spi.Batch; -import org.hibernate.engine.jdbc.spi.LogicalConnectionImplementor; -import org.hibernate.engine.jdbc.spi.SQLExceptionHelper; -import org.hibernate.engine.jdbc.spi.SQLStatementLogger; +import java.util.Map; /** * A builder for {@link Batch} instances. * * @author Steve Ebersole */ -public class BatchBuilder { - private static final Logger log = LoggerFactory.getLogger( BatchBuilder.class ); +public class BatchBuilderImpl implements BatchBuilder, Configurable { + private static final Logger log = LoggerFactory.getLogger( BatchBuilderImpl.class ); private int size; - public BatchBuilder() { + public BatchBuilderImpl() { } - public BatchBuilder(int size) { + @Override + public void configure(Map configurationValues) { + size = ConfigurationHelper.getInt( Environment.STATEMENT_BATCH_SIZE, configurationValues, size ); + } + + public BatchBuilderImpl(int size) { this.size = size; } @@ -52,13 +61,27 @@ public class BatchBuilder { this.size = size; } - public Batch buildBatch(Object key, - SQLStatementLogger statementLogger, - SQLExceptionHelper exceptionHelper) { + @Override + public Batch buildBatch(BatchKey key, JdbcCoordinator jdbcCoordinator) { log.trace( "building batch [size={}]", size ); return size > 1 - ? new BatchingBatch( key, statementLogger, exceptionHelper, size ) - : new NonBatchingBatch( key, statementLogger, exceptionHelper ); + ? new BatchingBatch( key, jdbcCoordinator, size ) + : new NonBatchingBatch( key, jdbcCoordinator ); + } + + @Override + public String getManagementDomain() { + return null; // use Hibernate default domain + } + + @Override + public String getManagementServiceType() { + return null; // use Hibernate default scheme + } + + @Override + public Object getManagementBean() { + return this; } } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchBuilderInitiator.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchBuilderInitiator.java new file mode 100644 index 0000000000..26b5c4f3bd --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchBuilderInitiator.java @@ -0,0 +1,69 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program 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 distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.engine.jdbc.batch.internal; + +import org.hibernate.cfg.Environment; +import org.hibernate.engine.jdbc.batch.spi.BatchBuilder; +import org.hibernate.internal.util.config.ConfigurationHelper; +import org.hibernate.service.classloading.spi.ClassLoaderService; +import org.hibernate.service.spi.ServiceException; +import org.hibernate.service.spi.ServiceInitiator; +import org.hibernate.service.spi.ServiceRegistry; + +import java.util.Map; + +/** + * @author Steve Ebersole + */ +public class BatchBuilderInitiator implements ServiceInitiator { + public static final BatchBuilderInitiator INSTANCE = new BatchBuilderInitiator(); + public static final String BUILDER = "hibernate.jdbc.batch.builder"; + + @Override + public Class getServiceInitiated() { + return BatchBuilder.class; + } + + @Override + public BatchBuilder initiateService(Map configurationValues, ServiceRegistry registry) { + final Object builder = configurationValues.get( BUILDER ); + if ( builder == null ) { + return new BatchBuilderImpl( + ConfigurationHelper.getInt( Environment.STATEMENT_BATCH_SIZE, configurationValues, 1 ) + ); + } + + if ( BatchBuilder.class.isInstance( builder ) ) { + return (BatchBuilder) builder; + } + + final String builderClassName = builder.toString(); + try { + return (BatchBuilder) registry.getService( ClassLoaderService.class ).classForName( builderClassName ).newInstance(); + } + catch (Exception e) { + throw new ServiceException( "Could not build explicit BatchBuilder [" + builderClassName + "]", e ); + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchingBatch.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchingBatch.java index 9dc1b27020..1b91a78b0a 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchingBatch.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchingBatch.java @@ -23,173 +23,116 @@ */ package org.hibernate.engine.jdbc.batch.internal; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - +import org.hibernate.HibernateException; +import org.hibernate.engine.jdbc.batch.spi.BatchKey; +import org.hibernate.engine.jdbc.spi.JdbcCoordinator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.hibernate.AssertionFailure; -import org.hibernate.HibernateException; -import org.hibernate.engine.jdbc.spi.SQLExceptionHelper; -import org.hibernate.engine.jdbc.spi.SQLStatementLogger; -import org.hibernate.jdbc.Expectation; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.Map; /** - * A {@link org.hibernate.engine.jdbc.batch.spi.Batch} implementation which does - * batching based on a given size. Once the batch size is reached for a statement - * in the batch, the entire batch is implicitly executed. + * A {@link org.hibernate.engine.jdbc.batch.spi.Batch} implementation which does bathing based on a given size. Once + * the batch size is reached for a statement in the batch, the entire batch is implicitly executed. * * @author Steve Ebersole */ public class BatchingBatch extends AbstractBatchImpl { private static final Logger log = LoggerFactory.getLogger( BatchingBatch.class ); + // IMPL NOTE : Until HHH-5797 is fixed, there will only be 1 statement in a batch + private final int batchSize; + private int batchPosition; + private int statementPosition; - // TODO: A Map is used for expectations so it is possible to track when a batch - // is full (i.e., when the batch for a particular statement exceeds batchSize) - // Until HHH-5797 is fixed, there will only be 1 statement in a batch, so it won't - // be necessary to track expectations by statement. - private Map> expectationsBySql; - private int maxBatchPosition; - - public BatchingBatch(Object key, - SQLStatementLogger statementLogger, - SQLExceptionHelper exceptionHelper, - int batchSize) { - super( key, statementLogger, exceptionHelper ); - this.batchSize = batchSize; - this.expectationsBySql = new HashMap>(); - } - - /** - * {@inheritDoc} - */ - public void addToBatch(Object key, String sql, Expectation expectation) { - checkConsistentBatchKey( key ); - if ( sql == null || expectation == null ) { - throw new AssertionFailure( "sql or expection was null." ); - } - if ( ! expectation.canBeBatched() ) { + public BatchingBatch( + BatchKey key, + JdbcCoordinator jdbcCoordinator, + int batchSize) { + super( key, jdbcCoordinator ); + if ( ! key.getExpectation().canBeBatched() ) { throw new HibernateException( "attempting to batch an operation which cannot be batched" ); } - final PreparedStatement statement = getStatements().get( sql ); + this.batchSize = batchSize; + } + + private String currentStatementSql; + private PreparedStatement currentStatement; + + @Override + public PreparedStatement getBatchStatement(String sql, boolean callable) { + currentStatementSql = sql; + currentStatement = super.getBatchStatement( sql, callable ); + return currentStatement; + } + + @Override + public void addToBatch() { try { - statement.addBatch(); + currentStatement.addBatch(); } catch ( SQLException e ) { - log.error( "sqlexception escaped proxy", e ); - throw getSqlExceptionHelper().convert( e, "could not perform addBatch", sql ); + log.debug( "sqlexception escaped proxy", e ); + throw sqlExceptionHelper().convert( e, "could not perform addBatch", currentStatementSql ); } - List expectations = expectationsBySql.get( sql ); - if ( expectations == null ) { - expectations = new ArrayList( batchSize ); - expectationsBySql.put( sql, expectations ); - } - expectations.add( expectation ); - maxBatchPosition = Math.max( maxBatchPosition, expectations.size() ); - - // TODO: When HHH-5797 is fixed the following if-block should probably be moved before - // adding the batch to the current statement (to detect that we have finished - // with the previous entity). - if ( maxBatchPosition == batchSize ) { - notifyObserversImplicitExecution(); - doExecuteBatch(); + statementPosition++; + if ( statementPosition >= getKey().getBatchedStatementCount() ) { + batchPosition++; + if ( batchPosition == batchSize ) { + notifyObserversImplicitExecution(); + performExecution(); + batchPosition = 0; + } + statementPosition = 0; } } - /** - * {@inheritDoc} - */ + @Override protected void doExecuteBatch() { - if ( maxBatchPosition == 0 ) { + if ( batchPosition == 0 ) { log.debug( "no batched statements to execute" ); } else { if ( log.isDebugEnabled() ) { - log.debug( "Executing {} statements with maximum batch size {} ", - getStatements().size(), maxBatchPosition - ); - } - try { - executeStatements(); - } - catch ( RuntimeException re ) { - log.error( "Exception executing batch [{}]", re.getMessage() ); - throw re; - } - finally { - for ( List expectations : expectationsBySql.values() ) { - expectations.clear(); - } - maxBatchPosition = 0; + log.debug( "Executing batch size: " + batchPosition ); } + performExecution(); } } - private void executeStatements() { - for ( Map.Entry entry : getStatements().entrySet() ) { - final String sql = entry.getKey(); - final PreparedStatement statement = entry.getValue(); - final List expectations = expectationsBySql.get( sql ); - if ( batchSize < expectations.size() ) { - throw new IllegalStateException( - "Number of expectations [" + expectations.size() + - "] is greater than batch size [" + batchSize + - "] for statement [" + sql + - "]" - ); - } - if ( expectations.size() > 0 ) { - if ( log.isDebugEnabled() ) { - log.debug( "Executing with batch of size {}: {}", expectations.size(), sql ); - } - executeStatement( sql, statement, expectations ); - expectations.clear(); - } - else { - if ( log.isDebugEnabled() ) { - log.debug( "Skipped executing because batch size is 0: ", sql ); - } - } - } - } - - private void executeStatement(String sql, PreparedStatement ps, List expectations) { + private void performExecution() { try { - checkRowCounts( sql, ps.executeBatch(), ps, expectations ); + for ( Map.Entry entry : getStatements().entrySet() ) { + try { + final PreparedStatement statement = entry.getValue(); + checkRowCounts( statement.executeBatch(), statement ); + } + catch ( SQLException e ) { + log.debug( "sqlexception escaped proxy", e ); + throw sqlExceptionHelper().convert( e, "could not perform addBatch", entry.getKey() ); + } + } } - catch ( SQLException e ) { - log.error( "sqlexception escaped proxy", e ); - throw getSqlExceptionHelper() - .convert( e, "could not execute statement: " + sql ); + catch ( RuntimeException re ) { + log.error( "Exception executing batch [{}]", re.getMessage() ); + throw re; + } + finally { + batchPosition = 0; } } - private void checkRowCounts(String sql, int[] rowCounts, PreparedStatement ps, List expectations) { + private void checkRowCounts(int[] rowCounts, PreparedStatement ps) throws SQLException, HibernateException { int numberOfRowCounts = rowCounts.length; - if ( numberOfRowCounts != expectations.size() ) { + if ( numberOfRowCounts != batchPosition ) { log.warn( "JDBC driver did not return the expected number of row counts" ); } - try { - for ( int i = 0; i < numberOfRowCounts; i++ ) { - expectations.get( i ).verifyOutcome( rowCounts[i], ps, i ); - } - } - catch ( SQLException e ) { - log.error( "sqlexception escaped proxy", e ); - throw getSqlExceptionHelper() - .convert( e, "row count verification failed for statement: ", sql ); + for ( int i = 0; i < numberOfRowCounts; i++ ) { + getKey().getExpectation().verifyOutcome( rowCounts[i], ps, i ); } } - public void release() { - expectationsBySql.clear(); - maxBatchPosition = 0; - } } \ No newline at end of file diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/NonBatchingBatch.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/NonBatchingBatch.java index 64eb6b116a..9b2e280096 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/NonBatchingBatch.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/NonBatchingBatch.java @@ -23,48 +23,52 @@ */ package org.hibernate.engine.jdbc.batch.internal; -import java.sql.PreparedStatement; -import java.sql.SQLException; - +import org.hibernate.engine.jdbc.batch.spi.BatchKey; +import org.hibernate.engine.jdbc.spi.JdbcCoordinator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.hibernate.engine.jdbc.spi.SQLExceptionHelper; -import org.hibernate.engine.jdbc.spi.SQLStatementLogger; -import org.hibernate.jdbc.Expectation; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.Map; /** - * An implementation of {@link org.hibernate.engine.jdbc.batch.spi.Batch} which does not perform batching. It simply executes each statement as it is - * encountered. + * An implementation of {@link org.hibernate.engine.jdbc.batch.spi.Batch} which does not perform batching. It simply + * executes each statement as it is encountered. * * @author Steve Ebersole */ public class NonBatchingBatch extends AbstractBatchImpl { private static final Logger log = LoggerFactory.getLogger( NonBatchingBatch.class ); - protected NonBatchingBatch(Object key, - SQLStatementLogger statementLogger, - SQLExceptionHelper exceptionHelper) { - super( key, statementLogger, exceptionHelper ); + protected NonBatchingBatch(BatchKey key, JdbcCoordinator jdbcCoordinator) { + super( key, jdbcCoordinator ); } - public void addToBatch(Object key, String sql, Expectation expectation) { - checkConsistentBatchKey( key ); - if ( sql == null ) { - throw new IllegalArgumentException( "sql must be non-null." ); - } + @Override + public void addToBatch() { notifyObserversImplicitExecution(); - try { - final PreparedStatement statement = getStatements().get( sql ); - final int rowCount = statement.executeUpdate(); - expectation.verifyOutcome( rowCount, statement, 0 ); - } - catch ( SQLException e ) { - log.error( "sqlexception escaped proxy", e ); - throw getSqlExceptionHelper().convert( e, "could not execute batch statement", sql ); + for ( Map.Entry entry : getStatements().entrySet() ) { + try { + final PreparedStatement statement = entry.getValue(); + final int rowCount = statement.executeUpdate(); + getKey().getExpectation().verifyOutcome( rowCount, statement, 0 ); + try { + statement.close(); + } + catch (SQLException e) { + log.debug( "Unable to close non-batched batch statement", e ); + } + } + catch ( SQLException e ) { + log.debug( "sqlexception escaped proxy", e ); + throw sqlExceptionHelper().convert( e, "could not execute batch statement", entry.getKey() ); + } } + getStatements().clear(); } + @Override protected void doExecuteBatch() { // nothing to do } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/spi/Batch.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/spi/Batch.java index 7c99332100..3a3ee658bb 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/spi/Batch.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/spi/Batch.java @@ -42,7 +42,7 @@ public interface Batch { * * @return The batch key. */ - public Object getKey(); + public BatchKey getKey(); /** * Adds an observer to this batch. @@ -52,30 +52,19 @@ public interface Batch { public void addObserver(BatchObserver observer); /** - * Get a statement which is part of the batch. + * Get a statement which is part of the batch, creating if necessary (and storing for next time). * * @param sql The SQL statement. - * @return the prepared statement representing the SQL statement, if the batch contained it; - * null, otherwise. - */ - public PreparedStatement getBatchStatement(Object key, String sql); - - /** - * Add a prepared statement to the batch. + * @param callable Is the SQL statement callable? * - * @param sql The SQL statement. + * @return The prepared statement instance, representing the SQL statement. */ - public void addBatchStatement(Object key, String sql, PreparedStatement preparedStatement); - + public PreparedStatement getBatchStatement(String sql, boolean callable); /** * Indicates completion of the current part of the batch. - * - * @param key - * @param sql - * @param expectation The expectation for the part's result. */ - public void addToBatch(Object key, String sql, Expectation expectation); + public void addToBatch(); /** * Execute this batch. diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/spi/BatchBuilder.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/spi/BatchBuilder.java new file mode 100644 index 0000000000..4715c13faa --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/spi/BatchBuilder.java @@ -0,0 +1,45 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program 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 distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.engine.jdbc.batch.spi; + +import org.hibernate.engine.jdbc.spi.JdbcCoordinator; +import org.hibernate.service.spi.Manageable; +import org.hibernate.service.spi.Service; + +/** + * A builder for {@link Batch} instances + * + * @author Steve Ebersole + */ +public interface BatchBuilder extends Service, Manageable { + /** + * Build a batch. + * + * @param key Value to uniquely identify a batch + * @param jdbcCoordinator The JDBC coordinator with which to coordinate efforts + * + * @return The built batch + */ + public Batch buildBatch(BatchKey key, JdbcCoordinator jdbcCoordinator); +} diff --git a/hibernate-core/src/main/java/org/hibernate/transaction/ResinTransactionManagerLookup.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/spi/BatchKey.java similarity index 59% rename from hibernate-core/src/main/java/org/hibernate/transaction/ResinTransactionManagerLookup.java rename to hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/spi/BatchKey.java index c1c157c761..86e8338cc0 100644 --- a/hibernate-core/src/main/java/org/hibernate/transaction/ResinTransactionManagerLookup.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/spi/BatchKey.java @@ -1,10 +1,10 @@ /* * Hibernate, Relational Persistence for Idiomatic Java * - * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as + * Copyright (c) 2011, Red Hat Inc. or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are - * distributed under license by Red Hat Middleware LLC. + * distributed under license by Red Hat Inc. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU @@ -20,29 +20,30 @@ * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA - * */ -package org.hibernate.transaction; +package org.hibernate.engine.jdbc.batch.spi; + +import org.hibernate.jdbc.Expectation; /** - * {@link TransactionManagerLookup} strategy for Resin + * Unique key for batch identification. * - * @author Aapo Laakkonen + * @author Steve Ebersole */ -public class ResinTransactionManagerLookup extends JNDITransactionManagerLookup { +public interface BatchKey { + /** + * How many statements will be in this batch? + *

+ * Note that this is distinctly different than the size of the batch. + * + * @return The number of statements. + */ + public int getBatchedStatementCount(); /** - * {@inheritDoc} + * Get the expectation pertaining to the outcome of the {@link Batch} associated with this key. + * + * @return The expectations */ - protected String getName() { - return "java:comp/TransactionManager"; - } - - /** - * {@inheritDoc} - */ - public String getUserTransactionName() { - return "java:comp/UserTransaction"; - } - + public Expectation getExpectation(); } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/ConnectionManagerImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/ConnectionManagerImpl.java deleted file mode 100644 index dddaa20eca..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/ConnectionManagerImpl.java +++ /dev/null @@ -1,611 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as - * indicated by the @author tags or express copyright attribution - * statements applied by the authors. All third-party contributions are - * distributed under license by Red Hat Middleware LLC. - * - * This copyrighted material is made available to anyone wishing to use, modify, - * copy, or redistribute it subject to the terms and conditions of the GNU - * Lesser General Public License, as published by the Free Software Foundation. - * - * This program 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 distribution; if not, write to: - * Free Software Foundation, Inc. - * 51 Franklin Street, Fifth Floor - * Boston, MA 02110-1301 USA - * - */ -package org.hibernate.engine.jdbc.internal; - -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.sql.CallableStatement; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.SQLException; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.hibernate.AssertionFailure; -import org.hibernate.ConnectionReleaseMode; -import org.hibernate.HibernateException; -import org.hibernate.Interceptor; -import org.hibernate.ScrollMode; -import org.hibernate.engine.SessionFactoryImplementor; -import org.hibernate.engine.jdbc.batch.internal.BatchBuilder; -import org.hibernate.engine.jdbc.batch.spi.Batch; -import org.hibernate.engine.jdbc.spi.ConnectionManager; -import org.hibernate.engine.jdbc.spi.ConnectionObserver; -import org.hibernate.jdbc.Expectation; - -/** - * Encapsulates JDBC Connection management logic needed by Hibernate. - *

- * The lifecycle is intended to span a logical series of interactions with the - * database. Internally, this means the the lifecycle of the Session. - * - * @author Steve Ebersole - */ -public class ConnectionManagerImpl implements ConnectionManager { - - private static final Logger log = LoggerFactory.getLogger( ConnectionManagerImpl.class ); - - public static interface Callback extends ConnectionObserver { - public boolean isTransactionInProgress(); - } - - // TODO: check if it's ok to change the method names in Callback - - private transient Interceptor interceptor; - - private final Callback callback; - private transient LogicalConnectionImpl logicalConnection; - private transient StatementPreparer statementPreparer; - private final transient BatchBuilder batchBuilder; - private Batch batch; - - /** - * Constructs a ConnectionManager. - *

- * This is the form used internally. - * - * @param callback An observer for internal state change. - * @param releaseMode The mode by which to release JDBC connections. - * @param suppliedConnection An externally supplied connection. - */ - public ConnectionManagerImpl( - SessionFactoryImplementor factory, - Callback callback, - ConnectionReleaseMode releaseMode, - Connection suppliedConnection, - Interceptor interceptor) { - this( factory, - callback, - interceptor, - new LogicalConnectionImpl( - suppliedConnection, - releaseMode, - factory.getJdbcServices(), - factory.getStatistics() != null ? factory.getStatisticsImplementor() : null - ) - ); - } - - /** - * Private constructor used exclusively from custom serialization - */ - private ConnectionManagerImpl( - SessionFactoryImplementor factory, - Callback callback, - Interceptor interceptor, - LogicalConnectionImpl logicalConnection - ) { - this.callback = callback; - this.interceptor = interceptor; - this.logicalConnection = logicalConnection; - this.logicalConnection.addObserver( callback ); - this.statementPreparer = new StatementPreparer( logicalConnection, factory.getSettings() ); - this.batchBuilder = factory.getSettings().getBatchBuilder(); - } - - /** - * Retrieves the connection currently managed by this ConnectionManager. - *

- * Note, that we may need to obtain a connection to return here if a - * connection has either not yet been obtained (non-UserSuppliedConnectionProvider) - * or has previously been aggressively released (if supported in this environment). - * - * @return The current Connection. - * - * @throws HibernateException Indicates a connection is currently not - * available (we are currently manually disconnected). - */ - @Override - public Connection getConnection() throws HibernateException { - return logicalConnection.getConnection(); - } - - @Override - public boolean hasBorrowedConnection() { - // used from testsuite - return logicalConnection.hasBorrowedConnection(); - } - - public Connection borrowConnection() { - return logicalConnection.borrowConnection(); - } - - @Override - public void releaseBorrowedConnection() { - logicalConnection.releaseBorrowedConnection(); - } - - /** - * Is the connection considered "auto-commit"? - * - * @return True if we either do not have a connection, or the connection - * really is in auto-commit mode. - * - * @throws SQLException Can be thrown by the Connection.isAutoCommit() check. - */ - public boolean isAutoCommit() throws SQLException { - return logicalConnection == null || - ! logicalConnection.isOpen() || - ! logicalConnection.isPhysicallyConnected() || - logicalConnection.getConnection().getAutoCommit(); - } - - /** - * Will connections be released after each statement execution? - *

- * Connections will be released after each statement if either: