From b3aa9e0c283842aa206c1fbea51f212c9abe64c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Galder=20Zamarre=C3=B1o?= Date: Wed, 15 Dec 2010 17:37:34 +0100 Subject: [PATCH 01/21] HHH-5793 - Query and timestamp caches to use cluster cache loader * Query and timestamp caches now use cluster cache loader instead of state transfer in order to remain asynchronous. * To maintain previous semantics, after query or timestamp regions have been completely evicted, a check has been added to avoid going remote if the region was invalid. --- .../hibernate-infinispan.gradle | 2 +- .../cache/infinispan/impl/BaseRegion.java | 24 ++++++++++++------- .../query/QueryResultsRegionImpl.java | 13 ++++++++-- .../timestamp/TimestampsRegionImpl.java | 14 ++++++++++- .../cache/infinispan/util/FlagAdapter.java | 5 +++- .../infinispan/builder/infinispan-configs.xml | 22 +++++++++++++++-- 6 files changed, 65 insertions(+), 15 deletions(-) diff --git a/hibernate-infinispan/hibernate-infinispan.gradle b/hibernate-infinispan/hibernate-infinispan.gradle index eea750b080..92eae99b12 100644 --- a/hibernate-infinispan/hibernate-infinispan.gradle +++ b/hibernate-infinispan/hibernate-infinispan.gradle @@ -1,5 +1,5 @@ dependencies { - infinispanVersion = '4.2.0.ALPHA3' + infinispanVersion = '4.2.0.CR4' jnpVersion = '5.0.3.GA' compile(project(':hibernate-core')) diff --git a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/impl/BaseRegion.java b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/impl/BaseRegion.java index da52527ffe..535d94bb15 100644 --- a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/impl/BaseRegion.java +++ b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/impl/BaseRegion.java @@ -169,7 +169,7 @@ public abstract class BaseRegion implements Region { } public boolean checkValid() { - boolean valid = invalidateState.get() == InvalidateState.VALID; + boolean valid = isValid(); if (!valid) { synchronized (invalidationMutex) { if (invalidateState.compareAndSet(InvalidateState.INVALID, InvalidateState.CLEARING)) { @@ -188,26 +188,34 @@ public abstract class BaseRegion implements Region { } } } - valid = invalidateState.get() == InvalidateState.VALID; + valid = isValid(); } return valid; } + protected boolean isValid() { + return invalidateState.get() == InvalidateState.VALID; + } + /** * Performs a Infinispan get(Fqn, Object) * * @param key The key of the item to get - * @param opt any option to add to the get invocation. May be null * @param suppressTimeout should any TimeoutException be suppressed? + * @param flagAdapters flags to add to the get invocation * @return The retrieved object - * @throws CacheException issue managing transaction or talking to cache + * @throws CacheException issue managing transaction or talking to cache */ - protected Object get(Object key, FlagAdapter opt, boolean suppressTimeout) throws CacheException { + protected Object get(Object key, boolean suppressTimeout, FlagAdapter... flagAdapters) throws CacheException { + CacheAdapter localCacheAdapter = cacheAdapter; + if (flagAdapters != null && flagAdapters.length > 0) + localCacheAdapter = cacheAdapter.withFlags(flagAdapters); + if (suppressTimeout) - return cacheAdapter.getAllowingTimeout(key); + return localCacheAdapter.getAllowingTimeout(key); else - return cacheAdapter.get(key); + return localCacheAdapter.get(key); } public Object getOwnerForPut() { @@ -295,4 +303,4 @@ public abstract class BaseRegion implements Region { } } -} \ No newline at end of file +} diff --git a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/query/QueryResultsRegionImpl.java b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/query/QueryResultsRegionImpl.java index 6e2b6f77cd..0f470c0d49 100644 --- a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/query/QueryResultsRegionImpl.java +++ b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/query/QueryResultsRegionImpl.java @@ -47,6 +47,13 @@ public class QueryResultsRegionImpl extends BaseTransactionalDataRegion implemen } public Object get(Object key) throws CacheException { + // If the region is not valid, skip cache store to avoid going remote to retrieve the query. + // The aim of this is to maintain same logic/semantics as when state transfer was configured. + // TODO: Once https://issues.jboss.org/browse/ISPN-835 has been resolved, revert to state transfer and remove workaround + boolean skipCacheStore = false; + if (!isValid()) + skipCacheStore = true; + if (!checkValid()) return null; @@ -55,7 +62,10 @@ public class QueryResultsRegionImpl extends BaseTransactionalDataRegion implemen // to avoid holding locks that would prevent updates. // Add a zero (or low) timeout option so we don't block // waiting for tx's that did a put to commit - return get(key, FlagAdapter.ZERO_LOCK_ACQUISITION_TIMEOUT, true); + if (skipCacheStore) + return get(key, true, FlagAdapter.ZERO_LOCK_ACQUISITION_TIMEOUT, FlagAdapter.SKIP_CACHE_STORE); + else + return get(key, true, FlagAdapter.ZERO_LOCK_ACQUISITION_TIMEOUT); } public void put(Object key, Object value) throws CacheException { @@ -83,5 +93,4 @@ public class QueryResultsRegionImpl extends BaseTransactionalDataRegion implemen .putAllowingTimeout(key, value); } } - } \ No newline at end of file diff --git a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/timestamp/TimestampsRegionImpl.java b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/timestamp/TimestampsRegionImpl.java index e7de3ded8d..758e62abda 100644 --- a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/timestamp/TimestampsRegionImpl.java +++ b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/timestamp/TimestampsRegionImpl.java @@ -57,8 +57,20 @@ public class TimestampsRegionImpl extends BaseGeneralDataRegion implements Times public Object get(Object key) throws CacheException { Object value = localCache.get(key); + + // If the region is not valid, skip cache store to avoid going remote to retrieve the query. + // The aim of this is to maintain same logic/semantics as when state transfer was configured. + // TODO: Once https://issues.jboss.org/browse/ISPN-835 has been resolved, revert to state transfer and remove workaround + boolean skipCacheStore = false; + if (!isValid()) + skipCacheStore = true; + if (value == null && checkValid()) { - value = get(key, null, false); + if (skipCacheStore) + value = get(key, false, FlagAdapter.SKIP_CACHE_STORE); + else + value = get(key, false); + if (value != null) localCache.put(key, value); } diff --git a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/util/FlagAdapter.java b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/util/FlagAdapter.java index 9e3318fcc0..f4f7a3a308 100644 --- a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/util/FlagAdapter.java +++ b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/util/FlagAdapter.java @@ -35,7 +35,8 @@ public enum FlagAdapter { ZERO_LOCK_ACQUISITION_TIMEOUT, CACHE_MODE_LOCAL, FORCE_ASYNCHRONOUS, - FORCE_SYNCHRONOUS; + FORCE_SYNCHRONOUS, + SKIP_CACHE_STORE; Flag toFlag() { switch(this) { @@ -47,6 +48,8 @@ public enum FlagAdapter { return Flag.FORCE_ASYNCHRONOUS; case FORCE_SYNCHRONOUS: return Flag.FORCE_SYNCHRONOUS; + case SKIP_CACHE_STORE: + return Flag.SKIP_CACHE_STORE; default: throw new CacheException("Unmatched Infinispan flag " + this); } diff --git a/hibernate-infinispan/src/main/resources/org/hibernate/cache/infinispan/builder/infinispan-configs.xml b/hibernate-infinispan/src/main/resources/org/hibernate/cache/infinispan/builder/infinispan-configs.xml index 99265a7b7d..b66c7cc87d 100644 --- a/hibernate-infinispan/src/main/resources/org/hibernate/cache/infinispan/builder/infinispan-configs.xml +++ b/hibernate-infinispan/src/main/resources/org/hibernate/cache/infinispan/builder/infinispan-configs.xml @@ -82,7 +82,6 @@ - + + + + + + + + - + + + + + + + + \ No newline at end of file From 7262276fa911285b8b3094c57af13322ee9d18dc Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Tue, 14 Dec 2010 15:09:05 -0800 Subject: [PATCH 02/21] HHH-5778 : Wire in new batch code --- .../main/java/org/hibernate/cfg/Settings.java | 10 - .../org/hibernate/cfg/SettingsFactory.java | 38 +-- .../batch/internal/AbstractBatchImpl.java | 86 +++-- .../jdbc/batch/internal/BatchBuilder.java | 12 +- .../jdbc/batch/internal/BatchingBatch.java | 141 +++++--- .../jdbc/batch/internal/NonBatchingBatch.java | 34 +- .../engine/jdbc/batch/spi/Batch.java | 15 +- .../jdbc/internal/ConnectionManagerImpl.java | 300 +++++++----------- .../internal/JdbcResourceRegistryImpl.java | 14 +- .../jdbc/internal/LogicalConnectionImpl.java | 42 +-- .../jdbc/internal/StatementPreparer.java | 276 ++++++++++++++++ .../proxy/PreparedStatementProxyHandler.java | 7 + .../engine/jdbc/spi/ConnectionManager.java | 39 ++- .../hibernate/impl/SessionFactoryImpl.java | 5 - .../org/hibernate/jdbc/AbstractBatcher.java | 161 ---------- .../main/java/org/hibernate/jdbc/Batcher.java | 76 ----- .../org/hibernate/jdbc/BatcherFactory.java | 38 --- .../org/hibernate/jdbc/BatchingBatcher.java | 100 ------ .../jdbc/BatchingBatcherFactory.java | 48 --- .../hibernate/jdbc/NonBatchingBatcher.java | 53 ---- .../jdbc/NonBatchingBatcherFactory.java | 49 --- .../AbstractCollectionPersister.java | 30 +- .../collection/BasicCollectionPersister.java | 8 +- .../collection/OneToManyPersister.java | 19 +- .../entity/AbstractEntityPersister.java | 18 +- .../insertordering/InsertOrderingTest.java | 39 ++- .../jdbc/proxies/AggressiveReleaseTest.java | 10 +- .../proxies/BasicConnectionProxyTest.java | 10 +- .../batchload/BatchedManyToManyTest.java | 21 +- .../src/test/resources/log4j.properties | 3 +- 30 files changed, 720 insertions(+), 982 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/StatementPreparer.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/jdbc/AbstractBatcher.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/jdbc/Batcher.java delete mode 100755 hibernate-core/src/main/java/org/hibernate/jdbc/BatcherFactory.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/jdbc/BatchingBatcher.java delete mode 100755 hibernate-core/src/main/java/org/hibernate/jdbc/BatchingBatcherFactory.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/jdbc/NonBatchingBatcher.java delete mode 100755 hibernate-core/src/main/java/org/hibernate/jdbc/NonBatchingBatcherFactory.java 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 68959ed419..5e8056a6b5 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/Settings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/Settings.java @@ -32,7 +32,6 @@ 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.BatcherFactory; import org.hibernate.jdbc.util.SQLStatementLogger; import org.hibernate.transaction.TransactionFactory; import org.hibernate.transaction.TransactionManagerLookup; @@ -78,7 +77,6 @@ public final class Settings { private QueryCacheFactory queryCacheFactory; private TransactionFactory transactionFactory; private TransactionManagerLookup transactionManagerLookup; - private BatcherFactory batcherFactory; private BatchBuilder batchBuilder; private QueryTranslatorFactory queryTranslatorFactory; private boolean wrapResultSetsEnabled; @@ -228,10 +226,6 @@ public final class Settings { return flushBeforeCompletionEnabled; } - public BatcherFactory getBatcherFactory() { - return batcherFactory; - } - public BatchBuilder getBatchBuilder() { return batchBuilder; } @@ -419,10 +413,6 @@ public final class Settings { this.flushBeforeCompletionEnabled = flushBeforeCompletionEnabled; } - void setBatcherFactory(BatcherFactory batcher) { - this.batcherFactory = batcher; - } - void setBatcherBuilder(BatchBuilder batchBuilder) { this.batchBuilder = batchBuilder; } 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 9a6c1ecf60..ca2a34f396 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/SettingsFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/SettingsFactory.java @@ -44,9 +44,6 @@ import org.hibernate.engine.jdbc.spi.ExtractedDatabaseMetaData; import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.hql.QueryTranslatorFactory; import org.hibernate.internal.util.config.ConfigurationHelper; -import org.hibernate.jdbc.BatcherFactory; -import org.hibernate.jdbc.BatchingBatcherFactory; -import org.hibernate.jdbc.NonBatchingBatcherFactory; import org.hibernate.jdbc.util.SQLStatementLogger; import org.hibernate.transaction.TransactionFactory; import org.hibernate.transaction.TransactionFactoryFactory; @@ -115,7 +112,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.setBatcherFactory( createBatcherFactory(properties, batchSize) ); settings.setBatcherBuilder( createBatchBuilder(properties, batchSize) ); boolean useScrollableResultSets = ConfigurationHelper.getBoolean(Environment.USE_SCROLLABLE_RESULTSET, properties, meta.supportsScrollableResults()); @@ -350,47 +346,25 @@ public class SettingsFactory implements Serializable { } } - protected BatcherFactory createBatcherFactory(Properties properties, int batchSize) { - String batcherClass = properties.getProperty(Environment.BATCH_STRATEGY); - BatcherFactory batcherFactory = null; - if (batcherClass==null) { - batcherFactory = batchSize == 0 - ? new NonBatchingBatcherFactory() - : new BatchingBatcherFactory( ); - } - else { - log.info("Batcher factory: " + batcherClass); - try { - batcherFactory = (BatcherFactory) ReflectHelper.classForName(batcherClass).newInstance(); - } - catch (Exception cnfe) { - throw new HibernateException("could not instantiate BatcherFactory: " + batcherClass, cnfe); - } - } - batcherFactory.setJdbcBatchSize( batchSize ); - return batcherFactory; - } - protected BatchBuilder createBatchBuilder(Properties properties, int batchSize) { - //FIXME: uncomment to use BatchBuilder - /* String batchBuilderClass = properties.getProperty(Environment.BATCH_STRATEGY); + BatchBuilder batchBuilder; if (batchBuilderClass==null) { - return batchSize > 0 + batchBuilder = batchSize > 0 ? new BatchBuilder( batchSize ) : new BatchBuilder(); } else { - log.info("Batcher factory: " + batchBuilderClass); + log.info("Batch factory: " + batchBuilderClass); try { - return (BatchBuilder) ReflectHelper.classForName(batchBuilderClass).newInstance(); + batchBuilder = (BatchBuilder) ReflectHelper.classForName(batchBuilderClass).newInstance(); } catch (Exception cnfe) { throw new HibernateException("could not instantiate BatchBuilder: " + batchBuilderClass, cnfe); } } - */ - return null; + batchBuilder.setJdbcBatchSize( batchSize ); + return batchBuilder; } protected TransactionFactory createTransactionFactory(Properties properties) { 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 1f58e3bda9..5d171f4a38 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,7 +23,6 @@ */ package org.hibernate.engine.jdbc.batch.internal; -import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.LinkedHashMap; @@ -34,9 +33,8 @@ 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.JdbcServices; -import org.hibernate.engine.jdbc.spi.LogicalConnectionImplementor; -import org.hibernate.engine.jdbc.internal.proxy.ProxyBuilder; +import org.hibernate.engine.jdbc.spi.SQLExceptionHelper; +import org.hibernate.engine.jdbc.spi.SQLStatementLogger; /** * Convenience base class for implementors of the Batch interface. @@ -46,16 +44,21 @@ import org.hibernate.engine.jdbc.internal.proxy.ProxyBuilder; 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 LogicalConnectionImplementor logicalConnection; - private Connection connectionProxy; private LinkedHashMap statements = new LinkedHashMap(); private LinkedHashSet observers = new LinkedHashSet(); - protected AbstractBatchImpl(Object key, LogicalConnectionImplementor logicalConnection) { + 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." ); + } this.key = key; - this.logicalConnection = logicalConnection; - this.connectionProxy = ProxyBuilder.buildConnection( logicalConnection ); + this.statementLogger = statementLogger; + this.exceptionHelper = exceptionHelper; } /** @@ -67,12 +70,21 @@ public abstract class AbstractBatchImpl implements Batch { protected abstract void doExecuteBatch(); /** - * Convenience access to the underlying JDBC services. + * Convenience access to the SQLException helper. + * + * @return The underlying SQLException helper. + */ + protected SQLExceptionHelper getSqlExceptionHelper() { + return exceptionHelper; + } + + /** + * Convenience access to the SQL statement logger. * * @return The underlying JDBC services. */ - protected JdbcServices getJdbcServices() { - return logicalConnection.getJdbcServices(); + protected SQLStatementLogger getSqlStatementLogger() { + return statementLogger; } /** @@ -101,31 +113,39 @@ public abstract class AbstractBatchImpl implements Batch { /** * {@inheritDoc} */ - public final PreparedStatement getBatchStatement(String sql, boolean callable) { + public final PreparedStatement getBatchStatement(Object key, String sql) { + checkConsistentBatchKey( key ); + if ( sql == null ) { + throw new IllegalArgumentException( "sql must be non-null." ); + } PreparedStatement statement = statements.get( sql ); - if ( statement == null ) { - statement = buildBatchStatement( sql, callable ); - statements.put( sql, statement ); - } - else { - log.debug( "reusing batch statement" ); - getJdbcServices().getSqlStatementLogger().logStatement( sql ); - } + if ( statement != null ) { + log.debug( "reusing prepared statement" ); + statementLogger.logStatement( sql ); + } return statement; } - private PreparedStatement buildBatchStatement(String sql, boolean callable) { - try { - if ( callable ) { - return connectionProxy.prepareCall( sql ); - } - else { - return connectionProxy.prepareStatement( sql ); - } + /** + * {@inheritDoc} + */ + // TODO: should this be final??? + @Override + public void addBatchStatement(Object key, String sql, PreparedStatement preparedStatement) { + checkConsistentBatchKey( key ); + if ( sql == null ) { + throw new IllegalArgumentException( "sql must be non-null." ); } - catch ( SQLException sqle ) { - log.error( "sqlexception escaped proxy", sqle ); - throw getJdbcServices().getSqlExceptionHelper().convert( sqle, "could not prepare batch statement", sql ); + 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 + "]." + ); } } @@ -142,7 +162,7 @@ public abstract class AbstractBatchImpl implements Batch { doExecuteBatch(); } finally { - releaseStatements(); + release(); } } finally { 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/BatchBuilder.java index 85febd5946..e01a7047b3 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/BatchBuilder.java @@ -28,6 +28,8 @@ 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; /** * A builder for {@link Batch} instances. @@ -46,15 +48,17 @@ public class BatchBuilder { this.size = size; } - public void setSize(int size) { + public void setJdbcBatchSize(int size) { this.size = size; } - public Batch buildBatch(Object key, LogicalConnectionImplementor logicalConnection) { + public Batch buildBatch(Object key, + SQLStatementLogger statementLogger, + SQLExceptionHelper exceptionHelper) { log.trace( "building batch [size={}]", size ); return size > 1 - ? new BatchingBatch( key, logicalConnection, size ) - : new NonBatchingBatch( key, logicalConnection ); + ? new BatchingBatch( key, statementLogger, exceptionHelper, size ) + : new NonBatchingBatch( key, statementLogger, exceptionHelper ); } } 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 d5d036e42a..f7c3b246a6 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 @@ -25,18 +25,24 @@ 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.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.hibernate.AssertionFailure; import org.hibernate.HibernateException; -import org.hibernate.engine.jdbc.spi.LogicalConnectionImplementor; +import org.hibernate.engine.jdbc.spi.SQLExceptionHelper; +import org.hibernate.engine.jdbc.spi.SQLStatementLogger; import org.hibernate.jdbc.Expectation; /** - * A {@link org.hibernate.engine.jdbc.batch.spi.Batch} implementation which does batching based on a given size. Once the batch size is exceeded, the - * batch is implicitly executed. + * 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. * * @author Steve Ebersole */ @@ -44,33 +50,45 @@ public class BatchingBatch extends AbstractBatchImpl { private static final Logger log = LoggerFactory.getLogger( BatchingBatch.class ); private final int batchSize; - private Expectation[] expectations; - private int batchPosition; + private Map> expectationsBySql; + private int maxBatchPosition; - public BatchingBatch(Object key, LogicalConnectionImplementor logicalConnection, int batchSize) { - super( key, logicalConnection ); + public BatchingBatch(Object key, + SQLStatementLogger statementLogger, + SQLExceptionHelper exceptionHelper, + int batchSize) { + super( key, statementLogger, exceptionHelper ); this.batchSize = batchSize; - this.expectations = new Expectation[ batchSize ]; + this.expectationsBySql = new HashMap>(); } /** * {@inheritDoc} */ - public void addToBatch(Expectation expectation) { - if ( !expectation.canBeBatched() ) { + 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() ) { throw new HibernateException( "attempting to batch an operation which cannot be batched" ); } - for ( Map.Entry entry : getStatements().entrySet() ) { - try { - entry.getValue().addBatch(); - } - catch ( SQLException e ) { - log.error( "sqlexception escaped proxy", e ); - throw getJdbcServices().getSqlExceptionHelper().convert( e, "could not perform addBatch", entry.getKey() ); - } + final PreparedStatement statement = getStatements().get( sql ); + try { + statement.addBatch(); } - expectations[ batchPosition++ ] = expectation; - if ( batchPosition == batchSize ) { + catch ( SQLException e ) { + log.error( "sqlexception escaped proxy", e ); + throw getSqlExceptionHelper().convert( e, "could not perform addBatch", sql ); + } + 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() ); + if ( maxBatchPosition == batchSize ) { notifyObserversImplicitExecution(); doExecuteBatch(); } @@ -80,46 +98,89 @@ public class BatchingBatch extends AbstractBatchImpl { * {@inheritDoc} */ protected void doExecuteBatch() { - if ( batchPosition == 0 ) { + if ( maxBatchPosition == 0 ) { log.debug( "no batched statements to execute" ); } else { if ( log.isDebugEnabled() ) { - log.debug( "Executing batch size: " + batchPosition ); + log.debug( "Executing {} statements with maximum batch size {} ", + getStatements().size(), maxBatchPosition + ); } - try { - for ( Map.Entry entry : getStatements().entrySet() ) { - try { - final PreparedStatement statement = entry.getValue(); - checkRowCounts( statement.executeBatch(), statement ); - } - catch ( SQLException e ) { - log.error( "sqlexception escaped proxy", e ); - throw getJdbcServices().getSqlExceptionHelper() - .convert( e, "could not perform addBatch", entry.getKey() ); - } - } + executeStatements(); } catch ( RuntimeException re ) { log.error( "Exception executing batch [{}]", re.getMessage() ); throw re; } finally { - batchPosition = 0; + for ( List expectations : expectationsBySql.values() ) { + expectations.clear(); + } + maxBatchPosition = 0; } - } } - private void checkRowCounts(int[] rowCounts, PreparedStatement ps) throws SQLException, HibernateException { + 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) { + try { + checkRowCounts( sql, ps.executeBatch(), ps, expectations ); + } + catch ( SQLException e ) { + log.error( "sqlexception escaped proxy", e ); + throw getSqlExceptionHelper() + .convert( e, "could not execute statement: " + sql ); + } + } + + private void checkRowCounts(String sql, int[] rowCounts, PreparedStatement ps, List expectations) { int numberOfRowCounts = rowCounts.length; - if ( numberOfRowCounts != batchPosition ) { + if ( numberOfRowCounts != expectations.size() ) { log.warn( "JDBC driver did not return the expected number of row counts" ); } - for ( int i = 0; i < numberOfRowCounts; i++ ) { - expectations[i].verifyOutcome( rowCounts[i], ps, i ); + 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 ); } } + 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 e9becd14b6..64eb6b116a 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 @@ -25,12 +25,12 @@ package org.hibernate.engine.jdbc.batch.internal; import java.sql.PreparedStatement; import java.sql.SQLException; -import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.hibernate.engine.jdbc.spi.LogicalConnectionImplementor; +import org.hibernate.engine.jdbc.spi.SQLExceptionHelper; +import org.hibernate.engine.jdbc.spi.SQLStatementLogger; import org.hibernate.jdbc.Expectation; /** @@ -42,22 +42,26 @@ import org.hibernate.jdbc.Expectation; public class NonBatchingBatch extends AbstractBatchImpl { private static final Logger log = LoggerFactory.getLogger( NonBatchingBatch.class ); - protected NonBatchingBatch(Object key, LogicalConnectionImplementor logicalConnection) { - super( key, logicalConnection ); + protected NonBatchingBatch(Object key, + SQLStatementLogger statementLogger, + SQLExceptionHelper exceptionHelper) { + super( key, statementLogger, exceptionHelper ); } - public void addToBatch(Expectation expectation) { + public void addToBatch(Object key, String sql, Expectation expectation) { + checkConsistentBatchKey( key ); + if ( sql == null ) { + throw new IllegalArgumentException( "sql must be non-null." ); + } notifyObserversImplicitExecution(); - for ( Map.Entry entry : getStatements().entrySet() ) { - try { - final PreparedStatement statement = entry.getValue(); - final int rowCount = statement.executeUpdate(); - expectation.verifyOutcome( rowCount, statement, 0 ); - } - catch ( SQLException e ) { - log.error( "sqlexception escaped proxy", e ); - throw getJdbcServices().getSqlExceptionHelper().convert( e, "could not execute batch statement", entry.getKey() ); - } + 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 ); } } 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 aeda16f69b..89ed9f39a3 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 @@ -55,17 +55,26 @@ public interface Batch { * Get a statement which is part of the batch, creating if necessary (and storing for next time). * * @param sql The SQL statement. - * @param callable Is the SQL statement callable? * @return The prepared statement instance, representing the SQL statement. */ - public PreparedStatement getBatchStatement(String sql, boolean callable); + public PreparedStatement getBatchStatement(Object key, String sql); + + /** + * Store a statement in the batch. + * + * @param sql The SQL statement. + */ + public void addBatchStatement(Object key, String sql, PreparedStatement preparedStatement); + /** * 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(Expectation expectation); + public void addToBatch(Object key, String sql, Expectation expectation); /** * Execute this batch. 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 index 306c65b86a..dddaa20eca 100644 --- 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 @@ -30,7 +30,6 @@ import java.io.ObjectOutputStream; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.PreparedStatement; -import java.sql.ResultSet; import java.sql.SQLException; import org.slf4j.Logger; @@ -41,12 +40,11 @@ import org.hibernate.ConnectionReleaseMode; import org.hibernate.HibernateException; import org.hibernate.Interceptor; import org.hibernate.ScrollMode; -import org.hibernate.TransactionException; import org.hibernate.engine.SessionFactoryImplementor; -import org.hibernate.engine.jdbc.internal.proxy.ProxyBuilder; +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.Batcher; import org.hibernate.jdbc.Expectation; /** @@ -67,15 +65,13 @@ public class ConnectionManagerImpl implements ConnectionManager { // TODO: check if it's ok to change the method names in Callback - private transient SessionFactoryImplementor factory; - private transient Connection proxiedConnection; private transient Interceptor interceptor; private final Callback callback; - private long transactionTimeout = -1; - boolean isTransactionTimeoutSet; - private transient LogicalConnectionImpl logicalConnection; + private transient StatementPreparer statementPreparer; + private final transient BatchBuilder batchBuilder; + private Batch batch; /** * Constructs a ConnectionManager. @@ -99,8 +95,7 @@ public class ConnectionManagerImpl implements ConnectionManager { suppliedConnection, releaseMode, factory.getJdbcServices(), - factory.getStatistics() != null ? factory.getStatisticsImplementor() : null, - factory.getSettings().getBatcherFactory() + factory.getStatistics() != null ? factory.getStatisticsImplementor() : null ) ); } @@ -114,16 +109,12 @@ public class ConnectionManagerImpl implements ConnectionManager { Interceptor interceptor, LogicalConnectionImpl logicalConnection ) { - this.factory = factory; this.callback = callback; this.interceptor = interceptor; - setupConnection( logicalConnection ); - } - - private void setupConnection(LogicalConnectionImpl logicalConnection) { this.logicalConnection = logicalConnection; this.logicalConnection.addObserver( callback ); - proxiedConnection = ProxyBuilder.buildConnection( logicalConnection ); + this.statementPreparer = new StatementPreparer( logicalConnection, factory.getSettings() ); + this.batchBuilder = factory.getSettings().getBatchBuilder(); } /** @@ -271,7 +262,9 @@ public class ConnectionManagerImpl implements ConnectionManager { log.debug( "transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!" ); } } - unsetTransactionTimeout(); + if ( statementPreparer != null ) { + statementPreparer.unsetTransactionTimeout(); + } } private boolean isAfterTransactionRelease() { @@ -282,37 +275,15 @@ public class ConnectionManagerImpl implements ConnectionManager { return logicalConnection.getConnectionReleaseMode() == ConnectionReleaseMode.ON_CLOSE; } - public boolean isLogicallyConnected() { + private boolean isLogicallyConnected() { return logicalConnection != null && logicalConnection.isOpen(); } @Override public void setTransactionTimeout(int seconds) { - isTransactionTimeoutSet = true; - transactionTimeout = System.currentTimeMillis() / 1000 + seconds; + statementPreparer.setTransactionTimeout( seconds ); } - /** - * Unset the transaction timeout, called after the end of a - * transaction. - */ - private void unsetTransactionTimeout() { - isTransactionTimeoutSet = false; - } - - private void setStatementTimeout(PreparedStatement preparedStatement) throws SQLException { - if ( isTransactionTimeoutSet ) { - int timeout = (int) ( transactionTimeout - ( System.currentTimeMillis() / 1000 ) ); - if ( timeout <= 0) { - throw new TransactionException("transaction timeout expired"); - } - else { - preparedStatement.setQueryTimeout(timeout); - } - } - } - - /** * To be called after Session completion. Used to release the JDBC * connection. @@ -337,6 +308,7 @@ public class ConnectionManagerImpl implements ConnectionManager { if ( ! isLogicallyConnected() ) { throw new IllegalStateException( "cannot manually disconnect because not logically connected." ); } + releaseBatch(); return logicalConnection.manualDisconnect(); } @@ -382,10 +354,14 @@ public class ConnectionManagerImpl implements ConnectionManager { } try { log.trace( "performing cleanup" ); + releaseBatch(); + statementPreparer.close(); Connection c = logicalConnection.close(); return c; } finally { + batch = null; + statementPreparer = null; logicalConnection = null; } } @@ -412,105 +388,68 @@ public class ConnectionManagerImpl implements ConnectionManager { afterStatement(); } - private abstract class StatementPreparer { - private final String sql; - StatementPreparer(String sql) { - this.sql = getSQL( sql ); - } - public String getSqlToPrepare() { - return sql; - } - abstract PreparedStatement doPrepare() throws SQLException; - public void afterPrepare(PreparedStatement preparedStatement) throws SQLException { - setStatementTimeout( preparedStatement ); - } - } - /** * Get a non-batchable prepared statement to use for inserting / deleting / updating, * using JDBC3 getGeneratedKeys ({@link java.sql.Connection#prepareStatement(String, int)}). + *

+ * If not explicitly closed via {@link java.sql.PreparedStatement#close()}, it will be + * released when the session is closed or disconnected. */ + @Override public PreparedStatement prepareStatement(String sql, final int autoGeneratedKeys) throws HibernateException { - if ( autoGeneratedKeys == PreparedStatement.RETURN_GENERATED_KEYS ) { - checkAutoGeneratedKeysSupportEnabled(); - } - StatementPreparer statementPreparer = new StatementPreparer( sql ) { - public PreparedStatement doPrepare() throws SQLException { - return proxiedConnection.prepareStatement( getSqlToPrepare(), autoGeneratedKeys ); - } - }; - return prepareStatement( statementPreparer, true ); + executeBatch(); + return statementPreparer.prepareStatement( getSQL( sql ), autoGeneratedKeys ); } /** * Get a non-batchable prepared statement to use for inserting / deleting / updating. * using JDBC3 getGeneratedKeys ({@link java.sql.Connection#prepareStatement(String, String[])}). + *

+ * If not explicitly closed via {@link java.sql.PreparedStatement#close()}, it will be + * released when the session is closed or disconnected. */ + @Override public PreparedStatement prepareStatement(String sql, final String[] columnNames) { - checkAutoGeneratedKeysSupportEnabled(); - StatementPreparer statementPreparer = new StatementPreparer( sql ) { - public PreparedStatement doPrepare() throws SQLException { - return proxiedConnection.prepareStatement( getSqlToPrepare(), columnNames ); - } - }; - return prepareStatement( statementPreparer, true ); - } - - private void checkAutoGeneratedKeysSupportEnabled() { - if ( ! factory.getSettings().isGetGeneratedKeysEnabled() ) { - throw new AssertionFailure("getGeneratedKeys() support is not enabled"); - } + executeBatch(); + return statementPreparer.prepareStatement( getSQL( sql ), columnNames ); } /** * Get a non-batchable prepared statement to use for selecting. Does not * result in execution of the current batch. + *

+ * If not explicitly closed via {@link java.sql.PreparedStatement#close()}, + * it will be released when the session is closed or disconnected. */ + @Override public PreparedStatement prepareSelectStatement(String sql) { - return prepareStatement( sql, false, false ); + return statementPreparer.prepareStatement( getSQL( sql ), false ); } /** * Get a non-batchable prepared statement to use for inserting / deleting / updating. + *

+ * If not explicitly closed via {@link java.sql.PreparedStatement#close()}, it will be + * released when the session is closed or disconnected. */ + @Override public PreparedStatement prepareStatement(String sql, final boolean isCallable) { - return prepareStatement( sql, isCallable, true ); + executeBatch(); + return statementPreparer.prepareStatement( getSQL( sql ), isCallable ); } /** * Get a non-batchable callable statement to use for inserting / deleting / updating. + *

+ * If not explicitly closed via {@link java.sql.PreparedStatement#close()}, it will be + * released when the session is closed or disconnected. */ + @Override public CallableStatement prepareCallableStatement(String sql) { + executeBatch(); log.trace("preparing callable statement"); - return CallableStatement.class.cast( prepareStatement( sql, true, true ) ); - } - - public PreparedStatement prepareStatement(String sql, final boolean isCallable, boolean forceExecuteBatch) { - StatementPreparer statementPreparer = new StatementPreparer( sql ) { - public PreparedStatement doPrepare() throws SQLException { - return prepareStatementInternal( getSqlToPrepare(), isCallable ); - } - }; - return prepareStatement( statementPreparer, forceExecuteBatch ); - } - - private PreparedStatement prepareStatementInternal(String sql, boolean isCallable) throws SQLException { - return isCallable ? - proxiedConnection.prepareCall( sql ) : - proxiedConnection.prepareStatement( sql ); - } - - private PreparedStatement prepareScrollableStatementInternal(String sql, - ScrollMode scrollMode, - boolean isCallable) throws SQLException { - return isCallable ? - proxiedConnection.prepareCall( - sql, scrollMode.toResultSetType(), ResultSet.CONCUR_READ_ONLY - ) : - proxiedConnection.prepareStatement( - sql, scrollMode.toResultSetType(), ResultSet.CONCUR_READ_ONLY - ); + return CallableStatement.class.cast( statementPreparer.prepareStatement( getSQL( sql ), true ) ); } /** @@ -518,105 +457,97 @@ public class ConnectionManagerImpl implements ConnectionManager { * (might be called many times before a single call to executeBatch()). * After setting parameters, call addToBatch - do not execute the * statement explicitly. - * @see org.hibernate.jdbc.Batcher#addToBatch + * @see org.hibernate.engine.jdbc.batch.spi.Batch#addToBatch + *

+ * If not explicitly closed via {@link java.sql.PreparedStatement#close()}, it will be + * released when the session is closed or disconnected. */ - public PreparedStatement prepareBatchStatement(String sql, boolean isCallable) { - String batchUpdateSQL = getSQL( sql ); - - PreparedStatement batchUpdate = getBatcher().getStatement( batchUpdateSQL ); - if ( batchUpdate == null ) { - batchUpdate = prepareStatement( batchUpdateSQL, isCallable, true ); // calls executeBatch() - getBatcher().setStatement( batchUpdateSQL, batchUpdate ); + @Override + public PreparedStatement prepareBatchStatement(Object key, String sql, boolean isCallable) { + if ( key == null ) { + throw new IllegalArgumentException( "batch key must be non-null." ); } - else { - log.debug( "reusing prepared statement" ); - factory.getJdbcServices().getSqlStatementLogger().logStatement( batchUpdateSQL ); + String actualSQL = getSQL( sql ); + PreparedStatement batchUpdate = null; + if ( batch != null ) { + if ( key.equals( batch.getKey() ) ) { + batchUpdate = batch.getBatchStatement( key, actualSQL ); + } + else { + batch.execute(); + batch = null; + } + } + if ( batch == null ) { + batch = batchBuilder.buildBatch( + key, + logicalConnection.getJdbcServices().getSqlStatementLogger(), + logicalConnection.getJdbcServices().getSqlExceptionHelper() + ); + } + if ( batchUpdate == null ) { + batchUpdate = statementPreparer.prepareStatement( actualSQL, isCallable ); + batch.addBatchStatement( key, actualSQL, batchUpdate ); } return batchUpdate; } - private Batcher getBatcher() { - return logicalConnection.getBatcher(); - } - /** - * Get a prepared statement for use in loading / querying. If not explicitly - * released by closeQueryStatement(), it will be released when the - * session is closed or disconnected. + * Get a prepared statement for use in loading / querying. Does not + * result in execution of the current batch. + *

+ * If not explicitly closed via {@link java.sql.PreparedStatement#close()}, + * it will be released when the session is closed or disconnected. */ + @Override public PreparedStatement prepareQueryStatement( String sql, final boolean isScrollable, final ScrollMode scrollMode, - final boolean isCallable - ) { - if ( isScrollable && ! factory.getSettings().isScrollableResultSetsEnabled() ) { - throw new AssertionFailure("scrollable result sets are not enabled"); - } - StatementPreparer statementPreparer = new StatementPreparer( sql ) { - public PreparedStatement doPrepare() throws SQLException { - PreparedStatement ps = - isScrollable ? - prepareScrollableStatementInternal( getSqlToPrepare(), scrollMode, isCallable ) : - prepareStatementInternal( getSqlToPrepare(), isCallable ) - ; - return ps; - } - public void afterPrepare(PreparedStatement preparedStatement) throws SQLException { - super.afterPrepare( preparedStatement ); - setStatementFetchSize( preparedStatement, getSqlToPrepare() ); - logicalConnection.getResourceRegistry().registerLastQuery( preparedStatement ); - } - }; - return prepareStatement( statementPreparer, false ); - } - - private void setStatementFetchSize(PreparedStatement statement, String sql) throws SQLException { - if ( factory.getSettings().getJdbcFetchSize() != null ) { - statement.setFetchSize( factory.getSettings().getJdbcFetchSize() ); - } - } - - private PreparedStatement prepareStatement(StatementPreparer preparer, boolean forceExecuteBatch) { - if ( forceExecuteBatch ) { - executeBatch(); - } - try { - PreparedStatement ps = preparer.doPrepare(); - preparer.afterPrepare( ps ); - return ps; - } - catch ( SQLException sqle ) { - log.error( "sqlexception escaped proxy", sqle ); - throw logicalConnection.getJdbcServices().getSqlExceptionHelper().convert( - sqle, "could not prepare statement", preparer.getSqlToPrepare() - ); - } + final boolean isCallable) { + PreparedStatement ps = ( + isScrollable ? + statementPreparer.prepareScrollableQueryStatement( + getSQL( sql ), scrollMode, isCallable + ) : + statementPreparer.prepareQueryStatement( + getSQL( sql ), isCallable + ) + ); + logicalConnection.getResourceRegistry().registerLastQuery( ps ); + return ps; } /** * Cancel the current query statement */ + @Override public void cancelLastQuery() throws HibernateException { logicalConnection.getResourceRegistry().cancelLastQuery(); } - public void abortBatch(SQLException sqle) { - getBatcher().abortBatch( sqle ); - } - - public void addToBatch(Expectation expectation ) { - try { - getBatcher().addToBatch( expectation ); - } - catch (SQLException sqle) { - throw logicalConnection.getJdbcServices().getSqlExceptionHelper().convert( - sqle, "could not add to batch statement" ); - } + @Override + public void addToBatch(Object batchKey, String sql, Expectation expectation) { + batch.addToBatch( batchKey, sql, expectation ); } + @Override public void executeBatch() throws HibernateException { - getBatcher().executeBatch(); + if ( batch != null ) { + batch.execute(); + batch.release(); // needed? + } + } + + @Override + public void abortBatch() { + releaseBatch(); + } + + private void releaseBatch() { + if ( batch != null ) { + batch.release(); + } } private String getSQL(String sql) { @@ -673,8 +604,7 @@ public class ConnectionManagerImpl implements ConnectionManager { ois, factory.getJdbcServices(), factory.getStatistics() != null ? factory.getStatisticsImplementor() : null, - connectionReleaseMode, - factory.getSettings().getBatcherFactory() + connectionReleaseMode ) ); } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/JdbcResourceRegistryImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/JdbcResourceRegistryImpl.java index a4c0249342..bcace088a0 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/JdbcResourceRegistryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/JdbcResourceRegistryImpl.java @@ -23,14 +23,11 @@ */ package org.hibernate.engine.jdbc.internal; -import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; -import java.util.ConcurrentModificationException; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.Map; import java.util.Set; @@ -42,8 +39,6 @@ import org.hibernate.engine.jdbc.spi.JdbcWrapper; import org.hibernate.engine.jdbc.spi.SQLExceptionHelper; import org.hibernate.engine.jdbc.spi.JdbcResourceRegistry; import org.hibernate.engine.jdbc.spi.InvalidatableWrapper; -import org.hibernate.jdbc.Batcher; -import org.hibernate.jdbc.BatcherFactory; /** * Standard implementation of the {@link org.hibernate.engine.jdbc.spi.JdbcResourceRegistry} contract @@ -56,13 +51,11 @@ public class JdbcResourceRegistryImpl implements JdbcResourceRegistry { private final HashMap> xref = new HashMap>(); private final Set unassociatedResultSets = new HashSet(); private final SQLExceptionHelper exceptionHelper; - private final Batcher batcher; private Statement lastQuery; - public JdbcResourceRegistryImpl(SQLExceptionHelper exceptionHelper, BatcherFactory batcherFactory) { + public JdbcResourceRegistryImpl(SQLExceptionHelper exceptionHelper) { this.exceptionHelper = exceptionHelper; - this.batcher = batcherFactory.createBatcher( exceptionHelper ); } public void register(Statement statement) { @@ -73,10 +66,6 @@ public class JdbcResourceRegistryImpl implements JdbcResourceRegistry { xref.put( statement, null ); } - public Batcher getBatcher() { - return batcher; - } - @SuppressWarnings({ "unchecked" }) public void registerLastQuery(Statement statement) { log.trace( "registering last query statement [{}]", statement ); @@ -183,7 +172,6 @@ public class JdbcResourceRegistryImpl implements JdbcResourceRegistry { } private void cleanup() { - batcher.closeStatements(); for ( Map.Entry> entry : xref.entrySet() ) { if ( entry.getValue() != null ) { for ( ResultSet resultSet : entry.getValue() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/LogicalConnectionImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/LogicalConnectionImpl.java index 35a8f091b8..8191d94162 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/LogicalConnectionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/LogicalConnectionImpl.java @@ -41,8 +41,6 @@ import org.hibernate.engine.jdbc.spi.JdbcResourceRegistry; import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.jdbc.spi.ConnectionObserver; import org.hibernate.engine.jdbc.spi.LogicalConnectionImplementor; -import org.hibernate.jdbc.Batcher; -import org.hibernate.jdbc.BatcherFactory; import org.hibernate.jdbc.BorrowedConnectionProxy; import org.hibernate.stat.StatisticsImplementor; @@ -60,7 +58,7 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor { private final ConnectionReleaseMode connectionReleaseMode; private final JdbcServices jdbcServices; private final StatisticsImplementor statisticsImplementor; - private final JdbcResourceRegistryImpl jdbcResourceRegistry; + private final JdbcResourceRegistry jdbcResourceRegistry; private final List observers = new ArrayList(); private boolean releasesEnabled = true; @@ -72,31 +70,20 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor { public LogicalConnectionImpl(Connection userSuppliedConnection, ConnectionReleaseMode connectionReleaseMode, JdbcServices jdbcServices, - StatisticsImplementor statisticsImplementor, - BatcherFactory batcherFactory + StatisticsImplementor statisticsImplementor ) { - this.jdbcServices = jdbcServices; - this.statisticsImplementor = statisticsImplementor; + this( connectionReleaseMode, + jdbcServices, + statisticsImplementor, + userSuppliedConnection != null, + false + ); this.physicalConnection = userSuppliedConnection; - this.connectionReleaseMode = - determineConnectionReleaseMode( - jdbcServices, userSuppliedConnection != null, connectionReleaseMode - ); - this.jdbcResourceRegistry = - new JdbcResourceRegistryImpl( - getJdbcServices().getSqlExceptionHelper(), - batcherFactory - ); - - this.isUserSuppliedConnection = ( userSuppliedConnection != null ); - this.isClosed = false; } - // used for deserialization private LogicalConnectionImpl(ConnectionReleaseMode connectionReleaseMode, JdbcServices jdbcServices, StatisticsImplementor statisticsImplementor, - BatcherFactory batcherFactory, boolean isUserSuppliedConnection, boolean isClosed) { this.connectionReleaseMode = determineConnectionReleaseMode( @@ -105,10 +92,7 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor { this.jdbcServices = jdbcServices; this.statisticsImplementor = statisticsImplementor; this.jdbcResourceRegistry = - new JdbcResourceRegistryImpl( - getJdbcServices().getSqlExceptionHelper(), - batcherFactory - ); + new JdbcResourceRegistryImpl( getJdbcServices().getSqlExceptionHelper() ); this.isUserSuppliedConnection = isUserSuppliedConnection; this.isClosed = isClosed; @@ -230,10 +214,6 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor { return connectionReleaseMode; } - public Batcher getBatcher() { - return jdbcResourceRegistry.getBatcher(); - } - public boolean hasBorrowedConnection() { return borrowedConnection != null; } @@ -436,14 +416,12 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor { public static LogicalConnectionImpl deserialize(ObjectInputStream ois, JdbcServices jdbcServices, StatisticsImplementor statisticsImplementor, - ConnectionReleaseMode connectionReleaseMode, - BatcherFactory batcherFactory + ConnectionReleaseMode connectionReleaseMode ) throws IOException { return new LogicalConnectionImpl( connectionReleaseMode, jdbcServices, statisticsImplementor, - batcherFactory, ois.readBoolean(), ois.readBoolean() ); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/StatementPreparer.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/StatementPreparer.java new file mode 100644 index 0000000000..2500f328f9 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/StatementPreparer.java @@ -0,0 +1,276 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010, 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.internal; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.hibernate.AssertionFailure; +import org.hibernate.HibernateException; +import org.hibernate.ScrollMode; +import org.hibernate.TransactionException; +import org.hibernate.cfg.Settings; +import org.hibernate.engine.jdbc.internal.proxy.ProxyBuilder; +import org.hibernate.engine.jdbc.spi.LogicalConnectionImplementor; +import org.hibernate.engine.jdbc.spi.SQLExceptionHelper; + +/** + * Prepares statements. + * + * @author Gail Badner + */ +public class StatementPreparer { + + private static final Logger log = LoggerFactory.getLogger( StatementPreparer.class ); + + // TODO: Move JDBC settings into a different object... + private final Settings settings; + private final Connection proxiedConnection; + private final SQLExceptionHelper sqlExceptionHelper; + + private long transactionTimeout = -1; + boolean isTransactionTimeoutSet; + + /** + * Constructs a StatementPreparer object + * @param logicalConnection - the logical connection + * @param settings - contains settings configured for preparing statements + */ + public StatementPreparer(LogicalConnectionImplementor logicalConnection, Settings settings) { + this.settings = settings; + proxiedConnection = ProxyBuilder.buildConnection( logicalConnection ); + sqlExceptionHelper = logicalConnection.getJdbcServices().getSqlExceptionHelper(); + } + + private abstract class StatementPreparation { + private final String sql; + protected abstract PreparedStatement doPrepare() throws SQLException; + public StatementPreparation(String sql) { + this.sql = sql; + } + public String getSql() { + return sql; + } + public void postProcess(PreparedStatement preparedStatement) throws SQLException { + setStatementTimeout( preparedStatement ); + } + public PreparedStatement prepareAndPostProcess() { + try { + PreparedStatement ps = doPrepare(); + postProcess( ps ); + return ps; + } + catch ( SQLException sqle ) { + log.error( "sqlexception escaped proxy", sqle ); + throw sqlExceptionHelper.convert( + sqle, "could not prepare statement", sql + ); + } + } + } + + private abstract class QueryStatementPreparation extends StatementPreparation { + QueryStatementPreparation(String sql) { + super( sql ); + } + public void postProcess(PreparedStatement preparedStatement) throws SQLException { + super.postProcess( preparedStatement ); + setStatementFetchSize( preparedStatement ); + } + } + + public void close() { + try { + proxiedConnection.close(); + } + catch (SQLException sqle) { + log.error( "sqlexception escaped proxy", sqle ); + throw sqlExceptionHelper.convert( sqle, "could not close connection proxy" ); + } + } + + /** + * Prepare a statement. If configured, the query timeout is set. + *

+ * If not explicitly closed via {@link java.sql.PreparedStatement#close()}, + * it will be released when the session is closed or disconnected. + * + * @param sql - the SQL for the statement to be prepared + * @param isCallable - true, if a callable statement is to be prepared + * @return the prepared statement + */ + public PreparedStatement prepareStatement(String sql, final boolean isCallable) { + StatementPreparation statementPreparation = new StatementPreparation( sql ) { + public PreparedStatement doPrepare() throws SQLException { + return isCallable ? + proxiedConnection.prepareCall( getSql() ) : + proxiedConnection.prepareStatement( getSql() ); + } + }; + return statementPreparation.prepareAndPostProcess(); + } + + /** + * Get a prepared statement to use for inserting / deleting / updating, + * using JDBC3 getGeneratedKeys ({@link java.sql.Connection#prepareStatement(String, int)}). + * If configured, the query timeout is set. + *

+ * If not explicitly closed via {@link java.sql.PreparedStatement#close()}, + * it will be released when the session is closed or disconnected. + + * @param sql - the SQL for the statement to be prepared + * @param autoGeneratedKeys - a flag indicating whether auto-generated + * keys should be returned; one of + * PreparedStatement.RETURN_GENERATED_KEYS or + * Statement.NO_GENERATED_KEYS + * @return the prepared statement + */ + public PreparedStatement prepareStatement(String sql, final int autoGeneratedKeys) + throws HibernateException { + if ( autoGeneratedKeys == PreparedStatement.RETURN_GENERATED_KEYS ) { + checkAutoGeneratedKeysSupportEnabled(); + } + StatementPreparation statementPreparation = new StatementPreparation( sql ) { + public PreparedStatement doPrepare() throws SQLException { + return proxiedConnection.prepareStatement( getSql(), autoGeneratedKeys ); + } + }; + return statementPreparation.prepareAndPostProcess(); + } + + /** + * Get a prepared statement to use for inserting / deleting / updating. + * using JDBC3 getGeneratedKeys ({@link java.sql.Connection#prepareStatement(String, String[])}). + * If configured, the query timeout is set. + *

+ * If not explicitly closed via {@link java.sql.PreparedStatement#close()}, + * it will be released when the session is closed or disconnected. + */ + public PreparedStatement prepareStatement(String sql, final String[] columnNames) { + checkAutoGeneratedKeysSupportEnabled(); + StatementPreparation preparation = new StatementPreparation( sql ) { + public PreparedStatement doPrepare() throws SQLException { + return proxiedConnection.prepareStatement( getSql(), columnNames ); + } + }; + return preparation.prepareAndPostProcess(); + } + + private void checkAutoGeneratedKeysSupportEnabled() { + if ( ! settings.isGetGeneratedKeysEnabled() ) { + throw new AssertionFailure("getGeneratedKeys() support is not enabled"); + } + } + + /** + * Get a prepared statement for use in loading / querying. + * If configured, the query timeout and statement fetch size are set. + *

+ * If not explicitly closed via {@link java.sql.PreparedStatement#close()}, + * it will be released when the session is closed or disconnected. + */ + public PreparedStatement prepareQueryStatement( + String sql, + final boolean isCallable + ) { + StatementPreparation prep = new QueryStatementPreparation( sql ) { + public PreparedStatement doPrepare() throws SQLException { + return isCallable ? + proxiedConnection.prepareCall( getSql() ) : + proxiedConnection.prepareStatement( getSql() ); + } + }; + return prep.prepareAndPostProcess(); + } + + /** + * Get a scrollable prepared statement for use in loading / querying. + * If configured, the query timeout and statement fetch size are set. + *

+ * If not explicitly closed via {@link java.sql.PreparedStatement#close()}, + * it will be released when the session is closed or disconnected. + */ + public PreparedStatement prepareScrollableQueryStatement( + String sql, + final ScrollMode scrollMode, + final boolean isCallable + ) { + if ( ! settings.isScrollableResultSetsEnabled() ) { + throw new AssertionFailure("scrollable result sets are not enabled"); + } + StatementPreparation prep = new QueryStatementPreparation( sql ) { + public PreparedStatement doPrepare() throws SQLException { + return isCallable ? + proxiedConnection.prepareCall( + getSql(), scrollMode.toResultSetType(), ResultSet.CONCUR_READ_ONLY + ) : + proxiedConnection.prepareStatement( + getSql(), scrollMode.toResultSetType(), ResultSet.CONCUR_READ_ONLY + ); + } + }; + return prep.prepareAndPostProcess(); + } + + /** + * Sets the transaction timeout. + * @param seconds - number of seconds until the the transaction times out. + */ + public void setTransactionTimeout(int seconds) { + isTransactionTimeoutSet = true; + transactionTimeout = System.currentTimeMillis() / 1000 + seconds; + } + + /** + * Unset the transaction timeout, called after the end of a + * transaction. + */ + public void unsetTransactionTimeout() { + isTransactionTimeoutSet = false; + } + + private void setStatementTimeout(PreparedStatement preparedStatement) throws SQLException { + if ( isTransactionTimeoutSet ) { + int timeout = (int) ( transactionTimeout - ( System.currentTimeMillis() / 1000 ) ); + if ( timeout <= 0) { + throw new TransactionException("transaction timeout expired"); + } + else { + preparedStatement.setQueryTimeout(timeout); + } + } + } + + private void setStatementFetchSize(PreparedStatement statement) throws SQLException { + if ( settings.getJdbcFetchSize() != null ) { + statement.setFetchSize( settings.getJdbcFetchSize() ); + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/proxy/PreparedStatementProxyHandler.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/proxy/PreparedStatementProxyHandler.java index cc8f76a2d7..e78e3e32bf 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/proxy/PreparedStatementProxyHandler.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/proxy/PreparedStatementProxyHandler.java @@ -26,6 +26,10 @@ package org.hibernate.engine.jdbc.internal.proxy; import java.lang.reflect.Method; import java.sql.Connection; import java.sql.Statement; +import java.util.Arrays; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Invocation handler for {@link java.sql.PreparedStatement} proxies @@ -33,6 +37,8 @@ import java.sql.Statement; * @author Steve Ebersole */ public class PreparedStatementProxyHandler extends AbstractStatementProxyHandler { + private static final Logger log = LoggerFactory.getLogger( ConnectionProxyHandler.class ); + private final String sql; protected PreparedStatementProxyHandler( @@ -63,6 +69,7 @@ public class PreparedStatementProxyHandler extends AbstractStatementProxyHandler } private void journalParameterBind(Method method, Object[] args) { + log.trace( "binding via {}: []", method.getName(), Arrays.asList( args ) ); } private boolean isExecution(Method method) { diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/spi/ConnectionManager.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/spi/ConnectionManager.java index 733fa01891..9e7d35fb8a 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/spi/ConnectionManager.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/spi/ConnectionManager.java @@ -79,6 +79,10 @@ public interface ConnectionManager extends Serializable { */ void afterStatement(); + /** + * Sets the transaction timeout. + * @param seconds - number of seconds until the the transaction times out. + */ void setTransactionTimeout(int seconds); /** @@ -131,28 +135,43 @@ public interface ConnectionManager extends Serializable { /** * Get a non-batchable prepared statement to use for inserting / deleting / updating, * using JDBC3 getGeneratedKeys ({@link java.sql.Connection#prepareStatement(String, int)}). + *

+ * If not explicitly closed via {@link java.sql.PreparedStatement#close()}, it will be + * released when the session is closed or disconnected. */ public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys); /** * Get a non-batchable prepared statement to use for inserting / deleting / updating. * using JDBC3 getGeneratedKeys ({@link java.sql.Connection#prepareStatement(String, String[])}). + *

+ * If not explicitly closed via {@link java.sql.PreparedStatement#close()}, it will be + * released when the session is closed or disconnected. */ public PreparedStatement prepareStatement(String sql, String[] columnNames); /** * Get a non-batchable prepared statement to use for selecting. Does not * result in execution of the current batch. + *

+ * If not explicitly closed via {@link java.sql.PreparedStatement#close()}, + * it will be released when the session is closed or disconnected. */ public PreparedStatement prepareSelectStatement(String sql); /** * Get a non-batchable prepared statement to use for inserting / deleting / updating. + *

+ * If not explicitly closed via {@link java.sql.PreparedStatement#close()}, it will be + * released when the session is closed or disconnected. */ public PreparedStatement prepareStatement(String sql, boolean isCallable); /** * Get a non-batchable callable statement to use for inserting / deleting / updating. + *

+ * If not explicitly closed via {@link java.sql.PreparedStatement#close()}, it will be + * released when the session is closed or disconnected. */ public CallableStatement prepareCallableStatement(String sql); @@ -161,28 +180,34 @@ public interface ConnectionManager extends Serializable { * (might be called many times before a single call to executeBatch()). * After setting parameters, call addToBatch - do not execute the * statement explicitly. - * @see org.hibernate.jdbc.Batcher#addToBatch + * @see org.hibernate.engine.jdbc.batch.spi.Batch#addToBatch + *

+ * If not explicitly closed via {@link java.sql.PreparedStatement#close()}, it will be + * released when the session is closed or disconnected. */ - public PreparedStatement prepareBatchStatement(String sql, boolean isCallable); + public PreparedStatement prepareBatchStatement(Object key, String sql, boolean isCallable); /** - * Get a prepared statement for use in loading / querying. If not explicitly - * released by closeQueryStatement(), it will be released when the - * session is closed or disconnected. + * Get a prepared statement for use in loading / querying. Does not + * result in execution of the current batch. + *

+ * If not explicitly closed via {@link java.sql.PreparedStatement#close()}, + * it will be released when the session is closed or disconnected. */ public PreparedStatement prepareQueryStatement( String sql, boolean isScrollable, ScrollMode scrollMode, boolean isCallable); + /** * Cancel the current query statement */ public void cancelLastQuery(); - public void abortBatch(SQLException sqle); + public void abortBatch(); - public void addToBatch(Expectation expectation ); + public void addToBatch(Object batchKey, String sql, Expectation expectation); public void executeBatch(); } diff --git a/hibernate-core/src/main/java/org/hibernate/impl/SessionFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/impl/SessionFactoryImpl.java index 703b81deed..ec43d984ef 100644 --- a/hibernate-core/src/main/java/org/hibernate/impl/SessionFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/impl/SessionFactoryImpl.java @@ -99,7 +99,6 @@ import org.hibernate.event.EventListeners; import org.hibernate.id.IdentifierGenerator; import org.hibernate.id.UUIDGenerator; import org.hibernate.id.factory.IdentifierGeneratorFactory; -import org.hibernate.jdbc.BatcherFactory; import org.hibernate.mapping.Collection; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.RootClass; @@ -1235,10 +1234,6 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI return filters.keySet(); } - public BatcherFactory getBatcherFactory() { - return settings.getBatcherFactory(); - } - public IdentifierGenerator getIdentifierGenerator(String rootEntityName) { return (IdentifierGenerator) identifierGenerators.get(rootEntityName); } diff --git a/hibernate-core/src/main/java/org/hibernate/jdbc/AbstractBatcher.java b/hibernate-core/src/main/java/org/hibernate/jdbc/AbstractBatcher.java deleted file mode 100644 index d619475881..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/jdbc/AbstractBatcher.java +++ /dev/null @@ -1,161 +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.jdbc; - -import java.sql.PreparedStatement; -import java.sql.SQLException; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.hibernate.HibernateException; -import org.hibernate.engine.jdbc.spi.SQLExceptionHelper; - -/** - * Manages prepared statements and batching. - * - * @author Gavin King - */ -public abstract class AbstractBatcher implements Batcher { - - protected static final Logger log = LoggerFactory.getLogger( AbstractBatcher.class ); - - private final SQLExceptionHelper exceptionHelper; - private final int jdbcBatchSize; - - private PreparedStatement batchUpdate; - private String batchUpdateSQL; - private boolean isClosingBatchUpdate = false; - - public AbstractBatcher(SQLExceptionHelper exceptionHelper, int jdbcBatchSize) { - this.exceptionHelper = exceptionHelper; - this.jdbcBatchSize = jdbcBatchSize; - } - - public final int getJdbcBatchSize() { - return jdbcBatchSize; - } - - public boolean hasOpenResources() { - try { - return !isClosingBatchUpdate && batchUpdate != null && ! batchUpdate.isClosed(); - } - catch (SQLException sqle) { - throw exceptionHelper.convert( - sqle, - "Could check to see if batch statement was closed", - batchUpdateSQL - ); - } - } - - public PreparedStatement getStatement(String sql) { - return batchUpdate != null && batchUpdateSQL.equals( sql ) ? batchUpdate : null; - } - - public void setStatement(String sql, PreparedStatement ps) { - checkNotClosingBatchUpdate(); - batchUpdateSQL = sql; - batchUpdate = ps; - } - - protected PreparedStatement getStatement() { - return batchUpdate; - } - - public void abortBatch(SQLException sqle) { - closeStatements(); - } - - /** - * Actually releases the batcher, allowing it to cleanup internally held - * resources. - */ - public void closeStatements() { - try { - closeBatchUpdate(); - } - catch ( SQLException sqle ) { - //no big deal - log.warn( "Could not close a JDBC prepared statement", sqle ); - } - batchUpdate = null; - batchUpdateSQL = null; - } - - public void executeBatch() throws HibernateException { - checkNotClosingBatchUpdate(); - if (batchUpdate!=null) { - try { - try { - doExecuteBatch(batchUpdate); - } - finally { - closeBatchUpdate(); - } - } - catch (SQLException sqle) { - throw exceptionHelper.convert( - sqle, - "Could not execute JDBC batch update", - batchUpdateSQL - ); - } - finally { - batchUpdate=null; - batchUpdateSQL=null; - } - } - } - - protected abstract void doExecuteBatch(PreparedStatement ps) throws SQLException, HibernateException; - - - private void closeBatchUpdate() throws SQLException{ - checkNotClosingBatchUpdate(); - try { - if ( batchUpdate != null ) { - isClosingBatchUpdate = true; - batchUpdate.close(); - } - } - finally { - isClosingBatchUpdate = false; - } - - } - - private void checkNotClosingBatchUpdate() { - if ( isClosingBatchUpdate ) { - throw new IllegalStateException( "Cannot perform operation while closing batch update." ); - } - } -} - - - - - - diff --git a/hibernate-core/src/main/java/org/hibernate/jdbc/Batcher.java b/hibernate-core/src/main/java/org/hibernate/jdbc/Batcher.java deleted file mode 100644 index df96c984e7..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/jdbc/Batcher.java +++ /dev/null @@ -1,76 +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.jdbc; - -import java.sql.CallableStatement; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; - -import org.hibernate.HibernateException; -import org.hibernate.ScrollMode; -import org.hibernate.dialect.Dialect; - -/** - * Manages PreparedStatements for a session. Abstracts JDBC - * batching to maintain the illusion that a single logical batch - * exists for the whole session, even when batching is disabled. - * Provides transparent PreparedStatement caching. - * - * @see java.sql.PreparedStatement - * @see org.hibernate.impl.SessionImpl - * @author Gavin King - */ -public interface Batcher { - - public PreparedStatement getStatement(String sql); - public void setStatement(String sql, PreparedStatement ps); - public boolean hasOpenResources(); - - /** - * Add an insert / delete / update to the current batch (might be called multiple times - * for single prepareBatchStatement()) - */ - public void addToBatch(Expectation expectation) throws SQLException, HibernateException; - - /** - * Execute the batch - */ - public void executeBatch() throws HibernateException; - - /** - * Must be called when an exception occurs - * @param sqle the (not null) exception that is the reason for aborting - */ - public void abortBatch(SQLException sqle); - - /** - * Actually releases the batcher, allowing it to cleanup internally held - * resources. - */ - public void closeStatements(); -} - diff --git a/hibernate-core/src/main/java/org/hibernate/jdbc/BatcherFactory.java b/hibernate-core/src/main/java/org/hibernate/jdbc/BatcherFactory.java deleted file mode 100755 index bf03718847..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/jdbc/BatcherFactory.java +++ /dev/null @@ -1,38 +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.jdbc; - -import org.hibernate.Interceptor; -import org.hibernate.engine.jdbc.spi.SQLExceptionHelper; - - -/** - * Factory for Batcher instances. - * @author Gavin King - */ -public interface BatcherFactory { - public void setJdbcBatchSize(int jdbcBatchSize); - public Batcher createBatcher(SQLExceptionHelper exceptionHelper); -} diff --git a/hibernate-core/src/main/java/org/hibernate/jdbc/BatchingBatcher.java b/hibernate-core/src/main/java/org/hibernate/jdbc/BatchingBatcher.java deleted file mode 100644 index aae2972d32..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/jdbc/BatchingBatcher.java +++ /dev/null @@ -1,100 +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.jdbc; - -import java.sql.PreparedStatement; -import java.sql.SQLException; - -import org.hibernate.HibernateException; -import org.hibernate.engine.jdbc.spi.SQLExceptionHelper; - -/** - * An implementation of the Batcher interface that - * actually uses batching - * @author Gavin King - */ -public class BatchingBatcher extends AbstractBatcher { - - private Expectation[] expectations; - - private int currentSize; - public BatchingBatcher(SQLExceptionHelper exceptionHelper, int jdbcBatchSize) { - super( exceptionHelper, jdbcBatchSize ); - expectations = new Expectation[ jdbcBatchSize ]; - currentSize = 0; - } - - public void addToBatch(Expectation expectation) throws SQLException, HibernateException { - if ( !expectation.canBeBatched() ) { - throw new HibernateException( "attempting to batch an operation which cannot be batched" ); - } - PreparedStatement batchUpdate = getStatement(); - batchUpdate.addBatch(); - expectations[ currentSize++ ] = expectation; - if ( currentSize == getJdbcBatchSize() ) { - doExecuteBatch( batchUpdate ); - } - } - - protected void doExecuteBatch(PreparedStatement ps) throws SQLException, HibernateException { - if ( currentSize == 0 ) { - log.debug( "no batched statements to execute" ); - } - else { - if ( log.isDebugEnabled() ) { - log.debug( "Executing batch size: " + currentSize ); - } - - try { - checkRowCounts( ps.executeBatch(), ps ); - } - catch (RuntimeException re) { - log.error( "Exception executing batch: ", re ); - throw re; - } - finally { - currentSize = 0; - } - - } - } - - private void checkRowCounts(int[] rowCounts, PreparedStatement ps) throws SQLException, HibernateException { - int numberOfRowCounts = rowCounts.length; - if ( numberOfRowCounts != currentSize ) { - log.warn( "JDBC driver did not return the expected number of row counts" ); - } - for ( int i = 0; i < numberOfRowCounts; i++ ) { - expectations[i].verifyOutcome( rowCounts[i], ps, i ); - } - } - -} - - - - - - diff --git a/hibernate-core/src/main/java/org/hibernate/jdbc/BatchingBatcherFactory.java b/hibernate-core/src/main/java/org/hibernate/jdbc/BatchingBatcherFactory.java deleted file mode 100755 index a1e14dbc0b..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/jdbc/BatchingBatcherFactory.java +++ /dev/null @@ -1,48 +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.jdbc; - -import org.hibernate.engine.jdbc.spi.SQLExceptionHelper; - - -/** - * A BatcherFactory implementation which constructs Batcher instances - * capable of actually performing batch operations. - * - * @author Gavin King - */ -public class BatchingBatcherFactory implements BatcherFactory { - - private int jdbcBatchSize; - - public void setJdbcBatchSize(int jdbcBatchSize) { - this.jdbcBatchSize = jdbcBatchSize; - } - - public Batcher createBatcher(SQLExceptionHelper exceptionHelper) { - return new BatchingBatcher( exceptionHelper, jdbcBatchSize ); - } - -} diff --git a/hibernate-core/src/main/java/org/hibernate/jdbc/NonBatchingBatcher.java b/hibernate-core/src/main/java/org/hibernate/jdbc/NonBatchingBatcher.java deleted file mode 100644 index 6dfea07339..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/jdbc/NonBatchingBatcher.java +++ /dev/null @@ -1,53 +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.jdbc; - -import java.sql.PreparedStatement; -import java.sql.SQLException; - -import org.hibernate.HibernateException; -import org.hibernate.engine.jdbc.spi.SQLExceptionHelper; - -/** - * An implementation of the Batcher interface that does no batching - * - * @author Gavin King - */ -public class NonBatchingBatcher extends AbstractBatcher { - - public NonBatchingBatcher(SQLExceptionHelper exceptionHelper) { - super( exceptionHelper, 1 ); - } - - public void addToBatch(Expectation expectation) throws SQLException, HibernateException { - PreparedStatement statement = getStatement(); - final int rowCount = statement.executeUpdate(); - expectation.verifyOutcome( rowCount, statement, 0 ); - } - - protected void doExecuteBatch(PreparedStatement ps) throws SQLException, HibernateException { - } - -} diff --git a/hibernate-core/src/main/java/org/hibernate/jdbc/NonBatchingBatcherFactory.java b/hibernate-core/src/main/java/org/hibernate/jdbc/NonBatchingBatcherFactory.java deleted file mode 100755 index ee55421e0d..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/jdbc/NonBatchingBatcherFactory.java +++ /dev/null @@ -1,49 +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.jdbc; - -import org.hibernate.AssertionFailure; -import org.hibernate.engine.jdbc.spi.SQLExceptionHelper; - - -/** - * A BatcherFactory implementation which constructs Batcher instances - * that do not perform batch operations. - * - * @author Gavin King - */ -public class NonBatchingBatcherFactory implements BatcherFactory { - - public void setJdbcBatchSize(int jdbcBatchSize) { - if ( jdbcBatchSize > 1 ) { - throw new AssertionFailure( "jdbcBatchSize must be 1 for " + getClass().getName() ); - } - } - - public Batcher createBatcher(SQLExceptionHelper exceptionHelper) { - return new NonBatchingBatcher( exceptionHelper ); - } - -} diff --git a/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java index d297f6e1a0..cabd43a6bd 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java @@ -1083,7 +1083,7 @@ public abstract class AbstractCollectionPersister boolean useBatch = expectation.canBeBatched(); String sql = getSQLDeleteString(); if ( useBatch ) { - st = session.getJDBCContext().getConnectionManager().prepareBatchStatement( sql, callable ); + st = session.getJDBCContext().getConnectionManager().prepareBatchStatement( this, sql, callable ); } else { st = session.getJDBCContext().getConnectionManager().prepareStatement( sql, callable ); @@ -1095,7 +1095,7 @@ public abstract class AbstractCollectionPersister writeKey( st, id, offset, session ); if ( useBatch ) { - session.getJDBCContext().getConnectionManager().addToBatch( expectation ); + session.getJDBCContext().getConnectionManager().addToBatch( this, sql, expectation ); } else { expectation.verifyOutcome( st.executeUpdate(), st, -1 ); @@ -1103,7 +1103,7 @@ public abstract class AbstractCollectionPersister } catch ( SQLException sqle ) { if ( useBatch ) { - session.getJDBCContext().getConnectionManager().abortBatch( sqle ); + session.getJDBCContext().getConnectionManager().abortBatch(); } throw sqle; } @@ -1161,7 +1161,9 @@ public abstract class AbstractCollectionPersister String sql = getSQLInsertRowString(); if ( useBatch ) { - st = session.getJDBCContext().getConnectionManager().prepareBatchStatement( sql, callable ); + st = session.getJDBCContext().getConnectionManager().prepareBatchStatement( + this, sql, callable + ); } else { st = session.getJDBCContext().getConnectionManager().prepareStatement( sql, callable ); @@ -1182,7 +1184,7 @@ public abstract class AbstractCollectionPersister loc = writeElement(st, collection.getElement(entry), loc, session ); if ( useBatch ) { - session.getJDBCContext().getConnectionManager().addToBatch( expectation ); + session.getJDBCContext().getConnectionManager().addToBatch( this, sql, expectation ); } else { expectation.verifyOutcome( st.executeUpdate(), st, -1 ); @@ -1193,7 +1195,7 @@ public abstract class AbstractCollectionPersister } catch ( SQLException sqle ) { if ( useBatch ) { - session.getJDBCContext().getConnectionManager().abortBatch( sqle ); + session.getJDBCContext().getConnectionManager().abortBatch(); } throw sqle; } @@ -1261,7 +1263,9 @@ public abstract class AbstractCollectionPersister String sql = getSQLDeleteRowString(); if ( useBatch ) { - st = session.getJDBCContext().getConnectionManager().prepareBatchStatement( sql, callable ); + st = session.getJDBCContext().getConnectionManager().prepareBatchStatement( + this, sql, callable + ); } else { st = session.getJDBCContext().getConnectionManager().prepareStatement( sql, callable ); @@ -1286,7 +1290,7 @@ public abstract class AbstractCollectionPersister } if ( useBatch ) { - session.getJDBCContext().getConnectionManager().addToBatch( expectation ); + session.getJDBCContext().getConnectionManager().addToBatch( this, sql, expectation ); } else { expectation.verifyOutcome( st.executeUpdate(), st, -1 ); @@ -1295,7 +1299,7 @@ public abstract class AbstractCollectionPersister } catch ( SQLException sqle ) { if ( useBatch ) { - session.getJDBCContext().getConnectionManager().abortBatch( sqle ); + session.getJDBCContext().getConnectionManager().abortBatch(); } throw sqle; } @@ -1361,7 +1365,9 @@ public abstract class AbstractCollectionPersister if ( useBatch ) { if ( st == null ) { - st = session.getJDBCContext().getConnectionManager().prepareBatchStatement( sql, callable ); + st = session.getJDBCContext().getConnectionManager().prepareBatchStatement( + this, sql, callable + ); } } else { @@ -1381,7 +1387,7 @@ public abstract class AbstractCollectionPersister writeElement(st, collection.getElement(entry), offset, session ); if ( useBatch ) { - session.getJDBCContext().getConnectionManager().addToBatch( expectation ); + session.getJDBCContext().getConnectionManager().addToBatch( this, sql, expectation ); } else { expectation.verifyOutcome( st.executeUpdate(), st, -1 ); @@ -1391,7 +1397,7 @@ public abstract class AbstractCollectionPersister } catch ( SQLException sqle ) { if ( useBatch ) { - session.getJDBCContext().getConnectionManager().abortBatch( sqle ); + session.getJDBCContext().getConnectionManager().abortBatch(); } throw sqle; } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java index 1a2184cac9..4fa624149b 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java @@ -211,7 +211,9 @@ public class BasicCollectionPersister extends AbstractCollectionPersister { if ( useBatch ) { if ( st == null ) { - st = session.getJDBCContext().getConnectionManager().prepareBatchStatement( sql, callable ); + st = session.getJDBCContext().getConnectionManager().prepareBatchStatement( + this, sql, callable + ); } } else { @@ -235,7 +237,7 @@ public class BasicCollectionPersister extends AbstractCollectionPersister { } if ( useBatch ) { - session.getJDBCContext().getConnectionManager().addToBatch( expectation ); + session.getJDBCContext().getConnectionManager().addToBatch( this, sql, expectation ); } else { expectation.verifyOutcome( st.executeUpdate(), st, -1 ); @@ -243,7 +245,7 @@ public class BasicCollectionPersister extends AbstractCollectionPersister { } catch ( SQLException sqle ) { if ( useBatch ) { - session.getJDBCContext().getConnectionManager().abortBatch( sqle ); + session.getJDBCContext().getConnectionManager().abortBatch(); } throw sqle; } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java index 5045323364..2057a92cd6 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java @@ -196,27 +196,26 @@ public class OneToManyPersister extends AbstractCollectionPersister { Object entry = entries.next(); if ( collection.needsUpdating( entry, i, elementType ) ) { // will still be issued when it used to be null + String sql = getSQLDeleteRowString(); if ( st == null ) { - String sql = getSQLDeleteRowString(); if ( isDeleteCallable() ) { expectation = Expectations.appropriateExpectation( getDeleteCheckStyle() ); useBatch = expectation.canBeBatched(); st = useBatch - ? session.getJDBCContext().getConnectionManager().prepareBatchStatement( sql, true ) + ? session.getJDBCContext().getConnectionManager().prepareBatchStatement( this, sql, true ) : session.getJDBCContext().getConnectionManager().prepareStatement( sql, true ); offset += expectation.prepare( st ); } else { st = session.getJDBCContext().getConnectionManager().prepareBatchStatement( - getSQLDeleteRowString(), - false + this, sql, false ); } } int loc = writeKey( st, id, offset, session ); writeElementToWhere( st, collection.getSnapshotElement(entry, i), loc, session ); if ( useBatch ) { - session.getJDBCContext().getConnectionManager().addToBatch( expectation ); + session.getJDBCContext().getConnectionManager().addToBatch( this, sql, expectation ); } else { expectation.verifyOutcome( st.executeUpdate(), st, -1 ); @@ -228,7 +227,7 @@ public class OneToManyPersister extends AbstractCollectionPersister { } catch ( SQLException sqle ) { if ( useBatch ) { - session.getJDBCContext().getConnectionManager().abortBatch( sqle ); + session.getJDBCContext().getConnectionManager().abortBatch(); } throw sqle; } @@ -255,7 +254,9 @@ public class OneToManyPersister extends AbstractCollectionPersister { if ( collection.needsUpdating( entry, i, elementType ) ) { if ( useBatch ) { if ( st == null ) { - st = session.getJDBCContext().getConnectionManager().prepareBatchStatement( sql, callable ); + st = session.getJDBCContext().getConnectionManager().prepareBatchStatement( + this, sql, callable + ); } } else { @@ -272,7 +273,7 @@ public class OneToManyPersister extends AbstractCollectionPersister { writeElementToWhere( st, collection.getElement( entry ), loc, session ); if ( useBatch ) { - session.getJDBCContext().getConnectionManager().addToBatch( expectation ); + session.getJDBCContext().getConnectionManager().addToBatch( this, sql, expectation ); } else { expectation.verifyOutcome( st.executeUpdate(), st, -1 ); @@ -284,7 +285,7 @@ public class OneToManyPersister extends AbstractCollectionPersister { } catch ( SQLException sqle ) { if ( useBatch ) { - session.getJDBCContext().getConnectionManager().abortBatch( sqle ); + session.getJDBCContext().getConnectionManager().abortBatch(); } throw sqle; } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index 528f412472..ba5e71e7bd 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -2381,7 +2381,7 @@ public abstract class AbstractEntityPersister // Render the SQL query final PreparedStatement insert; if ( useBatch ) { - insert = session.getJDBCContext().getConnectionManager().prepareBatchStatement( sql, callable ); + insert = session.getJDBCContext().getConnectionManager().prepareBatchStatement( this, sql, callable ); } else { insert = session.getJDBCContext().getConnectionManager().prepareStatement( sql, callable ); @@ -2398,7 +2398,7 @@ public abstract class AbstractEntityPersister if ( useBatch ) { // TODO : shouldnt inserts be Expectations.NONE? - session.getJDBCContext().getConnectionManager().addToBatch( expectation ); + session.getJDBCContext().getConnectionManager().addToBatch( this, sql, expectation ); } else { expectation.verifyOutcome( insert.executeUpdate(), insert, -1 ); @@ -2407,7 +2407,7 @@ public abstract class AbstractEntityPersister } catch ( SQLException sqle ) { if ( useBatch ) { - session.getJDBCContext().getConnectionManager().abortBatch( sqle ); + session.getJDBCContext().getConnectionManager().abortBatch(); } throw sqle; } @@ -2500,7 +2500,7 @@ public abstract class AbstractEntityPersister int index = 1; // starting index final PreparedStatement update; if ( useBatch ) { - update = session.getJDBCContext().getConnectionManager().prepareBatchStatement( sql, callable ); + update = session.getJDBCContext().getConnectionManager().prepareBatchStatement( this, sql, callable ); } else { update = session.getJDBCContext().getConnectionManager().prepareStatement( sql, callable ); @@ -2543,7 +2543,7 @@ public abstract class AbstractEntityPersister } if ( useBatch ) { - session.getJDBCContext().getConnectionManager().addToBatch( expectation ); + session.getJDBCContext().getConnectionManager().addToBatch( this, sql, expectation ); return true; } else { @@ -2553,7 +2553,7 @@ public abstract class AbstractEntityPersister } catch ( SQLException sqle ) { if ( useBatch ) { - session.getJDBCContext().getConnectionManager().abortBatch( sqle ); + session.getJDBCContext().getConnectionManager().abortBatch(); } throw sqle; } @@ -2614,7 +2614,7 @@ public abstract class AbstractEntityPersister PreparedStatement delete; int index = 1; if ( useBatch ) { - delete = session.getJDBCContext().getConnectionManager().prepareBatchStatement( sql, callable ); + delete = session.getJDBCContext().getConnectionManager().prepareBatchStatement( this, sql, callable ); } else { delete = session.getJDBCContext().getConnectionManager().prepareStatement( sql, callable ); @@ -2649,7 +2649,7 @@ public abstract class AbstractEntityPersister } if ( useBatch ) { - session.getJDBCContext().getConnectionManager().addToBatch( expectation ); + session.getJDBCContext().getConnectionManager().addToBatch( this, sql, expectation ); } else { check( delete.executeUpdate(), id, j, expectation, delete ); @@ -2658,7 +2658,7 @@ public abstract class AbstractEntityPersister } catch ( SQLException sqle ) { if ( useBatch ) { - session.getJDBCContext().getConnectionManager().abortBatch( sqle ); + session.getJDBCContext().getConnectionManager().abortBatch(); } throw sqle; } diff --git a/hibernate-core/src/test/java/org/hibernate/test/insertordering/InsertOrderingTest.java b/hibernate-core/src/test/java/org/hibernate/test/insertordering/InsertOrderingTest.java index 1a207b62f7..4df42c0a47 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/insertordering/InsertOrderingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/insertordering/InsertOrderingTest.java @@ -3,22 +3,21 @@ package org.hibernate.test.insertordering; import java.util.List; import java.util.ArrayList; import java.util.Iterator; -import java.sql.SQLException; import java.sql.PreparedStatement; import junit.framework.Test; +import org.hibernate.engine.jdbc.batch.internal.BatchBuilder; +import org.hibernate.engine.jdbc.batch.internal.BatchingBatch; +import org.hibernate.engine.jdbc.batch.spi.Batch; import org.hibernate.engine.jdbc.spi.SQLExceptionHelper; +import org.hibernate.engine.jdbc.spi.SQLStatementLogger; import org.hibernate.testing.junit.functional.FunctionalTestCase; import org.hibernate.testing.junit.functional.FunctionalTestClassTestSuite; import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Environment; import org.hibernate.Session; -import org.hibernate.HibernateException; -import org.hibernate.jdbc.BatchingBatcher; import org.hibernate.jdbc.Expectation; -import org.hibernate.jdbc.BatcherFactory; -import org.hibernate.jdbc.Batcher; /** * {@inheritDoc} @@ -42,7 +41,7 @@ public class InsertOrderingTest extends FunctionalTestCase { super.configure( cfg ); cfg.setProperty( Environment.ORDER_INSERTS, "true" ); cfg.setProperty( Environment.STATEMENT_BATCH_SIZE, "10" ); - cfg.setProperty( Environment.BATCH_STRATEGY, StatsBatcherFactory.class.getName() ); + cfg.setProperty( Environment.BATCH_STRATEGY, StatsBatchBuilder.class.getName() ); } public void testBatchOrdering() { @@ -56,11 +55,11 @@ public class InsertOrderingTest extends FunctionalTestCase { s.save( group ); user.addMembership( group ); } - StatsBatcher.reset(); + StatsBatch.reset(); s.getTransaction().commit(); s.close(); - assertEquals( 3, StatsBatcher.batchSizes.size() ); + assertEquals( 3, StatsBatch.batchSizes.size() ); s = openSession(); s.beginTransaction(); @@ -76,13 +75,13 @@ public class InsertOrderingTest extends FunctionalTestCase { public int count = 0; } - public static class StatsBatcher extends BatchingBatcher { + public static class StatsBatch extends BatchingBatch { private static String batchSQL; private static List batchSizes = new ArrayList(); private static int currentBatch = -1; - public StatsBatcher(SQLExceptionHelper exceptionHelper, int jdbcBatchSize) { - super( exceptionHelper, jdbcBatchSize ); + public StatsBatch(Object key, SQLStatementLogger statementLogger, SQLExceptionHelper exceptionHelper, int jdbcBatchSize) { + super( key, statementLogger, exceptionHelper, jdbcBatchSize ); } static void reset() { @@ -91,7 +90,7 @@ public class InsertOrderingTest extends FunctionalTestCase { batchSQL = null; } - public void setStatement(String sql, PreparedStatement ps) { + public void addBatchStatement(Object key, String sql, PreparedStatement ps) { if ( batchSQL == null || ! batchSQL.equals( sql ) ) { currentBatch++; batchSQL = sql; @@ -99,31 +98,31 @@ public class InsertOrderingTest extends FunctionalTestCase { System.out.println( "--------------------------------------------------------" ); System.out.println( "Preparing statement [" + sql + "]" ); } - super.setStatement( sql, ps ); + super.addBatchStatement( key, sql, ps ); } - public void addToBatch(Expectation expectation) throws SQLException, HibernateException { + public void addToBatch(Object key, String sql, Expectation expectation) { Counter counter = ( Counter ) batchSizes.get( currentBatch ); counter.count++; System.out.println( "Adding to batch [" + batchSQL + "]" ); - super.addToBatch( expectation ); + super.addToBatch( key, sql, expectation ); } - protected void doExecuteBatch(PreparedStatement ps) throws SQLException, HibernateException { + protected void doExecuteBatch() { System.out.println( "executing batch [" + batchSQL + "]" ); System.out.println( "--------------------------------------------------------" ); - super.doExecuteBatch( ps ); + super.doExecuteBatch(); } } - public static class StatsBatcherFactory implements BatcherFactory { + public static class StatsBatchBuilder extends BatchBuilder { private int jdbcBatchSize; public void setJdbcBatchSize(int jdbcBatchSize) { this.jdbcBatchSize = jdbcBatchSize; } - public Batcher createBatcher(SQLExceptionHelper exceptionHelper) { - return new StatsBatcher( exceptionHelper, jdbcBatchSize ); + public Batch buildBatch(Object key, SQLStatementLogger statementLogger, SQLExceptionHelper exceptionHelper) { + return new StatsBatch(key, statementLogger, exceptionHelper, jdbcBatchSize ); } } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/jdbc/proxies/AggressiveReleaseTest.java b/hibernate-core/src/test/java/org/hibernate/test/jdbc/proxies/AggressiveReleaseTest.java index 2a893a8fd2..e32122b4ed 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/jdbc/proxies/AggressiveReleaseTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/jdbc/proxies/AggressiveReleaseTest.java @@ -35,7 +35,6 @@ import org.hibernate.ConnectionReleaseMode; import org.hibernate.engine.jdbc.internal.LogicalConnectionImpl; import org.hibernate.engine.jdbc.spi.ConnectionObserver; import org.hibernate.engine.jdbc.internal.proxy.ProxyBuilder; -import org.hibernate.jdbc.NonBatchingBatcherFactory; import org.hibernate.test.common.BasicTestingJdbcServiceImpl; import org.hibernate.testing.junit.UnitTestCase; @@ -135,8 +134,7 @@ public class AggressiveReleaseTest extends UnitTestCase { null, ConnectionReleaseMode.AFTER_STATEMENT, services, - null, - new NonBatchingBatcherFactory() + null ); Connection proxiedConnection = ProxyBuilder.buildConnection( logicalConnection ); ConnectionCounter observer = new ConnectionCounter(); @@ -170,8 +168,7 @@ public class AggressiveReleaseTest extends UnitTestCase { null, ConnectionReleaseMode.AFTER_STATEMENT, services, - null, - new NonBatchingBatcherFactory() + null ); Connection proxiedConnection = ProxyBuilder.buildConnection( logicalConnection ); ConnectionCounter observer = new ConnectionCounter(); @@ -230,8 +227,7 @@ public class AggressiveReleaseTest extends UnitTestCase { null, ConnectionReleaseMode.AFTER_STATEMENT, services, - null, - new NonBatchingBatcherFactory() + null ); Connection proxiedConnection = ProxyBuilder.buildConnection( logicalConnection ); ConnectionCounter observer = new ConnectionCounter(); diff --git a/hibernate-core/src/test/java/org/hibernate/test/jdbc/proxies/BasicConnectionProxyTest.java b/hibernate-core/src/test/java/org/hibernate/test/jdbc/proxies/BasicConnectionProxyTest.java index 7de8b8f8ef..8107c1ea0b 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/jdbc/proxies/BasicConnectionProxyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/jdbc/proxies/BasicConnectionProxyTest.java @@ -34,7 +34,6 @@ import org.hibernate.ConnectionReleaseMode; import org.hibernate.JDBCException; import org.hibernate.engine.jdbc.internal.LogicalConnectionImpl; import org.hibernate.engine.jdbc.internal.proxy.ProxyBuilder; -import org.hibernate.jdbc.NonBatchingBatcherFactory; import org.hibernate.test.common.BasicTestingJdbcServiceImpl; import org.hibernate.testing.junit.UnitTestCase; @@ -63,8 +62,7 @@ public class BasicConnectionProxyTest extends UnitTestCase { null, ConnectionReleaseMode.AFTER_TRANSACTION, services, - null, - new NonBatchingBatcherFactory() + null ); Connection proxiedConnection = ProxyBuilder.buildConnection( logicalConnection ); try { @@ -92,8 +90,7 @@ public class BasicConnectionProxyTest extends UnitTestCase { null, ConnectionReleaseMode.AFTER_TRANSACTION, services, - null, - new NonBatchingBatcherFactory() + null ); Connection proxiedConnection = ProxyBuilder.buildConnection( logicalConnection ); try { @@ -115,8 +112,7 @@ public class BasicConnectionProxyTest extends UnitTestCase { null, ConnectionReleaseMode.AFTER_TRANSACTION, services, - null, - new NonBatchingBatcherFactory() + null ); Connection proxiedConnection = ProxyBuilder.buildConnection( logicalConnection ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/manytomany/batchload/BatchedManyToManyTest.java b/hibernate-core/src/test/java/org/hibernate/test/manytomany/batchload/BatchedManyToManyTest.java index 8c71891ac3..ca66ad9aa1 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/manytomany/batchload/BatchedManyToManyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/manytomany/batchload/BatchedManyToManyTest.java @@ -26,7 +26,11 @@ import java.util.List; import junit.framework.Test; import junit.framework.Assert; +import org.hibernate.engine.jdbc.batch.internal.BatchBuilder; +import org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch; +import org.hibernate.engine.jdbc.batch.spi.Batch; import org.hibernate.engine.jdbc.spi.SQLExceptionHelper; +import org.hibernate.engine.jdbc.spi.SQLStatementLogger; import org.hibernate.testing.junit.functional.FunctionalTestCase; import org.hibernate.testing.junit.functional.FunctionalTestClassTestSuite; import org.hibernate.cfg.Configuration; @@ -35,9 +39,6 @@ import org.hibernate.Session; import org.hibernate.Hibernate; import org.hibernate.Interceptor; import org.hibernate.EmptyInterceptor; -import org.hibernate.jdbc.BatcherFactory; -import org.hibernate.jdbc.NonBatchingBatcher; -import org.hibernate.jdbc.Batcher; import org.hibernate.stat.CollectionStatistics; import org.hibernate.loader.collection.BatchingCollectionInitializer; import org.hibernate.persister.collection.AbstractCollectionPersister; @@ -64,23 +65,23 @@ public class BatchedManyToManyTest extends FunctionalTestCase { public void configure(Configuration cfg) { cfg.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "false" ); cfg.setProperty( Environment.GENERATE_STATISTICS, "true" ); - cfg.setProperty( Environment.BATCH_STRATEGY, TestingBatcherFactory.class.getName() ); + cfg.setProperty( Environment.BATCH_STRATEGY, TestingBatchBuilder.class.getName() ); } - public static class TestingBatcherFactory implements BatcherFactory { + public static class TestingBatchBuilder extends BatchBuilder { private int jdbcBatchSize; public void setJdbcBatchSize(int jdbcBatchSize) { this.jdbcBatchSize = jdbcBatchSize; } - public Batcher createBatcher(SQLExceptionHelper exceptionHelper) { - return new TestingBatcher( exceptionHelper, jdbcBatchSize ); + public Batch buildBatch(Object key, SQLStatementLogger statementLogger, SQLExceptionHelper exceptionHelper) { + return new TestingBatch(key, statementLogger, exceptionHelper, jdbcBatchSize ); } } - public static class TestingBatcher extends NonBatchingBatcher { - public TestingBatcher(SQLExceptionHelper exceptionHelper, int jdbcBatchSize) { - super( exceptionHelper ); + public static class TestingBatch extends NonBatchingBatch { + public TestingBatch(Object key, SQLStatementLogger statementLogger, SQLExceptionHelper exceptionHelper, int jdbcBatchSize) { + super( key, statementLogger, exceptionHelper ); } } diff --git a/hibernate-core/src/test/resources/log4j.properties b/hibernate-core/src/test/resources/log4j.properties index a55e3d85fb..f8e9147f11 100644 --- a/hibernate-core/src/test/resources/log4j.properties +++ b/hibernate-core/src/test/resources/log4j.properties @@ -8,10 +8,11 @@ log4j.rootLogger=info, stdout log4j.logger.org.hibernate.test=info log4j.logger.org.hibernate.tool.hbm2ddl=debug +log4j.logger.org.hibernate.engine.jdbc.internal=trace log4j.logger.org.hibernate.engine.jdbc=trace log4j.logger.org.hibernate.hql.ast.QueryTranslatorImpl=trace log4j.logger.org.hibernate.hql.ast.HqlSqlWalker=trace log4j.logger.org.hibernate.hql.ast.SqlGenerator=trace log4j.logger.org.hibernate.hql.ast.AST=trace log4j.logger.org.hibernate.type.descriptor.sql.BasicBinder=trace -log4j.logger.org.hibernate.type.BasicTypeRegistry=trace \ No newline at end of file +log4j.logger.org.hibernate.type.BasicTypeRegistry=trace From 7d884f4bb693a5353bce47e649a696e4e02d92d4 Mon Sep 17 00:00:00 2001 From: dcarr Date: Tue, 14 Dec 2010 15:19:47 -0500 Subject: [PATCH 03/21] Enhance Ejb3XmlTest to try to persist an entity mapped using in the orm.xml --- .../test/annotations/xml/ejb3/Company.java | 10 +++++++++ .../annotations/xml/ejb3/Ejb3XmlTest.java | 14 +++++++++++- .../annotations/xml/ejb3/VicePresident.java | 6 +++++ .../test/annotations/xml/ejb3/orm4.xml | 22 +++++++++++++++++++ 4 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Company.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/VicePresident.java create mode 100644 hibernate-core/src/test/resources/org/hibernate/test/annotations/xml/ejb3/orm4.xml diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Company.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Company.java new file mode 100644 index 0000000000..95b0840acd --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Company.java @@ -0,0 +1,10 @@ +package org.hibernate.test.annotations.xml.ejb3; + +import java.util.Map; + +import javax.persistence.MapKeyClass; + +public class Company { + int id; + Map organization; +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTest.java index b5d04e1f18..0e3ce52c51 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTest.java @@ -67,6 +67,17 @@ public class Ejb3XmlTest extends TestCase { tx.rollback(); s.close(); } + + public void testMapKeyClass() throws Exception { + Session s = openSession(); + Transaction tx = s.beginTransaction(); + Company company = new Company(); + s.persist( company ); + s.flush(); + s.clear(); + tx.rollback(); + s.close(); + } protected Class[] getAnnotatedClasses() { return new Class[]{ @@ -83,7 +94,8 @@ public class Ejb3XmlTest extends TestCase { return new String[]{ "org/hibernate/test/annotations/xml/ejb3/orm.xml", "org/hibernate/test/annotations/xml/ejb3/orm2.xml", - "org/hibernate/test/annotations/xml/ejb3/orm3.xml" + "org/hibernate/test/annotations/xml/ejb3/orm3.xml", + "org/hibernate/test/annotations/xml/ejb3/orm4.xml" }; } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/VicePresident.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/VicePresident.java new file mode 100644 index 0000000000..c073b31401 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/VicePresident.java @@ -0,0 +1,6 @@ +package org.hibernate.test.annotations.xml.ejb3; + +public class VicePresident { + int id; + String name; +} diff --git a/hibernate-core/src/test/resources/org/hibernate/test/annotations/xml/ejb3/orm4.xml b/hibernate-core/src/test/resources/org/hibernate/test/annotations/xml/ejb3/orm4.xml new file mode 100644 index 0000000000..9623851f6c --- /dev/null +++ b/hibernate-core/src/test/resources/org/hibernate/test/annotations/xml/ejb3/orm4.xml @@ -0,0 +1,22 @@ + + + + org.hibernate.test.annotations.xml.ejb3 + + + + + + + + + + + + + + + \ No newline at end of file From 363aa25c55f73834ee03d98c5b125dce6b2954b2 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 14 Dec 2010 16:00:39 -0500 Subject: [PATCH 04/21] Add support for map-key-class in orm.xml --- .../JPAOverridenAnnotationReader.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverridenAnnotationReader.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverridenAnnotationReader.java index 7977ee200f..44a5e667ac 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverridenAnnotationReader.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverridenAnnotationReader.java @@ -77,6 +77,7 @@ import javax.persistence.Lob; import javax.persistence.ManyToMany; import javax.persistence.ManyToOne; import javax.persistence.MapKey; +import javax.persistence.MapKeyClass; import javax.persistence.MappedSuperclass; import javax.persistence.NamedNativeQueries; import javax.persistence.NamedNativeQuery; @@ -196,6 +197,7 @@ public class JPAOverridenAnnotationReader implements AnnotationReader { annotationToXml.put( JoinColumn.class, "join-column" ); annotationToXml.put( JoinColumns.class, "join-column" ); annotationToXml.put( MapKey.class, "map-key" ); + annotationToXml.put( MapKeyClass.class, "map-key-class" ); annotationToXml.put( OrderBy.class, "order-by" ); annotationToXml.put( EntityListeners.class, "entity-listeners" ); annotationToXml.put( PrePersist.class, "pre-persist" ); @@ -661,6 +663,7 @@ public class JPAOverridenAnnotationReader implements AnnotationReader { copyStringAttribute( ad, element, "mapped-by", false ); getOrderBy( annotationList, element ); getMapKey( annotationList, element ); + getMapKeyClass( annotationList, element, defaults ); annotationList.add( AnnotationFactory.create( ad ) ); getAccessType( annotationList, element ); } @@ -824,6 +827,31 @@ public class JPAOverridenAnnotationReader implements AnnotationReader { annotationList.add( AnnotationFactory.create( ad ) ); } } + + private void getMapKeyClass(List annotationList, Element element, XMLContext.Default defaults) { + String nodeName = "map-key-class"; + Element subelement = element != null ? element.element( nodeName ) : null; + if ( subelement != null ) { + String mapKeyClassName = subelement.attributeValue( "class" ); + AnnotationDescriptor ad = new AnnotationDescriptor( MapKeyClass.class ); + if ( StringHelper.isNotEmpty( mapKeyClassName ) ) { + Class clazz; + try { + clazz = ReflectHelper.classForName( + XMLContext.buildSafeClassName( mapKeyClassName, defaults ), + this.getClass() + ); + } + catch (ClassNotFoundException e) { + throw new AnnotationException( + "Unable to find " + element.getPath() + " " + nodeName + ": " + mapKeyClassName, e + ); + } + ad.setValue( "value", clazz ); + } + annotationList.add( AnnotationFactory.create( ad ) ); + } + } private void buildJoinColumns(List annotationList, Element element) { JoinColumn[] joinColumns = getJoinColumns( element, false ); From 13f25fe72fe42b54fec478bc45ed3fe3fdce4fcc Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 15 Dec 2010 09:53:54 -0500 Subject: [PATCH 05/21] Enhance the test to cover additional mapping elements, and implement support for them. --- .../JPAOverridenAnnotationReader.java | 142 +++++++++++++++--- .../test/annotations/xml/ejb3/Company.java | 16 +- .../annotations/xml/ejb3/Ejb3XmlTest.java | 23 ++- .../test/annotations/xml/ejb3/orm4.xml | 8 + 4 files changed, 167 insertions(+), 22 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverridenAnnotationReader.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverridenAnnotationReader.java index 44a5e667ac..3aba222491 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverridenAnnotationReader.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverridenAnnotationReader.java @@ -47,6 +47,7 @@ import javax.persistence.AttributeOverride; import javax.persistence.AttributeOverrides; import javax.persistence.Basic; import javax.persistence.CascadeType; +import javax.persistence.CollectionTable; import javax.persistence.Column; import javax.persistence.ColumnResult; import javax.persistence.DiscriminatorColumn; @@ -78,6 +79,11 @@ import javax.persistence.ManyToMany; import javax.persistence.ManyToOne; import javax.persistence.MapKey; import javax.persistence.MapKeyClass; +import javax.persistence.MapKeyColumn; +import javax.persistence.MapKeyEnumerated; +import javax.persistence.MapKeyJoinColumn; +import javax.persistence.MapKeyJoinColumns; +import javax.persistence.MapKeyTemporal; import javax.persistence.MappedSuperclass; import javax.persistence.NamedNativeQueries; import javax.persistence.NamedNativeQuery; @@ -86,6 +92,7 @@ import javax.persistence.NamedQuery; import javax.persistence.OneToMany; import javax.persistence.OneToOne; import javax.persistence.OrderBy; +import javax.persistence.OrderColumn; import javax.persistence.PostLoad; import javax.persistence.PostPersist; import javax.persistence.PostRemove; @@ -113,6 +120,7 @@ import javax.persistence.ElementCollection; import org.dom4j.Attribute; import org.dom4j.Element; import org.hibernate.AnnotationException; +import org.hibernate.annotations.Cascade; import org.hibernate.annotations.CollectionOfElements; import org.hibernate.annotations.Columns; import org.hibernate.annotations.common.annotationfactory.AnnotationDescriptor; @@ -196,9 +204,16 @@ public class JPAOverridenAnnotationReader implements AnnotationReader { annotationToXml.put( JoinTable.class, "join-table" ); annotationToXml.put( JoinColumn.class, "join-column" ); annotationToXml.put( JoinColumns.class, "join-column" ); + annotationToXml.put( CollectionTable.class, "collection-table" ); annotationToXml.put( MapKey.class, "map-key" ); annotationToXml.put( MapKeyClass.class, "map-key-class" ); + annotationToXml.put( MapKeyTemporal.class, "map-key-temporal" ); + annotationToXml.put( MapKeyEnumerated.class, "map-key-enumerated" ); + annotationToXml.put( MapKeyColumn.class, "map-key-column" ); + annotationToXml.put( MapKeyJoinColumn.class, "map-key-join-column" ); + annotationToXml.put( MapKeyJoinColumns.class, "map-key-join-column" ); annotationToXml.put( OrderBy.class, "order-by" ); + annotationToXml.put( OrderColumn.class, "order-column" ); annotationToXml.put( EntityListeners.class, "entity-listeners" ); annotationToXml.put( PrePersist.class, "pre-persist" ); annotationToXml.put( PreRemove.class, "pre-remove" ); @@ -660,10 +675,17 @@ public class JPAOverridenAnnotationReader implements AnnotationReader { Annotation annotation = getPrimaryKeyJoinColumns( element, defaults ); addIfNotNull( annotationList, annotation ); copyBooleanAttribute( ad, element, "optional" ); + copyBooleanAttribute( ad, element, "orphan-removal" ); copyStringAttribute( ad, element, "mapped-by", false ); getOrderBy( annotationList, element ); + //TODO: support order-column getMapKey( annotationList, element ); getMapKeyClass( annotationList, element, defaults ); + //TODO: support map-key-temporal + //TODO: support map-key-enumerated + //TODO: support map-key-attribute-override + getMapKeyColumn(annotationList, element); + //TODO: support map-key-join-column annotationList.add( AnnotationFactory.create( ad ) ); getAccessType( annotationList, element ); } @@ -684,8 +706,22 @@ public class JPAOverridenAnnotationReader implements AnnotationReader { addIfNotNull( annotationList, annotation ); annotation = getJavaAnnotation( MapKey.class ); addIfNotNull( annotationList, annotation ); + annotation = getJavaAnnotation( MapKeyClass.class ); + addIfNotNull( annotationList, annotation ); + annotation = getJavaAnnotation( MapKeyTemporal.class ); + addIfNotNull( annotationList, annotation ); + annotation = getJavaAnnotation( MapKeyEnumerated.class ); + addIfNotNull( annotationList, annotation ); + annotation = getJavaAnnotation( MapKeyColumn.class ); + addIfNotNull( annotationList, annotation ); + annotation = getJavaAnnotation( MapKeyJoinColumn.class ); + addIfNotNull( annotationList, annotation ); + annotation = getJavaAnnotation( MapKeyJoinColumns.class ); + addIfNotNull( annotationList, annotation ); annotation = getJavaAnnotation( OrderBy.class ); addIfNotNull( annotationList, annotation ); + annotation = getJavaAnnotation( OrderColumn.class ); + addIfNotNull( annotationList, annotation ); annotation = getJavaAnnotation( AttributeOverride.class ); addIfNotNull( annotationList, annotation ); annotation = getJavaAnnotation( AttributeOverrides.class ); @@ -704,21 +740,37 @@ public class JPAOverridenAnnotationReader implements AnnotationReader { addIfNotNull( annotationList, annotation ); annotation = getJavaAnnotation( Columns.class ); addIfNotNull( annotationList, annotation ); + annotation = getJavaAnnotation( Cascade.class ); + addIfNotNull( annotationList, annotation ); } else if ( isJavaAnnotationPresent( ElementCollection.class ) ) { //JPA2 annotation = overridesDefaultsInJoinTable( getJavaAnnotation( ElementCollection.class ), defaults ); addIfNotNull( annotationList, annotation ); - annotation = getJavaAnnotation( JoinColumn.class ); + annotation = getJavaAnnotation( OrderBy.class ); addIfNotNull( annotationList, annotation ); - annotation = getJavaAnnotation( JoinColumns.class ); - addIfNotNull( annotationList, annotation ); - annotation = getJavaAnnotation( PrimaryKeyJoinColumn.class ); - addIfNotNull( annotationList, annotation ); - annotation = getJavaAnnotation( PrimaryKeyJoinColumns.class ); + annotation = getJavaAnnotation( OrderColumn.class ); addIfNotNull( annotationList, annotation ); annotation = getJavaAnnotation( MapKey.class ); addIfNotNull( annotationList, annotation ); - annotation = getJavaAnnotation( OrderBy.class ); + annotation = getJavaAnnotation( MapKeyClass.class ); + addIfNotNull( annotationList, annotation ); + annotation = getJavaAnnotation( MapKeyTemporal.class ); + addIfNotNull( annotationList, annotation ); + annotation = getJavaAnnotation( MapKeyEnumerated.class ); + addIfNotNull( annotationList, annotation ); + annotation = getJavaAnnotation( MapKeyColumn.class ); + addIfNotNull( annotationList, annotation ); + annotation = getJavaAnnotation( MapKeyJoinColumn.class ); + addIfNotNull( annotationList, annotation ); + annotation = getJavaAnnotation( MapKeyJoinColumns.class ); + addIfNotNull( annotationList, annotation ); + annotation = getJavaAnnotation( Column.class ); + addIfNotNull( annotationList, annotation ); + annotation = getJavaAnnotation( Temporal.class ); + addIfNotNull( annotationList, annotation ); + annotation = getJavaAnnotation( Enumerated.class ); + addIfNotNull( annotationList, annotation ); + annotation = getJavaAnnotation( Lob.class ); addIfNotNull( annotationList, annotation ); annotation = getJavaAnnotation( AttributeOverride.class ); addIfNotNull( annotationList, annotation ); @@ -728,15 +780,7 @@ public class JPAOverridenAnnotationReader implements AnnotationReader { addIfNotNull( annotationList, annotation ); annotation = getJavaAnnotation( AssociationOverrides.class ); addIfNotNull( annotationList, annotation ); - annotation = getJavaAnnotation( Lob.class ); - addIfNotNull( annotationList, annotation ); - annotation = getJavaAnnotation( Enumerated.class ); - addIfNotNull( annotationList, annotation ); - annotation = getJavaAnnotation( Temporal.class ); - addIfNotNull( annotationList, annotation ); - annotation = getJavaAnnotation( Column.class ); - addIfNotNull( annotationList, annotation ); - annotation = getJavaAnnotation( Columns.class ); + annotation = getJavaAnnotation( CollectionTable.class ); addIfNotNull( annotationList, annotation ); } else if ( isJavaAnnotationPresent( CollectionOfElements.class ) ) { //legacy Hibernate @@ -795,19 +839,37 @@ public class JPAOverridenAnnotationReader implements AnnotationReader { } } - // TODO: Complete parsing of all element-collection related xml private void getElementCollection(List annotationList, XMLContext.Default defaults) { for ( Element element : elementsForProperty ) { if ( "element-collection".equals( element.getName() ) ) { AnnotationDescriptor ad = new AnnotationDescriptor( ElementCollection.class ); addTargetClass( element, ad, "target-class", defaults ); + getFetchType( ad, element ); + getOrderBy( annotationList, element ); + //TODO: support order-column + getMapKey( annotationList, element ); + getMapKeyClass( annotationList, element, defaults ); + //TODO: support map-key-temporal + //TODO: support map-key-enumerated + //TODO: support map-key-attribute-override + getMapKeyColumn(annotationList, element); + //TODO: support map-key-join-column + Annotation annotation = getColumn(element.element( "column" ), false, element); + addIfNotNull(annotationList, annotation); + getTemporal(annotationList, element); + getEnumerated(annotationList, element); + getLob(annotationList, element); + annotation = getAttributeOverrides( element, defaults ); + addIfNotNull( annotationList, annotation ); + annotation = getAssociationOverrides( element, defaults ); + addIfNotNull( annotationList, annotation ); + getCollectionTable(annotationList, element, defaults); annotationList.add( AnnotationFactory.create( ad ) ); - getAccessType( annotationList, element ); } } } - + private void getOrderBy(List annotationList, Element element) { Element subelement = element != null ? element.element( "order-by" ) : null; if ( subelement != null ) { @@ -828,6 +890,24 @@ public class JPAOverridenAnnotationReader implements AnnotationReader { } } + private void getMapKeyColumn(List annotationList, Element element) { + Element subelement = element != null ? element.element( "map-key-column" ) : null; + if ( subelement != null ) { + AnnotationDescriptor ad = new AnnotationDescriptor( MapKeyColumn.class ); + copyStringAttribute( ad, subelement, "name", false ); + copyBooleanAttribute( ad, subelement, "unique" ); + copyBooleanAttribute( ad, subelement, "nullable" ); + copyBooleanAttribute( ad, subelement, "insertable" ); + copyBooleanAttribute( ad, subelement, "updatable" ); + copyStringAttribute( ad, subelement, "column-definition", false ); + copyStringAttribute( ad, subelement, "table", false ); + copyIntegerAttribute( ad, subelement, "length" ); + copyIntegerAttribute( ad, subelement, "precision" ); + copyIntegerAttribute( ad, subelement, "scale" ); + annotationList.add( AnnotationFactory.create( ad ) ); + } + } + private void getMapKeyClass(List annotationList, Element element, XMLContext.Default defaults) { String nodeName = "map-key-class"; Element subelement = element != null ? element.element( nodeName ) : null; @@ -2064,6 +2144,30 @@ public class JPAOverridenAnnotationReader implements AnnotationReader { return null; } } + + private void getCollectionTable(List annotationList, Element element, XMLContext.Default defaults) { + Element subelement = element != null ? element.element( "collection-table" ) : null; + if ( subelement != null ) { + AnnotationDescriptor annotation = new AnnotationDescriptor( CollectionTable.class ); + copyStringAttribute( annotation, subelement, "name", false ); + copyStringAttribute( annotation, subelement, "catalog", false ); + if ( StringHelper.isNotEmpty( defaults.getCatalog() ) + && StringHelper.isEmpty( (String) annotation.valueOf( "catalog" ) ) ) { + annotation.setValue( "catalog", defaults.getCatalog() ); + } + copyStringAttribute( annotation, subelement, "schema", false ); + if ( StringHelper.isNotEmpty( defaults.getSchema() ) + && StringHelper.isEmpty( (String) annotation.valueOf( "schema" ) ) ) { + annotation.setValue( "schema", defaults.getSchema() ); + } + JoinColumn[] joinColumns = getJoinColumns( subelement, false ); + if ( joinColumns.length > 0 ) { + annotation.setValue( "joinColumns", joinColumns ); + } + buildUniqueConstraints( annotation, subelement ); + annotationList.add( AnnotationFactory.create( annotation ) ); + } + } private void overridesDefaultInSecondaryTable( SecondaryTable secTableAnn, XMLContext.Default defaults, List secondaryTables diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Company.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Company.java index 95b0840acd..1e00d73f00 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Company.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Company.java @@ -1,10 +1,22 @@ package org.hibernate.test.annotations.xml.ejb3; +import java.util.HashMap; import java.util.Map; -import javax.persistence.MapKeyClass; +//import javax.persistence.CollectionTable; +//import javax.persistence.Column; +//import javax.persistence.ElementCollection; +//import javax.persistence.JoinColumn; +//import javax.persistence.MapKeyClass; +//import javax.persistence.MapKeyColumn; public class Company { int id; - Map organization; + Map organization = new HashMap(); +// @ElementCollection(targetClass=String.class) +// @MapKeyClass(String.class) +// @MapKeyColumn(name="room_number") +// @Column(name="phone_extension") +// @CollectionTable(name="phone_extension_lookup", joinColumns={@JoinColumn(name="company_id", referencedColumnName="id")}) + Map conferenceRoomExtensions = new HashMap(); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTest.java index 0e3ce52c51..370b8710db 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTest.java @@ -3,12 +3,18 @@ package org.hibernate.test.annotations.xml.ejb3; import java.util.Date; import java.util.List; +import java.util.Map; import org.hibernate.Session; +import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.dialect.PostgreSQLDialect; +import org.hibernate.metadata.ClassMetadata; +import org.hibernate.metadata.CollectionMetadata; +import org.hibernate.persister.collection.BasicCollectionPersister; import org.hibernate.test.annotations.TestCase; import org.hibernate.testing.junit.SkipForDialect; +import org.hibernate.tuple.entity.EntityMetamodel; /** * @author Emmanuel Bernard @@ -68,13 +74,28 @@ public class Ejb3XmlTest extends TestCase { s.close(); } - public void testMapKeyClass() throws Exception { + public void testMapXMLSupport() throws Exception { Session s = openSession(); + SessionFactory sf = s.getSessionFactory(); Transaction tx = s.beginTransaction(); + + // Verify that we can persist an object with a couple Map mappings + VicePresident vpSales = new VicePresident(); + vpSales.name = "Dwight"; Company company = new Company(); + company.conferenceRoomExtensions.put("8932", "x1234"); + company.organization.put("sales", vpSales); s.persist( company ); s.flush(); s.clear(); + + // For the element-collection, check that the orm.xml entries are honored. + // This includes: map-key-column/column/collection-table/join-column + BasicCollectionPersister confRoomMeta = (BasicCollectionPersister) sf.getCollectionMetadata(Company.class.getName() + ".conferenceRoomExtensions"); + assertEquals("company_id", confRoomMeta.getKeyColumnNames()[0]); + assertEquals("phone_extension", confRoomMeta.getElementColumnNames()[0]); + assertEquals("room_number", confRoomMeta.getIndexColumnNames()[0]); + assertEquals("phone_extension_lookup", confRoomMeta.getTableName()); tx.rollback(); s.close(); } diff --git a/hibernate-core/src/test/resources/org/hibernate/test/annotations/xml/ejb3/orm4.xml b/hibernate-core/src/test/resources/org/hibernate/test/annotations/xml/ejb3/orm4.xml index 9623851f6c..486bd79f67 100644 --- a/hibernate-core/src/test/resources/org/hibernate/test/annotations/xml/ejb3/orm4.xml +++ b/hibernate-core/src/test/resources/org/hibernate/test/annotations/xml/ejb3/orm4.xml @@ -11,6 +11,14 @@ + + + + + + + + From 5cbffa051db3ae52b5e06a6bc8515c503d57375e Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 15 Dec 2010 11:55:52 -0500 Subject: [PATCH 06/21] Tidy up the changeset a little. --- .../JPAOverridenAnnotationReader.java | 120 +++++++++--------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverridenAnnotationReader.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverridenAnnotationReader.java index 3aba222491..53c8805d2f 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverridenAnnotationReader.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverridenAnnotationReader.java @@ -204,16 +204,8 @@ public class JPAOverridenAnnotationReader implements AnnotationReader { annotationToXml.put( JoinTable.class, "join-table" ); annotationToXml.put( JoinColumn.class, "join-column" ); annotationToXml.put( JoinColumns.class, "join-column" ); - annotationToXml.put( CollectionTable.class, "collection-table" ); annotationToXml.put( MapKey.class, "map-key" ); - annotationToXml.put( MapKeyClass.class, "map-key-class" ); - annotationToXml.put( MapKeyTemporal.class, "map-key-temporal" ); - annotationToXml.put( MapKeyEnumerated.class, "map-key-enumerated" ); - annotationToXml.put( MapKeyColumn.class, "map-key-column" ); - annotationToXml.put( MapKeyJoinColumn.class, "map-key-join-column" ); - annotationToXml.put( MapKeyJoinColumns.class, "map-key-join-column" ); annotationToXml.put( OrderBy.class, "order-by" ); - annotationToXml.put( OrderColumn.class, "order-column" ); annotationToXml.put( EntityListeners.class, "entity-listeners" ); annotationToXml.put( PrePersist.class, "pre-persist" ); annotationToXml.put( PreRemove.class, "pre-remove" ); @@ -222,6 +214,14 @@ public class JPAOverridenAnnotationReader implements AnnotationReader { annotationToXml.put( PostRemove.class, "post-remove" ); annotationToXml.put( PostUpdate.class, "post-update" ); annotationToXml.put( PostLoad.class, "post-load" ); + annotationToXml.put( CollectionTable.class, "collection-table" ); + annotationToXml.put( MapKeyClass.class, "map-key-class" ); + annotationToXml.put( MapKeyTemporal.class, "map-key-temporal" ); + annotationToXml.put( MapKeyEnumerated.class, "map-key-enumerated" ); + annotationToXml.put( MapKeyColumn.class, "map-key-column" ); + annotationToXml.put( MapKeyJoinColumn.class, "map-key-join-column" ); + annotationToXml.put( MapKeyJoinColumns.class, "map-key-join-column" ); + annotationToXml.put( OrderColumn.class, "order-column" ); } private XMLContext xmlContext; @@ -678,13 +678,13 @@ public class JPAOverridenAnnotationReader implements AnnotationReader { copyBooleanAttribute( ad, element, "orphan-removal" ); copyStringAttribute( ad, element, "mapped-by", false ); getOrderBy( annotationList, element ); - //TODO: support order-column getMapKey( annotationList, element ); getMapKeyClass( annotationList, element, defaults ); + getMapKeyColumn(annotationList, element); + //TODO: support order-column //TODO: support map-key-temporal //TODO: support map-key-enumerated //TODO: support map-key-attribute-override - getMapKeyColumn(annotationList, element); //TODO: support map-key-join-column annotationList.add( AnnotationFactory.create( ad ) ); getAccessType( annotationList, element ); @@ -706,22 +706,8 @@ public class JPAOverridenAnnotationReader implements AnnotationReader { addIfNotNull( annotationList, annotation ); annotation = getJavaAnnotation( MapKey.class ); addIfNotNull( annotationList, annotation ); - annotation = getJavaAnnotation( MapKeyClass.class ); - addIfNotNull( annotationList, annotation ); - annotation = getJavaAnnotation( MapKeyTemporal.class ); - addIfNotNull( annotationList, annotation ); - annotation = getJavaAnnotation( MapKeyEnumerated.class ); - addIfNotNull( annotationList, annotation ); - annotation = getJavaAnnotation( MapKeyColumn.class ); - addIfNotNull( annotationList, annotation ); - annotation = getJavaAnnotation( MapKeyJoinColumn.class ); - addIfNotNull( annotationList, annotation ); - annotation = getJavaAnnotation( MapKeyJoinColumns.class ); - addIfNotNull( annotationList, annotation ); annotation = getJavaAnnotation( OrderBy.class ); addIfNotNull( annotationList, annotation ); - annotation = getJavaAnnotation( OrderColumn.class ); - addIfNotNull( annotationList, annotation ); annotation = getJavaAnnotation( AttributeOverride.class ); addIfNotNull( annotationList, annotation ); annotation = getJavaAnnotation( AttributeOverrides.class ); @@ -740,17 +726,41 @@ public class JPAOverridenAnnotationReader implements AnnotationReader { addIfNotNull( annotationList, annotation ); annotation = getJavaAnnotation( Columns.class ); addIfNotNull( annotationList, annotation ); + annotation = getJavaAnnotation( MapKeyClass.class ); + addIfNotNull( annotationList, annotation ); + annotation = getJavaAnnotation( MapKeyTemporal.class ); + addIfNotNull( annotationList, annotation ); + annotation = getJavaAnnotation( MapKeyEnumerated.class ); + addIfNotNull( annotationList, annotation ); + annotation = getJavaAnnotation( MapKeyColumn.class ); + addIfNotNull( annotationList, annotation ); + annotation = getJavaAnnotation( MapKeyJoinColumn.class ); + addIfNotNull( annotationList, annotation ); + annotation = getJavaAnnotation( MapKeyJoinColumns.class ); + addIfNotNull( annotationList, annotation ); + annotation = getJavaAnnotation( OrderColumn.class ); + addIfNotNull( annotationList, annotation ); annotation = getJavaAnnotation( Cascade.class ); addIfNotNull( annotationList, annotation ); } else if ( isJavaAnnotationPresent( ElementCollection.class ) ) { //JPA2 annotation = overridesDefaultsInJoinTable( getJavaAnnotation( ElementCollection.class ), defaults ); addIfNotNull( annotationList, annotation ); + annotation = getJavaAnnotation( MapKey.class ); + addIfNotNull( annotationList, annotation ); annotation = getJavaAnnotation( OrderBy.class ); addIfNotNull( annotationList, annotation ); - annotation = getJavaAnnotation( OrderColumn.class ); + annotation = getJavaAnnotation( AttributeOverride.class ); addIfNotNull( annotationList, annotation ); - annotation = getJavaAnnotation( MapKey.class ); + annotation = getJavaAnnotation( AttributeOverrides.class ); + addIfNotNull( annotationList, annotation ); + annotation = getJavaAnnotation( AssociationOverride.class ); + addIfNotNull( annotationList, annotation ); + annotation = getJavaAnnotation( AssociationOverrides.class ); + addIfNotNull( annotationList, annotation ); + annotation = getJavaAnnotation( Lob.class ); + addIfNotNull( annotationList, annotation ); + annotation = getJavaAnnotation( OrderColumn.class ); addIfNotNull( annotationList, annotation ); annotation = getJavaAnnotation( MapKeyClass.class ); addIfNotNull( annotationList, annotation ); @@ -770,16 +780,6 @@ public class JPAOverridenAnnotationReader implements AnnotationReader { addIfNotNull( annotationList, annotation ); annotation = getJavaAnnotation( Enumerated.class ); addIfNotNull( annotationList, annotation ); - annotation = getJavaAnnotation( Lob.class ); - addIfNotNull( annotationList, annotation ); - annotation = getJavaAnnotation( AttributeOverride.class ); - addIfNotNull( annotationList, annotation ); - annotation = getJavaAnnotation( AttributeOverrides.class ); - addIfNotNull( annotationList, annotation ); - annotation = getJavaAnnotation( AssociationOverride.class ); - addIfNotNull( annotationList, annotation ); - annotation = getJavaAnnotation( AssociationOverrides.class ); - addIfNotNull( annotationList, annotation ); annotation = getJavaAnnotation( CollectionTable.class ); addIfNotNull( annotationList, annotation ); } @@ -932,6 +932,30 @@ public class JPAOverridenAnnotationReader implements AnnotationReader { annotationList.add( AnnotationFactory.create( ad ) ); } } + + private void getCollectionTable(List annotationList, Element element, XMLContext.Default defaults) { + Element subelement = element != null ? element.element( "collection-table" ) : null; + if ( subelement != null ) { + AnnotationDescriptor annotation = new AnnotationDescriptor( CollectionTable.class ); + copyStringAttribute( annotation, subelement, "name", false ); + copyStringAttribute( annotation, subelement, "catalog", false ); + if ( StringHelper.isNotEmpty( defaults.getCatalog() ) + && StringHelper.isEmpty( (String) annotation.valueOf( "catalog" ) ) ) { + annotation.setValue( "catalog", defaults.getCatalog() ); + } + copyStringAttribute( annotation, subelement, "schema", false ); + if ( StringHelper.isNotEmpty( defaults.getSchema() ) + && StringHelper.isEmpty( (String) annotation.valueOf( "schema" ) ) ) { + annotation.setValue( "schema", defaults.getSchema() ); + } + JoinColumn[] joinColumns = getJoinColumns( subelement, false ); + if ( joinColumns.length > 0 ) { + annotation.setValue( "joinColumns", joinColumns ); + } + buildUniqueConstraints( annotation, subelement ); + annotationList.add( AnnotationFactory.create( annotation ) ); + } + } private void buildJoinColumns(List annotationList, Element element) { JoinColumn[] joinColumns = getJoinColumns( element, false ); @@ -2144,30 +2168,6 @@ public class JPAOverridenAnnotationReader implements AnnotationReader { return null; } } - - private void getCollectionTable(List annotationList, Element element, XMLContext.Default defaults) { - Element subelement = element != null ? element.element( "collection-table" ) : null; - if ( subelement != null ) { - AnnotationDescriptor annotation = new AnnotationDescriptor( CollectionTable.class ); - copyStringAttribute( annotation, subelement, "name", false ); - copyStringAttribute( annotation, subelement, "catalog", false ); - if ( StringHelper.isNotEmpty( defaults.getCatalog() ) - && StringHelper.isEmpty( (String) annotation.valueOf( "catalog" ) ) ) { - annotation.setValue( "catalog", defaults.getCatalog() ); - } - copyStringAttribute( annotation, subelement, "schema", false ); - if ( StringHelper.isNotEmpty( defaults.getSchema() ) - && StringHelper.isEmpty( (String) annotation.valueOf( "schema" ) ) ) { - annotation.setValue( "schema", defaults.getSchema() ); - } - JoinColumn[] joinColumns = getJoinColumns( subelement, false ); - if ( joinColumns.length > 0 ) { - annotation.setValue( "joinColumns", joinColumns ); - } - buildUniqueConstraints( annotation, subelement ); - annotationList.add( AnnotationFactory.create( annotation ) ); - } - } private void overridesDefaultInSecondaryTable( SecondaryTable secTableAnn, XMLContext.Default defaults, List secondaryTables From 48f5b51ca73892908cb8b210fc46883f2acee6d7 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 15 Dec 2010 12:45:58 -0500 Subject: [PATCH 07/21] More changeset cleanup. --- .../reflection/JPAOverridenAnnotationReader.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverridenAnnotationReader.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverridenAnnotationReader.java index 53c8805d2f..9d7cb4f4c8 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverridenAnnotationReader.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverridenAnnotationReader.java @@ -760,6 +760,12 @@ public class JPAOverridenAnnotationReader implements AnnotationReader { addIfNotNull( annotationList, annotation ); annotation = getJavaAnnotation( Lob.class ); addIfNotNull( annotationList, annotation ); + annotation = getJavaAnnotation( Enumerated.class ); + addIfNotNull( annotationList, annotation ); + annotation = getJavaAnnotation( Temporal.class ); + addIfNotNull( annotationList, annotation ); + annotation = getJavaAnnotation( Column.class ); + addIfNotNull( annotationList, annotation ); annotation = getJavaAnnotation( OrderColumn.class ); addIfNotNull( annotationList, annotation ); annotation = getJavaAnnotation( MapKeyClass.class ); @@ -774,12 +780,6 @@ public class JPAOverridenAnnotationReader implements AnnotationReader { addIfNotNull( annotationList, annotation ); annotation = getJavaAnnotation( MapKeyJoinColumns.class ); addIfNotNull( annotationList, annotation ); - annotation = getJavaAnnotation( Column.class ); - addIfNotNull( annotationList, annotation ); - annotation = getJavaAnnotation( Temporal.class ); - addIfNotNull( annotationList, annotation ); - annotation = getJavaAnnotation( Enumerated.class ); - addIfNotNull( annotationList, annotation ); annotation = getJavaAnnotation( CollectionTable.class ); addIfNotNull( annotationList, annotation ); } @@ -839,6 +839,7 @@ public class JPAOverridenAnnotationReader implements AnnotationReader { } } + // TODO: Complete parsing of all element-collection related xml private void getElementCollection(List annotationList, XMLContext.Default defaults) { for ( Element element : elementsForProperty ) { if ( "element-collection".equals( element.getName() ) ) { From 66f7018b9debcb6b43fe37263fd44a1d1b435be5 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 15 Dec 2010 12:50:20 -0500 Subject: [PATCH 08/21] Remove extraneous comments from test entity. --- .../hibernate/test/annotations/xml/ejb3/Company.java | 12 ------------ .../org/hibernate/test/annotations/xml/ejb3/orm4.xml | 2 +- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Company.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Company.java index 1e00d73f00..f42584b5e8 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Company.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Company.java @@ -3,20 +3,8 @@ package org.hibernate.test.annotations.xml.ejb3; import java.util.HashMap; import java.util.Map; -//import javax.persistence.CollectionTable; -//import javax.persistence.Column; -//import javax.persistence.ElementCollection; -//import javax.persistence.JoinColumn; -//import javax.persistence.MapKeyClass; -//import javax.persistence.MapKeyColumn; - public class Company { int id; Map organization = new HashMap(); -// @ElementCollection(targetClass=String.class) -// @MapKeyClass(String.class) -// @MapKeyColumn(name="room_number") -// @Column(name="phone_extension") -// @CollectionTable(name="phone_extension_lookup", joinColumns={@JoinColumn(name="company_id", referencedColumnName="id")}) Map conferenceRoomExtensions = new HashMap(); } diff --git a/hibernate-core/src/test/resources/org/hibernate/test/annotations/xml/ejb3/orm4.xml b/hibernate-core/src/test/resources/org/hibernate/test/annotations/xml/ejb3/orm4.xml index 486bd79f67..c42cff5f09 100644 --- a/hibernate-core/src/test/resources/org/hibernate/test/annotations/xml/ejb3/orm4.xml +++ b/hibernate-core/src/test/resources/org/hibernate/test/annotations/xml/ejb3/orm4.xml @@ -27,4 +27,4 @@ - \ No newline at end of file + From e5da3bf14953c55ba12691d6c30dd292e8c4daac Mon Sep 17 00:00:00 2001 From: Hardy Ferentschik Date: Thu, 16 Dec 2010 15:26:50 +0100 Subject: [PATCH 09/21] HHH-5794 Adding/Updating license headers --- .../JPAOverridenAnnotationReader.java | 6 +- .../test/annotations/xml/ejb3/Company.java | 44 ++- .../annotations/xml/ejb3/Ejb3XmlTest.java | 266 ++++++++++-------- .../annotations/xml/ejb3/VicePresident.java | 36 ++- .../test/annotations/xml/ejb3/orm4.xml | 84 ++++-- 5 files changed, 264 insertions(+), 172 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverridenAnnotationReader.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverridenAnnotationReader.java index 9d7cb4f4c8..c2467937f4 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverridenAnnotationReader.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverridenAnnotationReader.java @@ -22,8 +22,6 @@ * Boston, MA 02110-1301 USA */ -// $Id$ - package org.hibernate.cfg.annotations.reflection; import java.beans.Introspector; @@ -1349,7 +1347,7 @@ public class JPAOverridenAnnotationReader implements AnnotationReader { } private AssociationOverrides getAssociationOverrides(Element tree, XMLContext.Default defaults) { - List attributes = (List) buildAssociationOverrides( tree ); + List attributes = buildAssociationOverrides( tree ); if ( defaults.canUseJavaAnnotations() ) { AssociationOverride annotation = getJavaAnnotation( AssociationOverride.class ); addAssociationOverrideIfNeeded( annotation, attributes ); @@ -1565,7 +1563,7 @@ public class JPAOverridenAnnotationReader implements AnnotationReader { } private SqlResultSetMappings getSqlResultSetMappings(Element tree, XMLContext.Default defaults) { - List results = (List) buildSqlResultsetMappings( tree, defaults ); + List results = buildSqlResultsetMappings( tree, defaults ); if ( defaults.canUseJavaAnnotations() ) { SqlResultSetMapping annotation = getJavaAnnotation( SqlResultSetMapping.class ); addSqlResultsetMappingIfNeeded( annotation, results ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Company.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Company.java index f42584b5e8..20aae6ce29 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Company.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Company.java @@ -1,10 +1,34 @@ -package org.hibernate.test.annotations.xml.ejb3; - -import java.util.HashMap; -import java.util.Map; - -public class Company { - int id; - Map organization = new HashMap(); - Map conferenceRoomExtensions = new HashMap(); -} +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010 by Red Hat Inc and/or its affiliates or by + * third-party contributors as indicated by either @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.annotations.xml.ejb3; + +import java.util.HashMap; +import java.util.Map; + +public class Company { + int id; + Map organization = new HashMap(); + Map conferenceRoomExtensions = new HashMap(); +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTest.java index 370b8710db..1554f7bc62 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTest.java @@ -1,122 +1,144 @@ -//$Id$ -package org.hibernate.test.annotations.xml.ejb3; - -import java.util.Date; -import java.util.List; -import java.util.Map; - -import org.hibernate.Session; -import org.hibernate.SessionFactory; -import org.hibernate.Transaction; -import org.hibernate.dialect.PostgreSQLDialect; -import org.hibernate.metadata.ClassMetadata; -import org.hibernate.metadata.CollectionMetadata; -import org.hibernate.persister.collection.BasicCollectionPersister; -import org.hibernate.test.annotations.TestCase; -import org.hibernate.testing.junit.SkipForDialect; -import org.hibernate.tuple.entity.EntityMetamodel; - -/** - * @author Emmanuel Bernard - */ -public class Ejb3XmlTest extends TestCase { - @SkipForDialect(value = {PostgreSQLDialect.class}, comment = "postgresql jdbc driver does not implement the setQueryTimeout method") - public void testEjb3Xml() throws Exception { - Session s = openSession(); - Transaction tx = s.beginTransaction(); - CarModel model = new CarModel(); - model.setYear( new Date() ); - Manufacturer manufacturer = new Manufacturer(); - //s.persist( manufacturer ); - model.setManufacturer( manufacturer ); - manufacturer.getModels().add( model ); - s.persist( model ); - s.flush(); - s.clear(); - - model.setYear( new Date() ); - manufacturer = (Manufacturer) s.get( Manufacturer.class, manufacturer.getId() ); - List cars = s.getNamedQuery( "allModelsPerManufacturer" ) - .setParameter( "manufacturer", manufacturer ) - .list(); - assertEquals( 1, cars.size() ); - for ( Model car : cars ) { - assertNotNull( car.getManufacturer() ); - s.delete( manufacturer ); - s.delete( car ); - } - tx.rollback(); - s.close(); - } - - public void testXMLEntityHandled() throws Exception { - Session s = openSession(); - s.getTransaction().begin(); - Lighter l = new Lighter(); - l.name = "Blue"; - l.power = "400F"; - s.persist( l ); - s.flush(); - s.getTransaction().rollback(); - s.close(); - } - - public void testXmlDefaultOverriding() throws Exception { - Session s = openSession(); - Transaction tx = s.beginTransaction(); - Manufacturer manufacturer = new Manufacturer(); - s.persist( manufacturer ); - s.flush(); - s.clear(); - - assertEquals( 1, s.getNamedQuery( "manufacturer.findAll" ).list().size() ); - tx.rollback(); - s.close(); - } - - public void testMapXMLSupport() throws Exception { - Session s = openSession(); - SessionFactory sf = s.getSessionFactory(); - Transaction tx = s.beginTransaction(); - - // Verify that we can persist an object with a couple Map mappings - VicePresident vpSales = new VicePresident(); - vpSales.name = "Dwight"; - Company company = new Company(); - company.conferenceRoomExtensions.put("8932", "x1234"); - company.organization.put("sales", vpSales); - s.persist( company ); - s.flush(); - s.clear(); - - // For the element-collection, check that the orm.xml entries are honored. - // This includes: map-key-column/column/collection-table/join-column - BasicCollectionPersister confRoomMeta = (BasicCollectionPersister) sf.getCollectionMetadata(Company.class.getName() + ".conferenceRoomExtensions"); - assertEquals("company_id", confRoomMeta.getKeyColumnNames()[0]); - assertEquals("phone_extension", confRoomMeta.getElementColumnNames()[0]); - assertEquals("room_number", confRoomMeta.getIndexColumnNames()[0]); - assertEquals("phone_extension_lookup", confRoomMeta.getTableName()); - tx.rollback(); - s.close(); - } - - protected Class[] getAnnotatedClasses() { - return new Class[]{ - CarModel.class, - Manufacturer.class, - Model.class, - Light.class - //Lighter.class xml only entuty - }; - } - - @Override - protected String[] getXmlFiles() { - return new String[]{ - "org/hibernate/test/annotations/xml/ejb3/orm.xml", - "org/hibernate/test/annotations/xml/ejb3/orm2.xml", - "org/hibernate/test/annotations/xml/ejb3/orm3.xml", - "org/hibernate/test/annotations/xml/ejb3/orm4.xml" - }; - } -} +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010 by Red Hat Inc and/or its affiliates or by + * third-party contributors as indicated by either @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.annotations.xml.ejb3; + +import java.util.Date; +import java.util.List; + +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.Transaction; +import org.hibernate.dialect.PostgreSQLDialect; +import org.hibernate.persister.collection.BasicCollectionPersister; +import org.hibernate.test.annotations.TestCase; +import org.hibernate.testing.junit.SkipForDialect; + +/** + * @author Emmanuel Bernard + */ +public class Ejb3XmlTest extends TestCase { + @SkipForDialect(value = { PostgreSQLDialect.class }, + comment = "postgresql jdbc driver does not implement the setQueryTimeout method") + public void testEjb3Xml() throws Exception { + Session s = openSession(); + Transaction tx = s.beginTransaction(); + CarModel model = new CarModel(); + model.setYear( new Date() ); + Manufacturer manufacturer = new Manufacturer(); + //s.persist( manufacturer ); + model.setManufacturer( manufacturer ); + manufacturer.getModels().add( model ); + s.persist( model ); + s.flush(); + s.clear(); + + model.setYear( new Date() ); + manufacturer = (Manufacturer) s.get( Manufacturer.class, manufacturer.getId() ); + @SuppressWarnings("unchecked") + List cars = s.getNamedQuery( "allModelsPerManufacturer" ) + .setParameter( "manufacturer", manufacturer ) + .list(); + assertEquals( 1, cars.size() ); + for ( Model car : cars ) { + assertNotNull( car.getManufacturer() ); + s.delete( manufacturer ); + s.delete( car ); + } + tx.rollback(); + s.close(); + } + + public void testXMLEntityHandled() throws Exception { + Session s = openSession(); + s.getTransaction().begin(); + Lighter l = new Lighter(); + l.name = "Blue"; + l.power = "400F"; + s.persist( l ); + s.flush(); + s.getTransaction().rollback(); + s.close(); + } + + public void testXmlDefaultOverriding() throws Exception { + Session s = openSession(); + Transaction tx = s.beginTransaction(); + Manufacturer manufacturer = new Manufacturer(); + s.persist( manufacturer ); + s.flush(); + s.clear(); + + assertEquals( 1, s.getNamedQuery( "manufacturer.findAll" ).list().size() ); + tx.rollback(); + s.close(); + } + + @SuppressWarnings("unchecked") + public void testMapXMLSupport() throws Exception { + Session s = openSession(); + SessionFactory sf = s.getSessionFactory(); + Transaction tx = s.beginTransaction(); + + // Verify that we can persist an object with a couple Map mappings + VicePresident vpSales = new VicePresident(); + vpSales.name = "Dwight"; + Company company = new Company(); + company.conferenceRoomExtensions.put( "8932", "x1234" ); + company.organization.put( "sales", vpSales ); + s.persist( company ); + s.flush(); + s.clear(); + + // For the element-collection, check that the orm.xml entries are honored. + // This includes: map-key-column/column/collection-table/join-column + BasicCollectionPersister confRoomMeta = (BasicCollectionPersister) sf.getCollectionMetadata( Company.class.getName() + ".conferenceRoomExtensions" ); + assertEquals( "company_id", confRoomMeta.getKeyColumnNames()[0] ); + assertEquals( "phone_extension", confRoomMeta.getElementColumnNames()[0] ); + assertEquals( "room_number", confRoomMeta.getIndexColumnNames()[0] ); + assertEquals( "phone_extension_lookup", confRoomMeta.getTableName() ); + tx.rollback(); + s.close(); + } + + protected Class[] getAnnotatedClasses() { + return new Class[] { + CarModel.class, + Manufacturer.class, + Model.class, + Light.class + //Lighter.class xml only entuty + }; + } + + @Override + protected String[] getXmlFiles() { + return new String[] { + "org/hibernate/test/annotations/xml/ejb3/orm.xml", + "org/hibernate/test/annotations/xml/ejb3/orm2.xml", + "org/hibernate/test/annotations/xml/ejb3/orm3.xml", + "org/hibernate/test/annotations/xml/ejb3/orm4.xml" + }; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/VicePresident.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/VicePresident.java index c073b31401..c7266463a3 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/VicePresident.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/VicePresident.java @@ -1,6 +1,30 @@ -package org.hibernate.test.annotations.xml.ejb3; - -public class VicePresident { - int id; - String name; -} +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010 by Red Hat Inc and/or its affiliates or by + * third-party contributors as indicated by either @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.annotations.xml.ejb3; + +public class VicePresident { + int id; + String name; +} diff --git a/hibernate-core/src/test/resources/org/hibernate/test/annotations/xml/ejb3/orm4.xml b/hibernate-core/src/test/resources/org/hibernate/test/annotations/xml/ejb3/orm4.xml index c42cff5f09..f149d17bce 100644 --- a/hibernate-core/src/test/resources/org/hibernate/test/annotations/xml/ejb3/orm4.xml +++ b/hibernate-core/src/test/resources/org/hibernate/test/annotations/xml/ejb3/orm4.xml @@ -1,30 +1,54 @@ - - - - org.hibernate.test.annotations.xml.ejb3 - - - - - - - - - - - - - - - - - - - - - - - + + + + + + org.hibernate.test.annotations.xml.ejb3 + + + + + + + + + + + + + + + + + + + + + + + From 1f0c74cb5eaef450aa206876bd328eabbf6170a1 Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Thu, 16 Dec 2010 17:36:18 -0800 Subject: [PATCH 10/21] HHH-5778 : Wire in new batch code --- .../jdbc/batch/internal/BatchingBatch.java | 9 ++++ .../engine/jdbc/batch/spi/Batch.java | 7 +-- .../org/hibernate/test/batch/BatchTest.java | 47 +++++++++++++++++-- .../src/test/resources/log4j.properties | 3 +- 4 files changed, 57 insertions(+), 9 deletions(-) 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 f7c3b246a6..9dc1b27020 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 @@ -50,6 +50,11 @@ public class BatchingBatch extends AbstractBatchImpl { private static final Logger log = LoggerFactory.getLogger( BatchingBatch.class ); private final int batchSize; + + // 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; @@ -88,6 +93,10 @@ public class BatchingBatch extends AbstractBatchImpl { } 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(); 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 89ed9f39a3..7c99332100 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 @@ -52,15 +52,16 @@ public interface Batch { public void addObserver(BatchObserver observer); /** - * Get a statement which is part of the batch, creating if necessary (and storing for next time). + * Get a statement which is part of the batch. * * @param sql The SQL statement. - * @return The prepared statement instance, representing 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); /** - * Store a statement in the batch. + * Add a prepared statement to the batch. * * @param sql The SQL statement. */ diff --git a/hibernate-core/src/test/java/org/hibernate/test/batch/BatchTest.java b/hibernate-core/src/test/java/org/hibernate/test/batch/BatchTest.java index 4e4df6c734..2bb8158b79 100755 --- a/hibernate-core/src/test/java/org/hibernate/test/batch/BatchTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/batch/BatchTest.java @@ -10,6 +10,7 @@ import org.hibernate.ScrollMode; import org.hibernate.ScrollableResults; import org.hibernate.Session; import org.hibernate.Transaction; +import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.testing.junit.functional.FunctionalTestCase; import org.hibernate.testing.junit.functional.FunctionalTestClassTestSuite; import org.hibernate.cfg.Configuration; @@ -49,16 +50,37 @@ public class BatchTest extends FunctionalTestCase { final int N = 5000; //26 secs with batch flush, 26 without //final int N = 100000; //53 secs with batch flush, OOME without //final int N = 250000; //137 secs with batch flush, OOME without + int batchSize = ( ( SessionFactoryImplementor ) getSessions() ).getSettings().getJdbcBatchSize(); + doBatchInsertUpdate( N, batchSize ); + System.out.println( System.currentTimeMillis() - start ); + } + public void testBatchInsertUpdateSizeEqJdbcBatchSize() { + int batchSize = ( ( SessionFactoryImplementor ) getSessions() ).getSettings().getJdbcBatchSize(); + doBatchInsertUpdate( 50, batchSize ); + } + + public void testBatchInsertUpdateSizeLtJdbcBatchSize() { + int batchSize = ( ( SessionFactoryImplementor ) getSessions() ).getSettings().getJdbcBatchSize(); + doBatchInsertUpdate( 50, batchSize - 1 ); + } + + public void testBatchInsertUpdateSizeGtJdbcBatchSize() { + long start = System.currentTimeMillis(); + int batchSize = ( ( SessionFactoryImplementor ) getSessions() ).getSettings().getJdbcBatchSize(); + doBatchInsertUpdate( 50, batchSize + 1 ); + } + + public void doBatchInsertUpdate(int nEntities, int nBeforeFlush) { Session s = openSession(); s.setCacheMode( CacheMode.IGNORE ); Transaction t = s.beginTransaction(); - for ( int i = 0; i < N; i++ ) { + for ( int i = 0; i < nEntities; i++ ) { DataPoint dp = new DataPoint(); dp.setX( new BigDecimal( i * 0.1d ).setScale( 19, BigDecimal.ROUND_DOWN ) ); dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale( 19, BigDecimal.ROUND_DOWN ) ); s.save( dp ); - if ( i % 20 == 0 ) { + if ( i + 1 % nBeforeFlush == 0 ) { s.flush(); s.clear(); } @@ -75,15 +97,30 @@ public class BatchTest extends FunctionalTestCase { while ( sr.next() ) { DataPoint dp = ( DataPoint ) sr.get( 0 ); dp.setDescription( "done!" ); - if ( ++i % 20 == 0 ) { + if ( ++i % nBeforeFlush == 0 ) { s.flush(); s.clear(); } } t.commit(); s.close(); - System.out.println( System.currentTimeMillis() - start ); - } + s = openSession(); + s.setCacheMode( CacheMode.IGNORE ); + t = s.beginTransaction(); + i = 0; + sr = s.createQuery( "from DataPoint dp order by dp.x asc" ) + .scroll( ScrollMode.FORWARD_ONLY ); + while ( sr.next() ) { + DataPoint dp = ( DataPoint ) sr.get( 0 ); + s.delete( dp ); + if ( ++i % nBeforeFlush == 0 ) { + s.flush(); + s.clear(); + } + } + t.commit(); + s.close(); + } } diff --git a/hibernate-core/src/test/resources/log4j.properties b/hibernate-core/src/test/resources/log4j.properties index f8e9147f11..cd9c5224cf 100644 --- a/hibernate-core/src/test/resources/log4j.properties +++ b/hibernate-core/src/test/resources/log4j.properties @@ -9,7 +9,8 @@ log4j.rootLogger=info, stdout log4j.logger.org.hibernate.test=info log4j.logger.org.hibernate.tool.hbm2ddl=debug log4j.logger.org.hibernate.engine.jdbc.internal=trace -log4j.logger.org.hibernate.engine.jdbc=trace +log4j.logger.org.hibernate.engine.jdbc.internal.proxy=trace +log4j.logger.org.hibernate.engine.jdbc.batch.internal=trace log4j.logger.org.hibernate.hql.ast.QueryTranslatorImpl=trace log4j.logger.org.hibernate.hql.ast.HqlSqlWalker=trace log4j.logger.org.hibernate.hql.ast.SqlGenerator=trace From 0c05f66f8d4f156e432d10e035e8857e63eeb122 Mon Sep 17 00:00:00 2001 From: Vyacheslav Dimitrov Date: Mon, 6 Dec 2010 18:13:36 +0300 Subject: [PATCH 11/21] HHH-5736 Fixed problem with "not" function of CriteriaBuilder --- .../ejb/criteria/CriteriaBuilderImpl.java | 5 +- .../criteria/predicate/CompoundPredicate.java | 27 +++++++- .../ejb/criteria/basic/PredicateTest.java | 67 +++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/ejb/criteria/CriteriaBuilderImpl.java b/hibernate-entitymanager/src/main/java/org/hibernate/ejb/criteria/CriteriaBuilderImpl.java index 9f29b3c863..4fc5855698 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/ejb/criteria/CriteriaBuilderImpl.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/ejb/criteria/CriteriaBuilderImpl.java @@ -251,7 +251,10 @@ public class CriteriaBuilderImpl implements CriteriaBuilder, Serializable { // predicates ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ public Predicate wrap(Expression expression) { - if ( Predicate.class.isInstance( expression ) ) { + if ( CompoundPredicate.class.isInstance( expression ) ) { + return (( CompoundPredicate ) expression); + } + else if(Predicate.class.isInstance(expression)) { return ( ( Predicate ) expression ); } else if ( PathImplementor.class.isInstance( expression ) ) { diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/ejb/criteria/predicate/CompoundPredicate.java b/hibernate-entitymanager/src/main/java/org/hibernate/ejb/criteria/predicate/CompoundPredicate.java index 6bda4f1249..255211f4e3 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/ejb/criteria/predicate/CompoundPredicate.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/ejb/criteria/predicate/CompoundPredicate.java @@ -44,7 +44,7 @@ import org.hibernate.ejb.criteria.Renderable; public class CompoundPredicate extends AbstractPredicateImpl implements Serializable { - private final BooleanOperator operator; + private BooleanOperator operator; private final List> expressions = new ArrayList>(); /** @@ -148,4 +148,29 @@ public class CompoundPredicate public String renderProjection(CriteriaQueryCompiler.RenderingContext renderingContext) { return render( renderingContext ); } + + /** + * Create negation of compound predicate by using logic rules: + * 1. not (x || y) is (not x && not y) + * 2. not (x && y) is (not x || not y) + * + */ + @Override + public Predicate not() { + if (this.operator == BooleanOperator.AND) { + this.operator = BooleanOperator.OR; + } else { + this.operator = BooleanOperator.AND; + } + for (Expression expr : this.getExpressions()) { + if (Predicate.class.isInstance(expr)) { + ( (Predicate) expr ).not(); + } + else if(CompoundPredicate.class.isInstance(expr)) { + ( (CompoundPredicate) expr ).not(); + } + } + + return this; + } } diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/ejb/criteria/basic/PredicateTest.java b/hibernate-entitymanager/src/test/java/org/hibernate/ejb/criteria/basic/PredicateTest.java index 2d2d12df5a..97e89a258e 100644 --- a/hibernate-entitymanager/src/test/java/org/hibernate/ejb/criteria/basic/PredicateTest.java +++ b/hibernate-entitymanager/src/test/java/org/hibernate/ejb/criteria/basic/PredicateTest.java @@ -27,6 +27,7 @@ import javax.persistence.EntityManager; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Root; +import javax.persistence.criteria.Predicate; import org.hibernate.ejb.metamodel.AbstractMetamodelSpecificTest; import org.hibernate.ejb.metamodel.Order; @@ -64,4 +65,70 @@ public class PredicateTest extends AbstractMetamodelSpecificTest { em.getTransaction().commit(); em.close(); } + + /** + * Check simple not. + */ + public void testSimpleNot() { + // yes this is a retarded case, but explicitly allowed in the JPA spec + CriteriaBuilder builder = factory.getCriteriaBuilder(); + EntityManager em = getOrCreateEntityManager(); + em.getTransaction().begin(); + + CriteriaQuery orderCriteria = builder.createQuery(Order.class); + Root orderRoot = orderCriteria.from(Order.class); + + orderCriteria.select(orderRoot); + orderCriteria.where( builder.not( builder.equal(orderRoot.get("id"), 1) ) ); + + em.createQuery( orderCriteria ).getResultList(); + em.getTransaction().commit(); + em.close(); + } + + /** + * Check complicated not. + */ + public void testComplicatedNotOr() { + // yes this is a retarded case, but explicitly allowed in the JPA spec + CriteriaBuilder builder = factory.getCriteriaBuilder(); + EntityManager em = getOrCreateEntityManager(); + em.getTransaction().begin(); + + CriteriaQuery orderCriteria = builder.createQuery(Order.class); + Root orderRoot = orderCriteria.from(Order.class); + + orderCriteria.select(orderRoot); + Predicate p1 = builder.equal(orderRoot.get("id"), 1); + Predicate p1 = builder.equal(orderRoot.get("id"), 2); + orderCriteria.where( builder.not( builder.or (p1, p2) ) ); + + em.createQuery( orderCriteria ).getResultList(); + em.getTransaction().commit(); + em.close(); + } + + /** + * Check complicated not. + */ + public void testComplicatedNotAND() { + // yes this is a retarded case, but explicitly allowed in the JPA spec + CriteriaBuilder builder = factory.getCriteriaBuilder(); + EntityManager em = getOrCreateEntityManager(); + em.getTransaction().begin(); + + CriteriaQuery orderCriteria = builder.createQuery(Order.class); + Root orderRoot = orderCriteria.from(Order.class); + + orderCriteria.select(orderRoot); + Predicate p1 = builder.equal(orderRoot.get("id"), 1); + Predicate p1 = builder.equal(orderRoot.get("id"), 2); + orderCriteria.where( builder.not( builder.and (p1, p2) ) ); + + em.createQuery( orderCriteria ).getResultList(); + em.getTransaction().commit(); + em.close(); + } + + } From a4fdb870f2bc56ac11ec5f7e13d1e2ce8dbd2046 Mon Sep 17 00:00:00 2001 From: Vyacheslav Dimitrov Date: Mon, 6 Dec 2010 22:50:29 +0300 Subject: [PATCH 12/21] HHH-5736 Fixed tests --- .../java/org/hibernate/ejb/criteria/basic/PredicateTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/ejb/criteria/basic/PredicateTest.java b/hibernate-entitymanager/src/test/java/org/hibernate/ejb/criteria/basic/PredicateTest.java index 97e89a258e..cc58d10630 100644 --- a/hibernate-entitymanager/src/test/java/org/hibernate/ejb/criteria/basic/PredicateTest.java +++ b/hibernate-entitymanager/src/test/java/org/hibernate/ejb/criteria/basic/PredicateTest.java @@ -100,7 +100,7 @@ public class PredicateTest extends AbstractMetamodelSpecificTest { orderCriteria.select(orderRoot); Predicate p1 = builder.equal(orderRoot.get("id"), 1); - Predicate p1 = builder.equal(orderRoot.get("id"), 2); + Predicate p2 = builder.equal(orderRoot.get("id"), 2); orderCriteria.where( builder.not( builder.or (p1, p2) ) ); em.createQuery( orderCriteria ).getResultList(); @@ -122,7 +122,7 @@ public class PredicateTest extends AbstractMetamodelSpecificTest { orderCriteria.select(orderRoot); Predicate p1 = builder.equal(orderRoot.get("id"), 1); - Predicate p1 = builder.equal(orderRoot.get("id"), 2); + Predicate p2 = builder.equal(orderRoot.get("id"), 2); orderCriteria.where( builder.not( builder.and (p1, p2) ) ); em.createQuery( orderCriteria ).getResultList(); From 18ed85a0cd50117a20cc01fd318357f517a23f30 Mon Sep 17 00:00:00 2001 From: Hardy Ferentschik Date: Fri, 17 Dec 2010 15:33:39 +0100 Subject: [PATCH 13/21] HHH-5736 Adding actual asserts to the tests and adding some new tests --- .../ejb/criteria/basic/PredicateTest.java | 147 ++++++++++-------- 1 file changed, 85 insertions(+), 62 deletions(-) diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/ejb/criteria/basic/PredicateTest.java b/hibernate-entitymanager/src/test/java/org/hibernate/ejb/criteria/basic/PredicateTest.java index cc58d10630..f7314048a0 100644 --- a/hibernate-entitymanager/src/test/java/org/hibernate/ejb/criteria/basic/PredicateTest.java +++ b/hibernate-entitymanager/src/test/java/org/hibernate/ejb/criteria/basic/PredicateTest.java @@ -23,11 +23,12 @@ */ package org.hibernate.ejb.criteria.basic; +import java.util.List; import javax.persistence.EntityManager; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; -import javax.persistence.criteria.Root; import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; import org.hibernate.ejb.metamodel.AbstractMetamodelSpecificTest; import org.hibernate.ejb.metamodel.Order; @@ -36,99 +37,121 @@ import org.hibernate.ejb.metamodel.Order; * Test the various predicates. * * @author Steve Ebersole + * @author Hardy Ferentschik */ public class PredicateTest extends AbstractMetamodelSpecificTest { - public void testEmptyConjunction() { - // yes this is a retarded case, but explicitly allowed in the JPA spec - CriteriaBuilder builder = factory.getCriteriaBuilder(); - EntityManager em = getOrCreateEntityManager(); + + private EntityManager em; + private CriteriaBuilder builder; + + public void setUp() throws Exception { + super.setUp(); + builder = factory.getCriteriaBuilder(); + em = getOrCreateEntityManager(); + createTestOrders(); em.getTransaction().begin(); - CriteriaQuery orderCriteria = builder.createQuery(Order.class); - Root orderRoot = orderCriteria.from(Order.class); - orderCriteria.select(orderRoot); - orderCriteria.where( builder.isTrue( builder.conjunction() ) ); - em.createQuery( orderCriteria ).getResultList(); + } + + public void tearDown() throws Exception { em.getTransaction().commit(); em.close(); + super.tearDown(); + } + + public void testEmptyConjunction() { + // yes this is a retarded case, but explicitly allowed in the JPA spec + CriteriaQuery orderCriteria = builder.createQuery( Order.class ); + Root orderRoot = orderCriteria.from( Order.class ); + orderCriteria.select( orderRoot ); + orderCriteria.where( builder.isTrue( builder.conjunction() ) ); + em.createQuery( orderCriteria ).getResultList(); + + List orders = em.createQuery( orderCriteria ).getResultList(); + assertTrue( orders.size() == 3 ); } public void testEmptyDisjunction() { // yes this is a retarded case, but explicitly allowed in the JPA spec - CriteriaBuilder builder = factory.getCriteriaBuilder(); - EntityManager em = getOrCreateEntityManager(); - em.getTransaction().begin(); - CriteriaQuery orderCriteria = builder.createQuery(Order.class); - Root orderRoot = orderCriteria.from(Order.class); - orderCriteria.select(orderRoot); + CriteriaQuery orderCriteria = builder.createQuery( Order.class ); + Root orderRoot = orderCriteria.from( Order.class ); + orderCriteria.select( orderRoot ); orderCriteria.where( builder.isFalse( builder.disjunction() ) ); em.createQuery( orderCriteria ).getResultList(); - em.getTransaction().commit(); - em.close(); + + List orders = em.createQuery( orderCriteria ).getResultList(); + assertTrue( orders.size() == 3 ); } /** * Check simple not. - */ + */ public void testSimpleNot() { - // yes this is a retarded case, but explicitly allowed in the JPA spec - CriteriaBuilder builder = factory.getCriteriaBuilder(); - EntityManager em = getOrCreateEntityManager(); - em.getTransaction().begin(); + CriteriaQuery orderCriteria = builder.createQuery( Order.class ); + Root orderRoot = orderCriteria.from( Order.class ); - CriteriaQuery orderCriteria = builder.createQuery(Order.class); - Root orderRoot = orderCriteria.from(Order.class); + orderCriteria.select( orderRoot ); + orderCriteria.where( builder.not( builder.equal( orderRoot.get( "id" ), "order-1" ) ) ); - orderCriteria.select(orderRoot); - orderCriteria.where( builder.not( builder.equal(orderRoot.get("id"), 1) ) ); - - em.createQuery( orderCriteria ).getResultList(); - em.getTransaction().commit(); - em.close(); + List orders = em.createQuery( orderCriteria ).getResultList(); + assertTrue( orders.size() == 2 ); } /** * Check complicated not. - */ + */ public void testComplicatedNotOr() { - // yes this is a retarded case, but explicitly allowed in the JPA spec - CriteriaBuilder builder = factory.getCriteriaBuilder(); - EntityManager em = getOrCreateEntityManager(); - em.getTransaction().begin(); + CriteriaQuery orderCriteria = builder.createQuery( Order.class ); + Root orderRoot = orderCriteria.from( Order.class ); - CriteriaQuery orderCriteria = builder.createQuery(Order.class); - Root orderRoot = orderCriteria.from(Order.class); + orderCriteria.select( orderRoot ); + Predicate p1 = builder.equal( orderRoot.get( "id" ), "order-1" ); + Predicate p2 = builder.equal( orderRoot.get( "id" ), "order-2" ); + orderCriteria.where( builder.not( builder.or( p1, p2 ) ) ); - orderCriteria.select(orderRoot); - Predicate p1 = builder.equal(orderRoot.get("id"), 1); - Predicate p2 = builder.equal(orderRoot.get("id"), 2); - orderCriteria.where( builder.not( builder.or (p1, p2) ) ); - - em.createQuery( orderCriteria ).getResultList(); - em.getTransaction().commit(); - em.close(); + List orders = em.createQuery( orderCriteria ).getResultList(); + assertTrue( orders.size() == 1 ); + Order order = orders.get( 0 ); + assertEquals( "order-3", order.getId() ); } /** * Check complicated not. - */ - public void testComplicatedNotAND() { - // yes this is a retarded case, but explicitly allowed in the JPA spec - CriteriaBuilder builder = factory.getCriteriaBuilder(); - EntityManager em = getOrCreateEntityManager(); - em.getTransaction().begin(); + */ + public void testNotMultipleOr() { + CriteriaQuery orderCriteria = builder.createQuery( Order.class ); + Root orderRoot = orderCriteria.from( Order.class ); - CriteriaQuery orderCriteria = builder.createQuery(Order.class); - Root orderRoot = orderCriteria.from(Order.class); + orderCriteria.select( orderRoot ); + Predicate p1 = builder.equal( orderRoot.get( "id" ), "order-1" ); + Predicate p2 = builder.equal( orderRoot.get( "id" ), "order-2" ); + Predicate p3 = builder.equal( orderRoot.get( "id" ), "order-3" ); + orderCriteria.where( builder.not( builder.or( p1, p2, p3 ) ) ); - orderCriteria.select(orderRoot); - Predicate p1 = builder.equal(orderRoot.get("id"), 1); - Predicate p2 = builder.equal(orderRoot.get("id"), 2); - orderCriteria.where( builder.not( builder.and (p1, p2) ) ); - - em.createQuery( orderCriteria ).getResultList(); - em.getTransaction().commit(); - em.close(); + List orders = em.createQuery( orderCriteria ).getResultList(); + assertTrue( orders.size() == 0 ); } + /** + * Check complicated not. + */ + public void testComplicatedNotAnd() { + CriteriaQuery orderCriteria = builder.createQuery( Order.class ); + Root orderRoot = orderCriteria.from( Order.class ); + orderCriteria.select( orderRoot ); + Predicate p1 = builder.equal( orderRoot.get( "id" ), "order-1" ); + Predicate p2 = builder.equal( orderRoot.get( "id" ), "order-2" ); + orderCriteria.where( builder.not( builder.and( p1, p2 ) ) ); + + List orders = em.createQuery( orderCriteria ).getResultList(); + assertTrue( orders.size() == 3 ); + } + + private void createTestOrders() { + em.getTransaction().begin(); + em.persist( new Order( "order-1", 1.0d ) ); + em.persist( new Order( "order-2", 10.0d ) ); + em.persist( new Order( "order-3", 100.0d ) ); + em.getTransaction().commit(); + } } From ed89cef855d1bb345047a88f90b0c93c9a9b1402 Mon Sep 17 00:00:00 2001 From: Hardy Ferentschik Date: Fri, 17 Dec 2010 15:35:12 +0100 Subject: [PATCH 14/21] HHH-5736 Removing unnecessary instance check. Applying Hibernate formatting. --- .../hibernate/ejb/criteria/CriteriaBuilderImpl.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/ejb/criteria/CriteriaBuilderImpl.java b/hibernate-entitymanager/src/main/java/org/hibernate/ejb/criteria/CriteriaBuilderImpl.java index 4fc5855698..f5521c4f9a 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/ejb/criteria/CriteriaBuilderImpl.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/ejb/criteria/CriteriaBuilderImpl.java @@ -251,11 +251,8 @@ public class CriteriaBuilderImpl implements CriteriaBuilder, Serializable { // predicates ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ public Predicate wrap(Expression expression) { - if ( CompoundPredicate.class.isInstance( expression ) ) { - return (( CompoundPredicate ) expression); - } - else if(Predicate.class.isInstance(expression)) { - return ( ( Predicate ) expression ); + if ( Predicate.class.isInstance( expression ) ) { + return ( (Predicate) expression ); } else if ( PathImplementor.class.isInstance( expression ) ) { return new BooleanAssertionPredicate( this, expression, Boolean.TRUE ); @@ -343,7 +340,7 @@ public class CriteriaBuilderImpl implements CriteriaBuilder, Serializable { if ( predicate.getExpressions().size() == 0 ) { return new BooleanStaticAssertionPredicate( this, - predicate.getOperator() == Predicate.BooleanOperator.OR + predicate.getOperator() == Predicate.BooleanOperator.OR ); } predicate.not(); @@ -1366,7 +1363,7 @@ public class CriteriaBuilderImpl implements CriteriaBuilder, Serializable { } return new MemberOfPredicate( this, - e, + e, (PluralAttributePath)collectionExpression ); } From 2b7573febb15486a917cf93cfba67de83d436c7a Mon Sep 17 00:00:00 2001 From: Hardy Ferentschik Date: Fri, 17 Dec 2010 15:36:10 +0100 Subject: [PATCH 15/21] HHH-5736 Removing unnecessary instance check. Applying Hibernate formatting. --- .../criteria/predicate/CompoundPredicate.java | 76 +++++++++---------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/ejb/criteria/predicate/CompoundPredicate.java b/hibernate-entitymanager/src/main/java/org/hibernate/ejb/criteria/predicate/CompoundPredicate.java index 255211f4e3..874b019010 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/ejb/criteria/predicate/CompoundPredicate.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/ejb/criteria/predicate/CompoundPredicate.java @@ -24,15 +24,15 @@ package org.hibernate.ejb.criteria.predicate; import java.io.Serializable; -import java.util.List; import java.util.ArrayList; import java.util.Arrays; -import javax.persistence.criteria.Predicate; +import java.util.List; import javax.persistence.criteria.Expression; +import javax.persistence.criteria.Predicate; -import org.hibernate.ejb.criteria.ParameterRegistry; import org.hibernate.ejb.criteria.CriteriaBuilderImpl; import org.hibernate.ejb.criteria.CriteriaQueryCompiler; +import org.hibernate.ejb.criteria.ParameterRegistry; import org.hibernate.ejb.criteria.Renderable; /** @@ -50,9 +50,9 @@ public class CompoundPredicate /** * Constructs an empty conjunction or disjunction. * - * @param criteriaBuilder The query builder from whcih this originates. - * @param operator Indicates whether this predicate will funtion - * as a conjunction or disjuntion. + * @param criteriaBuilder The query builder from which this originates. + * @param operator Indicates whether this predicate will function + * as a conjunction or disjunction. */ public CompoundPredicate(CriteriaBuilderImpl criteriaBuilder, BooleanOperator operator) { super( criteriaBuilder ); @@ -63,31 +63,31 @@ public class CompoundPredicate * Constructs a conjunction or disjunction over the given expressions. * * @param criteriaBuilder The query builder from which this originates. - * @param operator Indicates whether this predicate will funtion - * as a conjunction or disjuntion. + * @param operator Indicates whether this predicate will function + * as a conjunction or disjunction. * @param expressions The expressions to be grouped. */ public CompoundPredicate( CriteriaBuilderImpl criteriaBuilder, BooleanOperator operator, Expression... expressions) { - this( criteriaBuilder, operator ); + this( criteriaBuilder, operator ); applyExpressions( expressions ); } /** * Constructs a conjunction or disjunction over the given expressions. * - * @param criteriaBuilder The query builder from whcih this originates. - * @param operator Indicates whether this predicate will funtion - * as a conjunction or disjuntion. + * @param criteriaBuilder The query builder from which this originates. + * @param operator Indicates whether this predicate will function + * as a conjunction or disjunction. * @param expressions The expressions to be grouped. */ public CompoundPredicate( CriteriaBuilderImpl criteriaBuilder, BooleanOperator operator, List> expressions) { - this( criteriaBuilder, operator ); + this( criteriaBuilder, operator ); applyExpressions( expressions ); } @@ -110,7 +110,7 @@ public class CompoundPredicate public void registerParameters(ParameterRegistry registry) { for ( Expression expression : getExpressions() ) { - Helper.possibleParameter(expression, registry); + Helper.possibleParameter( expression, registry ); } } @@ -125,7 +125,7 @@ public class CompoundPredicate : "0=1"; // false } if ( getExpressions().size() == 1 ) { - return ( (Renderable) getExpressions().get(0) ).render( renderingContext ); + return ( (Renderable) getExpressions().get( 0 ) ).render( renderingContext ); } final StringBuilder buffer = new StringBuilder(); String sep = ""; @@ -149,28 +149,28 @@ public class CompoundPredicate return render( renderingContext ); } - /** - * Create negation of compound predicate by using logic rules: - * 1. not (x || y) is (not x && not y) - * 2. not (x && y) is (not x || not y) - * - */ - @Override - public Predicate not() { - if (this.operator == BooleanOperator.AND) { - this.operator = BooleanOperator.OR; - } else { - this.operator = BooleanOperator.AND; - } - for (Expression expr : this.getExpressions()) { - if (Predicate.class.isInstance(expr)) { - ( (Predicate) expr ).not(); - } - else if(CompoundPredicate.class.isInstance(expr)) { - ( (CompoundPredicate) expr ).not(); - } - } + /** + * Create negation of compound predicate by using logic rules: + * 1. not (x || y) is (not x && not y) + * 2. not (x && y) is (not x || not y) + */ + @Override + public Predicate not() { + toggleOperator(); + for ( Expression expr : this.getExpressions() ) { + if ( Predicate.class.isInstance( expr ) ) { + ( (Predicate) expr ).not(); + } + } + return this; + } - return this; - } + private void toggleOperator() { + if ( this.operator == BooleanOperator.AND ) { + this.operator = BooleanOperator.OR; + } + else { + this.operator = BooleanOperator.AND; + } + } } From 262f25311d3b5a3953512d2bf4f88215defee515 Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Fri, 17 Dec 2010 16:10:33 -0800 Subject: [PATCH 16/21] HHH-5791 : NPE merging transient entity with non-nullable property set to null with delayed insert if check_nullability set to false --- .../event/def/DefaultMergeEventListener.java | 42 +++++----- ...ascadeCheckNullFalseDelayedInsertTest.java | 52 ++++++++++++ ...CascadeCheckNullTrueDelayedInsertTest.java | 51 ++++++++++++ ...ultiPathCircleCascadeDelayedInsert.hbm.xml | 82 +++++++++++++++++++ ...ltiPathCircleCascadeDelayedInsertTest.java | 65 +++++++++++++++ .../circle/MultiPathCircleCascadeTest.java | 50 +++++++---- 6 files changed, 303 insertions(+), 39 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/cascade/circle/MultiPathCircleCascadeCheckNullFalseDelayedInsertTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/cascade/circle/MultiPathCircleCascadeCheckNullTrueDelayedInsertTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/cascade/circle/MultiPathCircleCascadeDelayedInsert.hbm.xml create mode 100644 hibernate-core/src/test/java/org/hibernate/test/cascade/circle/MultiPathCircleCascadeDelayedInsertTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/event/def/DefaultMergeEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/def/DefaultMergeEventListener.java index 63767ac45c..7b64492889 100755 --- a/hibernate-core/src/main/java/org/hibernate/event/def/DefaultMergeEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/def/DefaultMergeEventListener.java @@ -346,9 +346,19 @@ public class DefaultMergeEventListener extends AbstractSaveEventListener Object propertyFromEntity = persister.getPropertyValue( entity, propertyName, source.getEntityMode() ); Type propertyType = persister.getPropertyType( propertyName ); EntityEntry copyEntry = source.getPersistenceContext().getEntry( copy ); - if ( propertyFromCopy == null || ! propertyType.isEntityType() ) { - log.trace( "property '" + copyEntry.getEntityName() + "." + propertyName + - "' is null or not an entity; " + propertyName + " =["+propertyFromCopy+"]"); + if ( propertyFromCopy == null || + propertyFromEntity == null || + ! propertyType.isEntityType() || + ! copyCache.containsKey( propertyFromEntity ) ) { + if ( log.isTraceEnabled() ) { + String fullPropertyName = "property '" + copyEntry.getEntityName() + "." + propertyName; + log.trace( fullPropertyName + " in copy is " + ( propertyFromCopy == null ? "null" : propertyFromCopy ) ); + log.trace( fullPropertyName + " in original is " + ( propertyFromCopy == null ? "null" : propertyFromCopy ) ); + log.trace( fullPropertyName + ( propertyType.isEntityType() ? " is" : " is not" ) + " an entity type" ); + if ( propertyFromEntity != null && ! copyCache.containsKey( propertyFromEntity ) ) { + log.trace( fullPropertyName + " is not in copy cache" ); + } + } if ( isNullabilityCheckedGlobal( source ) ) { throw ex; } @@ -358,28 +368,18 @@ public class DefaultMergeEventListener extends AbstractSaveEventListener saveTransientEntity( copy, entityName, requestedId, source, copyCache, false ); } } - if ( ! copyCache.containsKey( propertyFromEntity ) ) { - log.trace( "property '" + copyEntry.getEntityName() + "." + propertyName + - "' from original entity is not in copyCache; " + propertyName + " =["+propertyFromEntity+"]"); - if ( isNullabilityCheckedGlobal( source ) ) { - throw ex; + if ( log.isTraceEnabled() && propertyFromEntity != null ) { + if ( ( ( EventCache ) copyCache ).isOperatedOn( propertyFromEntity ) ) { + log.trace( "property '" + copyEntry.getEntityName() + "." + propertyName + + "' from original entity is in copyCache and is in the process of being merged; " + + propertyName + " =["+propertyFromEntity+"]"); } else { - // retry save w/o checking non-nullable properties - // (the failure will be detected later) - saveTransientEntity( copy, entityName, requestedId, source, copyCache, false ); + log.trace( "property '" + copyEntry.getEntityName() + "." + propertyName + + "' from original entity is in copyCache and is not in the process of being merged; " + + propertyName + " =["+propertyFromEntity+"]"); } } - if ( ( ( EventCache ) copyCache ).isOperatedOn( propertyFromEntity ) ) { - log.trace( "property '" + copyEntry.getEntityName() + "." + propertyName + - "' from original entity is in copyCache and is in the process of being merged; " + - propertyName + " =["+propertyFromEntity+"]"); - } - else { - log.trace( "property '" + copyEntry.getEntityName() + "." + propertyName + - "' from original entity is in copyCache and is not in the process of being merged; " + - propertyName + " =["+propertyFromEntity+"]"); - } // continue...; we'll find out if it ends up not getting saved later } diff --git a/hibernate-core/src/test/java/org/hibernate/test/cascade/circle/MultiPathCircleCascadeCheckNullFalseDelayedInsertTest.java b/hibernate-core/src/test/java/org/hibernate/test/cascade/circle/MultiPathCircleCascadeCheckNullFalseDelayedInsertTest.java new file mode 100644 index 0000000000..b9353399bf --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/cascade/circle/MultiPathCircleCascadeCheckNullFalseDelayedInsertTest.java @@ -0,0 +1,52 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010, 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.test.cascade.circle; + +import junit.framework.Test; + +import org.hibernate.TransientObjectException; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.testing.junit.functional.FunctionalTestClassTestSuite; + +/** + * @author Gail Badner + */ +public class MultiPathCircleCascadeCheckNullFalseDelayedInsertTest extends MultiPathCircleCascadeDelayedInsertTest { + + public MultiPathCircleCascadeCheckNullFalseDelayedInsertTest(String str) { + super( str ); + } + + @Override + public void configure(Configuration cfg) { + super.configure( cfg ); + cfg.setProperty( Environment.CHECK_NULLABILITY, "false" ); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( MultiPathCircleCascadeCheckNullFalseDelayedInsertTest.class ); + } +} \ No newline at end of file diff --git a/hibernate-core/src/test/java/org/hibernate/test/cascade/circle/MultiPathCircleCascadeCheckNullTrueDelayedInsertTest.java b/hibernate-core/src/test/java/org/hibernate/test/cascade/circle/MultiPathCircleCascadeCheckNullTrueDelayedInsertTest.java new file mode 100644 index 0000000000..750b7c6ccb --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/cascade/circle/MultiPathCircleCascadeCheckNullTrueDelayedInsertTest.java @@ -0,0 +1,51 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010, 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.test.cascade.circle; + +import junit.framework.Test; + +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.testing.junit.functional.FunctionalTestClassTestSuite; + +/** + * @author Gail Badner + */ +public class MultiPathCircleCascadeCheckNullTrueDelayedInsertTest extends MultiPathCircleCascadeDelayedInsertTest { + + public MultiPathCircleCascadeCheckNullTrueDelayedInsertTest(String str) { + super( str ); + } + + @Override + public void configure(Configuration cfg) { + super.configure( cfg ); + cfg.setProperty( Environment.CHECK_NULLABILITY, "true" ); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( MultiPathCircleCascadeCheckNullTrueDelayedInsertTest.class ); + } +} \ No newline at end of file diff --git a/hibernate-core/src/test/java/org/hibernate/test/cascade/circle/MultiPathCircleCascadeDelayedInsert.hbm.xml b/hibernate-core/src/test/java/org/hibernate/test/cascade/circle/MultiPathCircleCascadeDelayedInsert.hbm.xml new file mode 100644 index 0000000000..985fd92891 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/cascade/circle/MultiPathCircleCascadeDelayedInsert.hbm.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hibernate-core/src/test/java/org/hibernate/test/cascade/circle/MultiPathCircleCascadeDelayedInsertTest.java b/hibernate-core/src/test/java/org/hibernate/test/cascade/circle/MultiPathCircleCascadeDelayedInsertTest.java new file mode 100644 index 0000000000..d6531a25c0 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/cascade/circle/MultiPathCircleCascadeDelayedInsertTest.java @@ -0,0 +1,65 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010, 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.test.cascade.circle; + +import junit.framework.Test; + +import org.hibernate.JDBCException; +import org.hibernate.PropertyValueException; +import org.hibernate.TransientObjectException; +import org.hibernate.testing.junit.functional.FunctionalTestClassTestSuite; + +/** + * @author Gail Badner + */ +public class MultiPathCircleCascadeDelayedInsertTest extends MultiPathCircleCascadeTest { + public MultiPathCircleCascadeDelayedInsertTest(String string) { + super(string); + } + + public String[] getMappings() { + return new String[] { + "cascade/circle/MultiPathCircleCascadeDelayedInsert.hbm.xml" + }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( MultiPathCircleCascadeDelayedInsertTest.class ); + } + + protected void checkExceptionFromNullValueForNonNullable(Exception ex, boolean checkNullability, boolean isNullValue ) { + if ( checkNullability ) { + if ( isNullValue ) { + assertTrue( ex instanceof PropertyValueException ); + } + else { + assertTrue( ex instanceof TransientObjectException ); + } + } + else { + assertTrue( ex instanceof JDBCException || ex instanceof TransientObjectException ); + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/cascade/circle/MultiPathCircleCascadeTest.java b/hibernate-core/src/test/java/org/hibernate/test/cascade/circle/MultiPathCircleCascadeTest.java index c4aabe0285..4ffbe5e740 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/cascade/circle/MultiPathCircleCascadeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/cascade/circle/MultiPathCircleCascadeTest.java @@ -109,15 +109,15 @@ public class MultiPathCircleCascadeTest extends FunctionalTestCase { try { s.merge( node ); + s.getTransaction().commit(); fail( "should have thrown an exception" ); } catch ( Exception ex ) { - if ( ( ( SessionImplementor ) s ).getFactory().getSettings().isCheckNullability() ) { - assertTrue( ex instanceof TransientObjectException ); - } - else { - assertTrue( ex instanceof JDBCException ); - } + checkExceptionFromNullValueForNonNullable( + ex, + ( ( SessionImplementor ) s ).getFactory().getSettings().isCheckNullability(), + false + ); } finally { s.getTransaction().rollback(); @@ -138,15 +138,15 @@ public class MultiPathCircleCascadeTest extends FunctionalTestCase { try { s.merge( node ); + s.getTransaction().commit(); fail( "should have thrown an exception" ); } catch ( Exception ex ) { - if ( ( ( SessionImplementor ) s ).getFactory().getSettings().isCheckNullability() ) { - assertTrue( ex instanceof PropertyValueException ); - } - else { - assertTrue( ex instanceof JDBCException ); - } + checkExceptionFromNullValueForNonNullable( + ex, + ( ( SessionImplementor ) s ).getFactory().getSettings().isCheckNullability(), + true + ); } finally { s.getTransaction().rollback(); @@ -165,15 +165,15 @@ public class MultiPathCircleCascadeTest extends FunctionalTestCase { try { s.merge( route ); + s.getTransaction().commit(); fail( "should have thrown an exception" ); } catch ( Exception ex ) { - if ( ( ( SessionImplementor ) s ).getFactory().getSettings().isCheckNullability() ) { - assertTrue( ex instanceof PropertyValueException ); - } - else { - assertTrue( ex instanceof JDBCException ); - } + checkExceptionFromNullValueForNonNullable( + ex, + ( ( SessionImplementor ) s ).getFactory().getSettings().isCheckNullability(), + true + ); } finally { s.getTransaction().rollback(); @@ -531,6 +531,20 @@ public class MultiPathCircleCascadeTest extends FunctionalTestCase { assertUpdateCount( 1 ); } + protected void checkExceptionFromNullValueForNonNullable(Exception ex, boolean checkNullability, boolean isNullValue ) { + if ( checkNullability ) { + if ( isNullValue ) { + assertTrue( ex instanceof PropertyValueException ); + } + else { + assertTrue( ex instanceof TransientObjectException ); + } + } + else { + assertTrue( ex instanceof JDBCException ); + } + } + protected void clearCounts() { getSessions().getStatistics().clear(); } From 863864fcce3bcdba5e9783adf9d23863f50ce202 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Galder=20Zamarre=C3=B1o?= Date: Mon, 20 Dec 2010 11:00:45 +0100 Subject: [PATCH 17/21] HHH-5793 - Query and timestamp caches to use cluster cache loader Make evict put calls skip the cache loader since previous value is not needed. --- .../org/hibernate/cache/infinispan/util/CacheHelper.java | 4 ++-- .../org/hibernate/cache/infinispan/util/FlagAdapter.java | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/util/CacheHelper.java b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/util/CacheHelper.java index 984f6c63cc..923c2b06a2 100644 --- a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/util/CacheHelper.java +++ b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/util/CacheHelper.java @@ -50,12 +50,12 @@ public class CacheHelper { public static void initInternalEvict(CacheAdapter cacheAdapter, AddressAdapter member) { EvictAll eKey = new EvictAll(member == null ? NoAddress.INSTANCE : member); - cacheAdapter.withFlags(FlagAdapter.CACHE_MODE_LOCAL).put(eKey, Internal.INIT); + cacheAdapter.withFlags(FlagAdapter.CACHE_MODE_LOCAL, FlagAdapter.SKIP_CACHE_LOAD).put(eKey, Internal.INIT); } public static void sendEvictAllNotification(CacheAdapter cacheAdapter, AddressAdapter member) { EvictAll eKey = new EvictAll(member == null ? NoAddress.INSTANCE : member); - cacheAdapter.put(eKey, Internal.EVICT); + cacheAdapter.withFlags(FlagAdapter.SKIP_CACHE_LOAD).put(eKey, Internal.EVICT); } public static boolean isEvictAllNotification(Object key) { diff --git a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/util/FlagAdapter.java b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/util/FlagAdapter.java index f4f7a3a308..b4d329bf0f 100644 --- a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/util/FlagAdapter.java +++ b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/util/FlagAdapter.java @@ -36,7 +36,8 @@ public enum FlagAdapter { CACHE_MODE_LOCAL, FORCE_ASYNCHRONOUS, FORCE_SYNCHRONOUS, - SKIP_CACHE_STORE; + SKIP_CACHE_STORE, + SKIP_CACHE_LOAD; Flag toFlag() { switch(this) { @@ -50,6 +51,8 @@ public enum FlagAdapter { return Flag.FORCE_SYNCHRONOUS; case SKIP_CACHE_STORE: return Flag.SKIP_CACHE_STORE; + case SKIP_CACHE_LOAD: + return Flag.SKIP_CACHE_LOAD; default: throw new CacheException("Unmatched Infinispan flag " + this); } From bf6bd51c7e8ca4bd354afa4579d21c5383a2846a Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Mon, 20 Dec 2010 17:27:10 -0800 Subject: [PATCH 18/21] HHH-5325 : Improvements to test suite (fixes HQLDB 2.0 failures) --- .../various/readwriteexpression/Staff.java | 12 ++++++------ .../org/hibernate/test/component/basic/User.hbm.xml | 4 ++-- .../java/org/hibernate/test/filter/Product.hbm.xml | 4 ++-- .../org/hibernate/test/hql/ASTParserLoadingTest.java | 6 +++--- .../test/java/org/hibernate/test/hql/Animal.hbm.xml | 4 ++-- .../test/java/org/hibernate/test/join/Person.hbm.xml | 8 ++++---- .../org/hibernate/test/joinedsubclass/Person.hbm.xml | 8 ++++---- .../java/org/hibernate/test/legacy/FooBarTest.java | 2 +- .../java/org/hibernate/test/subselect/Beings.hbm.xml | 10 +++++----- .../org/hibernate/test/unionsubclass2/Person.hbm.xml | 8 ++++---- 10 files changed, 33 insertions(+), 33 deletions(-) diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/various/readwriteexpression/Staff.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/various/readwriteexpression/Staff.java index 1f1a5265fa..b58bac8c2b 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/various/readwriteexpression/Staff.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/various/readwriteexpression/Staff.java @@ -52,24 +52,24 @@ public class Staff { @Column(name="size_in_cm") @ColumnTransformer( forColumn = "size_in_cm", - read = "size_in_cm / 2.54", - write = "? * 2.54" ) + read = "size_in_cm / 2.54E0", + write = "? * 2.54E0" ) public double getSizeInInches() { return sizeInInches; } public void setSizeInInches(double sizeInInches) { this.sizeInInches = sizeInInches; } private double sizeInInches; //Weird extra S to avoid potential SQL keywords @ColumnTransformer( - read = "radiusS / 2.54", - write = "? * 2.54" ) + read = "radiusS / 2.54E0", + write = "? * 2.54E0" ) public double getRadiusS() { return radiusS; } public void setRadiusS(double radiusS) { this.radiusS = radiusS; } private double radiusS; @Column(name="diamet") @ColumnTransformer( - read = "diamet / 2.54", - write = "? * 2.54" ) + read = "diamet / 2.54E0", + write = "? * 2.54E0" ) public double getDiameter() { return diameter; } public void setDiameter(double diameter) { this.diameter = diameter; } private double diameter; diff --git a/hibernate-core/src/test/java/org/hibernate/test/component/basic/User.hbm.xml b/hibernate-core/src/test/java/org/hibernate/test/component/basic/User.hbm.xml index 85839a6956..255df21705 100755 --- a/hibernate-core/src/test/java/org/hibernate/test/component/basic/User.hbm.xml +++ b/hibernate-core/src/test/java/org/hibernate/test/component/basic/User.hbm.xml @@ -22,8 +22,8 @@ + read="height_centimeters / 2.54E0" + write="? * 2.54E0"/> + write="0.453E0 * ?" + read="weight_kg / 0.453E0"/> diff --git a/hibernate-core/src/test/java/org/hibernate/test/hql/ASTParserLoadingTest.java b/hibernate-core/src/test/java/org/hibernate/test/hql/ASTParserLoadingTest.java index e88985e36e..a9fae2c83f 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/hql/ASTParserLoadingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/hql/ASTParserLoadingTest.java @@ -307,7 +307,7 @@ public class ASTParserLoadingTest extends FunctionalTestCase { results = s.createQuery( "from Human where name is not null" ).list(); assertEquals( 3, results.size() ); String query = - getDialect() instanceof DB2Dialect ? + ( getDialect() instanceof DB2Dialect || getDialect() instanceof HSQLDialect ) ? "from Human where cast(? as string) is null" : "from Human where ? is null" ; @@ -2600,14 +2600,14 @@ public class ASTParserLoadingTest extends FunctionalTestCase { * PostgreSQL >= 8.3.7 typecasts are no longer automatically allowed * http://www.postgresql.org/docs/current/static/release-8-3.html */ - if(getDialect() instanceof PostgreSQLDialect){ + if(getDialect() instanceof PostgreSQLDialect || getDialect() instanceof HSQLDialect){ hql = "from Animal a where bit_length(str(a.bodyWeight)) = 24"; }else{ hql = "from Animal a where bit_length(a.bodyWeight) = 24"; } session.createQuery(hql).list(); - if(getDialect() instanceof PostgreSQLDialect){ + if(getDialect() instanceof PostgreSQLDialect || getDialect() instanceof HSQLDialect){ hql = "select bit_length(str(a.bodyWeight)) from Animal a"; }else{ hql = "select bit_length(a.bodyWeight) from Animal a"; diff --git a/hibernate-core/src/test/java/org/hibernate/test/hql/Animal.hbm.xml b/hibernate-core/src/test/java/org/hibernate/test/hql/Animal.hbm.xml index 94411be0db..71e693d348 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/hql/Animal.hbm.xml +++ b/hibernate-core/src/test/java/org/hibernate/test/hql/Animal.hbm.xml @@ -50,8 +50,8 @@ + read="height_centimeters / 2.54E0" + write="? * 2.54E0"/> diff --git a/hibernate-core/src/test/java/org/hibernate/test/join/Person.hbm.xml b/hibernate-core/src/test/java/org/hibernate/test/join/Person.hbm.xml index bf9bf03ca1..227f1456ed 100755 --- a/hibernate-core/src/test/java/org/hibernate/test/join/Person.hbm.xml +++ b/hibernate-core/src/test/java/org/hibernate/test/join/Person.hbm.xml @@ -39,8 +39,8 @@ + read="height_centimeters / 2.54E0" + write="? * 2.54E0"/> @@ -73,8 +73,8 @@ + read="pwd_expiry_weeks * 7.0E0" + write="? / 7.0E0"/> diff --git a/hibernate-core/src/test/java/org/hibernate/test/joinedsubclass/Person.hbm.xml b/hibernate-core/src/test/java/org/hibernate/test/joinedsubclass/Person.hbm.xml index bb60f51dd3..99845abb25 100755 --- a/hibernate-core/src/test/java/org/hibernate/test/joinedsubclass/Person.hbm.xml +++ b/hibernate-core/src/test/java/org/hibernate/test/joinedsubclass/Person.hbm.xml @@ -38,8 +38,8 @@ + read="height_centimeters / 2.54E0" + write="? * 2.54E0"/> @@ -58,8 +58,8 @@ + read="pwd_expiry_weeks * 7.0E0" + write="? / 7.0E0"/> diff --git a/hibernate-core/src/test/java/org/hibernate/test/legacy/FooBarTest.java b/hibernate-core/src/test/java/org/hibernate/test/legacy/FooBarTest.java index c63b5391fa..390bd85459 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/legacy/FooBarTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/legacy/FooBarTest.java @@ -1939,7 +1939,7 @@ public class FooBarTest extends LegacyTestCase { .addOrder( Order.asc("date") ) .list(); assertTrue( list.size()==1 && list.get(0)==f ); - if(!(getDialect() instanceof TimesTenDialect)) { + if(!(getDialect() instanceof TimesTenDialect || getDialect() instanceof HSQLDialect)) { list = s.createCriteria(Foo.class).setMaxResults(0).list(); assertTrue( list.size()==0 ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/subselect/Beings.hbm.xml b/hibernate-core/src/test/java/org/hibernate/test/subselect/Beings.hbm.xml index 10a8752058..adc3ebc2a7 100755 --- a/hibernate-core/src/test/java/org/hibernate/test/subselect/Beings.hbm.xml +++ b/hibernate-core/src/test/java/org/hibernate/test/subselect/Beings.hbm.xml @@ -39,8 +39,8 @@ + read="height_centimeters / 2.54E0" + write="? * 2.54E0"/> @@ -62,8 +62,8 @@ + read="height_centimeters / 2.54E0" + write="? * 2.54E0"/> @@ -92,7 +92,7 @@ + read="height_centimeters / 2.54E0"/> diff --git a/hibernate-core/src/test/java/org/hibernate/test/unionsubclass2/Person.hbm.xml b/hibernate-core/src/test/java/org/hibernate/test/unionsubclass2/Person.hbm.xml index dced315dae..bda7e18803 100755 --- a/hibernate-core/src/test/java/org/hibernate/test/unionsubclass2/Person.hbm.xml +++ b/hibernate-core/src/test/java/org/hibernate/test/unionsubclass2/Person.hbm.xml @@ -37,8 +37,8 @@ + read="height_centimeters / 2.54E0" + write="? * 2.54E0"/> @@ -56,8 +56,8 @@ + read="pwd_expiry_weeks * 7.0E0" + write="? / 7.0E0"/> From 1dc7317694c2725f49725de64fdb6b79e3c1a689 Mon Sep 17 00:00:00 2001 From: Greg Luck Date: Tue, 21 Dec 2010 15:24:50 +1000 Subject: [PATCH 19/21] Create new Ehcache CacheRegionFactory implementation. This delegates to underlying classes in Ehcache. --- hibernate-ehcache/hibernate-ehcache.gradle | 4 +- .../cache/AbstractEhCacheRegionFactory.java | 111 ++++++++++++++++++ .../java/org/hibernate/cache/EhCache.java | 8 +- .../org/hibernate/cache/EhCacheProvider.java | 12 +- .../hibernate/cache/EhCacheRegionFactory.java | 41 +++++++ .../cache/SingletonEhCacheProvider.java | 2 +- .../cache/SingletonEhCacheRegionFactory.java | 41 +++++++ 7 files changed, 206 insertions(+), 13 deletions(-) create mode 100644 hibernate-ehcache/src/main/java/org/hibernate/cache/AbstractEhCacheRegionFactory.java create mode 100644 hibernate-ehcache/src/main/java/org/hibernate/cache/EhCacheRegionFactory.java create mode 100644 hibernate-ehcache/src/main/java/org/hibernate/cache/SingletonEhCacheRegionFactory.java diff --git a/hibernate-ehcache/hibernate-ehcache.gradle b/hibernate-ehcache/hibernate-ehcache.gradle index fc6165c231..93a71d998f 100644 --- a/hibernate-ehcache/hibernate-ehcache.gradle +++ b/hibernate-ehcache/hibernate-ehcache.gradle @@ -2,6 +2,6 @@ apply plugin: 'java' dependencies { compile( project( ':hibernate-core' ) ) - compile( [group: 'net.sf.ehcache', name: 'ehcache', version: '1.5.0'] ) + compile( [group: 'net.sf.ehcache', name: 'ehcache-core', version: '2.3.1'] ) testCompile( project(':hibernate-core').sourceSets.test.classes ) -} \ No newline at end of file +} diff --git a/hibernate-ehcache/src/main/java/org/hibernate/cache/AbstractEhCacheRegionFactory.java b/hibernate-ehcache/src/main/java/org/hibernate/cache/AbstractEhCacheRegionFactory.java new file mode 100644 index 0000000000..774d5fe6f1 --- /dev/null +++ b/hibernate-ehcache/src/main/java/org/hibernate/cache/AbstractEhCacheRegionFactory.java @@ -0,0 +1,111 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2007, 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.cache; + +import org.hibernate.cache.access.AccessType; +import org.hibernate.cfg.Settings; + +import java.util.Properties; + +/** + * Abstract class that will delegate all calls to org.hibernate.cache.RegionFactory to the instance it wraps. + * This abstracts the Singleton CacheManager construct of Ehcache + * + * @author Alex Snaps + */ +class AbstractEhCacheRegionFactory implements RegionFactory { + + private final RegionFactory underlyingRegionFactory; + + /** + * {@inheritDoc} + */ + protected AbstractEhCacheRegionFactory(RegionFactory regionFactory) { + underlyingRegionFactory = regionFactory; + } + + /** + * {@inheritDoc} + */ + public final void start(final Settings settings, final Properties properties) throws CacheException { + underlyingRegionFactory.start(settings, properties); + } + + /** + * {@inheritDoc} + */ + public final void stop() { + underlyingRegionFactory.stop(); + } + + /** + * {@inheritDoc} + */ + public final boolean isMinimalPutsEnabledByDefault() { + return underlyingRegionFactory.isMinimalPutsEnabledByDefault(); + } + + /** + * {@inheritDoc} + */ + public final AccessType getDefaultAccessType() { + return underlyingRegionFactory.getDefaultAccessType(); + } + + /** + * {@inheritDoc} + */ + public final long nextTimestamp() { + return underlyingRegionFactory.nextTimestamp(); + } + + /** + * {@inheritDoc} + */ + public final EntityRegion buildEntityRegion(final String regionName, final Properties properties, final CacheDataDescription metadata) throws CacheException { + return underlyingRegionFactory.buildEntityRegion(regionName, properties, metadata); + } + + /** + * {@inheritDoc} + */ + public final CollectionRegion buildCollectionRegion(final String regionName, final Properties properties, final CacheDataDescription metadata) throws CacheException { + return underlyingRegionFactory.buildCollectionRegion(regionName, properties, metadata); + } + + /** + * {@inheritDoc} + */ + public final QueryResultsRegion buildQueryResultsRegion(final String regionName, final Properties properties) throws CacheException { + return underlyingRegionFactory.buildQueryResultsRegion(regionName, properties); + } + + /** + * {@inheritDoc} + */ + public final TimestampsRegion buildTimestampsRegion(final String regionName, final Properties properties) throws CacheException { + return underlyingRegionFactory.buildTimestampsRegion(regionName, properties); + } +} diff --git a/hibernate-ehcache/src/main/java/org/hibernate/cache/EhCache.java b/hibernate-ehcache/src/main/java/org/hibernate/cache/EhCache.java index 30f3c019f6..b638dab3c6 100644 --- a/hibernate-ehcache/src/main/java/org/hibernate/cache/EhCache.java +++ b/hibernate-ehcache/src/main/java/org/hibernate/cache/EhCache.java @@ -23,15 +23,15 @@ */ package org.hibernate.cache; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - import net.sf.ehcache.CacheManager; import net.sf.ehcache.Element; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + /** * EHCache plugin for Hibernate *

diff --git a/hibernate-ehcache/src/main/java/org/hibernate/cache/EhCacheProvider.java b/hibernate-ehcache/src/main/java/org/hibernate/cache/EhCacheProvider.java index 082779e8f6..5821364f1e 100644 --- a/hibernate-ehcache/src/main/java/org/hibernate/cache/EhCacheProvider.java +++ b/hibernate-ehcache/src/main/java/org/hibernate/cache/EhCacheProvider.java @@ -23,15 +23,15 @@ */ package org.hibernate.cache; -import java.util.Properties; -import java.net.URL; - import net.sf.ehcache.CacheManager; +import org.hibernate.cfg.Environment; +import org.hibernate.util.ConfigHelper; +import org.hibernate.util.StringHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.hibernate.cfg.Environment; -import org.hibernate.util.StringHelper; -import org.hibernate.util.ConfigHelper; + +import java.net.URL; +import java.util.Properties; /** * Cache Provider plugin for Hibernate diff --git a/hibernate-ehcache/src/main/java/org/hibernate/cache/EhCacheRegionFactory.java b/hibernate-ehcache/src/main/java/org/hibernate/cache/EhCacheRegionFactory.java new file mode 100644 index 0000000000..28eae11f38 --- /dev/null +++ b/hibernate-ehcache/src/main/java/org/hibernate/cache/EhCacheRegionFactory.java @@ -0,0 +1,41 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2007, 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.cache; + +import java.util.Properties; + +/** + * Thin wrapper class around the within Ehcache-core packaged EhCacheRegionFactory. + * It directly delegates to the wrapped instance, enabling users to upgrade Ehcache-core versions + * by simply dropping in the new jar. + * + * @author Alex Snaps + */ +public final class EhCacheRegionFactory extends AbstractEhCacheRegionFactory { + + public EhCacheRegionFactory(Properties properties) { + super(new net.sf.ehcache.hibernate.EhCacheRegionFactory(properties)); + } +} diff --git a/hibernate-ehcache/src/main/java/org/hibernate/cache/SingletonEhCacheProvider.java b/hibernate-ehcache/src/main/java/org/hibernate/cache/SingletonEhCacheProvider.java index e3b627b3ea..204a5bef0c 100644 --- a/hibernate-ehcache/src/main/java/org/hibernate/cache/SingletonEhCacheProvider.java +++ b/hibernate-ehcache/src/main/java/org/hibernate/cache/SingletonEhCacheProvider.java @@ -29,8 +29,8 @@ import net.sf.ehcache.util.ClassLoaderUtil; import java.net.URL; import java.util.Properties; -import java.util.logging.Logger; import java.util.logging.Level; +import java.util.logging.Logger; /** * Singleton cache Provider plugin for Hibernate 3.2 and ehcache-1.2. New in this provider is support for diff --git a/hibernate-ehcache/src/main/java/org/hibernate/cache/SingletonEhCacheRegionFactory.java b/hibernate-ehcache/src/main/java/org/hibernate/cache/SingletonEhCacheRegionFactory.java new file mode 100644 index 0000000000..cbcef114fb --- /dev/null +++ b/hibernate-ehcache/src/main/java/org/hibernate/cache/SingletonEhCacheRegionFactory.java @@ -0,0 +1,41 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2007, 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.cache; + +import java.util.Properties; + +/** + * Thin wrapper class around the within Ehcache-core packaged SingletonEhCacheRegionFactory. + * It directly delegates to the wrapped instance, enabling user to upgrade the Ehcache-core version + * by simply dropping in a new jar. + * + * @author Alex Snaps + */ +public final class SingletonEhCacheRegionFactory extends AbstractEhCacheRegionFactory { + + public SingletonEhCacheRegionFactory(Properties properties) { + super(new net.sf.ehcache.hibernate.SingletonEhCacheRegionFactory(properties)); + } +} From f125f06c4575294ed58960f6e09c524d29114440 Mon Sep 17 00:00:00 2001 From: Erik-Berndt Scheper Date: Wed, 22 Dec 2010 11:37:07 +0100 Subject: [PATCH 20/21] HHH-5750 - Proxied objects lose the temporary session used to initialize them --- .../org/hibernate/envers/tools/Tools.java | 1 - .../proxy/AuditedCollectionProxyTest.java | 76 +++++++++++++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 hibernate-envers/src/test/java/org/hibernate/envers/test/integration/proxy/AuditedCollectionProxyTest.java diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/tools/Tools.java b/hibernate-envers/src/main/java/org/hibernate/envers/tools/Tools.java index 6a420588b3..cffe0fcd0a 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/tools/Tools.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/tools/Tools.java @@ -82,7 +82,6 @@ public class Tools { proxy.getHibernateLazyInitializer().getEntityName(), proxy.getHibernateLazyInitializer().getIdentifier() ); - proxy.getHibernateLazyInitializer().setImplementation( target ); return target; } finally { diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/proxy/AuditedCollectionProxyTest.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/proxy/AuditedCollectionProxyTest.java new file mode 100644 index 0000000000..da0dab29eb --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/proxy/AuditedCollectionProxyTest.java @@ -0,0 +1,76 @@ +package org.hibernate.envers.test.integration.proxy; + +import javax.persistence.EntityManager; + +import org.hibernate.ejb.Ejb3Configuration; +import org.hibernate.envers.test.AbstractEntityTest; +import org.hibernate.envers.test.entities.onetomany.ListRefEdEntity; +import org.hibernate.envers.test.entities.onetomany.ListRefIngEntity; +import org.hibernate.proxy.HibernateProxy; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +/** + * Test case for HHH-5750: Proxied objects lose the temporary session used to + * initialize them. + * + * @author Erik-Berndt Scheper + * + */ +public class AuditedCollectionProxyTest extends AbstractEntityTest { + + Integer id_ListRefEdEntity1; + + public void configure(Ejb3Configuration cfg) { + cfg.addAnnotatedClass(ListRefEdEntity.class); + cfg.addAnnotatedClass(ListRefIngEntity.class); + } + + @BeforeClass(dependsOnMethods = "init") + public void initData() { + EntityManager em = getEntityManager(); + + ListRefEdEntity listReferencedEntity1 = new ListRefEdEntity( + Integer.valueOf(1), "str1"); + ListRefIngEntity refingEntity1 = new ListRefIngEntity( + Integer.valueOf(1), "refing1", listReferencedEntity1); + + // Revision 1 + em.getTransaction().begin(); + em.persist(listReferencedEntity1); + em.persist(refingEntity1); + em.getTransaction().commit(); + + id_ListRefEdEntity1 = listReferencedEntity1.getId(); + + // Revision 2 + ListRefIngEntity refingEntity2 = new ListRefIngEntity( + Integer.valueOf(2), "refing2", listReferencedEntity1); + + em.getTransaction().begin(); + em.persist(refingEntity2); + em.getTransaction().commit(); + } + + @Test + public void testProxyIdentifier() { + EntityManager em = getEntityManager(); + + ListRefEdEntity listReferencedEntity1 = em.getReference( + ListRefEdEntity.class, id_ListRefEdEntity1); + + assert listReferencedEntity1 instanceof HibernateProxy; + + // Revision 3 + ListRefIngEntity refingEntity3 = new ListRefIngEntity( + Integer.valueOf(3), "refing3", listReferencedEntity1); + + em.getTransaction().begin(); + em.persist(refingEntity3); + em.getTransaction().commit(); + + listReferencedEntity1.getReffering().size(); + + } + +} From 6ac46d506b04d589c84d179e61ad5a12811db550 Mon Sep 17 00:00:00 2001 From: Erik-Berndt Scheper Date: Wed, 22 Dec 2010 11:47:09 +0100 Subject: [PATCH 21/21] HHH-5750 - Added license header --- .../proxy/AuditedCollectionProxyTest.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/proxy/AuditedCollectionProxyTest.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/proxy/AuditedCollectionProxyTest.java index da0dab29eb..3c009f5bdc 100644 --- a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/proxy/AuditedCollectionProxyTest.java +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/proxy/AuditedCollectionProxyTest.java @@ -1,3 +1,26 @@ +/* + * 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.envers.test.integration.proxy; import javax.persistence.EntityManager;