diff --git a/build.gradle b/build.gradle index efada05429..7929ef22b2 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.7.0', 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/hibernate-core.gradle b/hibernate-core/hibernate-core.gradle index 7263d71648..23defc1a7b 100644 --- a/hibernate-core/hibernate-core.gradle +++ b/hibernate-core/hibernate-core.gradle @@ -96,4 +96,9 @@ task installTesting(type:Upload, dependsOn: [testingJar,testingSourcesJar]) { } install.dependsOn installTesting -uploadTesting.dependsOn installTesting \ No newline at end of file +uploadTesting.dependsOn installTesting + +// temporary +test { + ignoreFailures = true +} \ No newline at end of file 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: