From a0d8e6a41577f2b17b15e847c41ac6f7e1f9cdb6 Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Wed, 27 Jan 2010 06:36:55 +0000 Subject: [PATCH] HHH-2501 HHH-4804 : Add default read-only/modifiable setting for session; fix setting for non-lazy associations loaded from Query git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@18641 1b8cb986-b30d-0410-93ca-fae66ebed9b2 --- core/src/main/java/org/hibernate/Query.java | 41 +- core/src/main/java/org/hibernate/Session.java | 56 +- .../hibernate/engine/PersistenceContext.java | 71 +- .../org/hibernate/engine/QueryParameters.java | 78 + .../engine/StatefulPersistenceContext.java | 20 +- .../event/def/DefaultLoadEventListener.java | 8 +- .../org/hibernate/impl/AbstractQueryImpl.java | 18 +- .../java/org/hibernate/impl/SessionImpl.java | 14 + .../hibernate/impl/StatelessSessionImpl.java | 16 + .../java/org/hibernate/loader/Loader.java | 31 +- .../proxy/AbstractLazyInitializer.java | 6 +- .../pojo/cglib/CGLIBLazyInitializer.java | 1 + .../proxy/pojo/cglib/SerializableProxy.java | 4 + .../javassist/JavassistLazyInitializer.java | 1 + .../pojo/javassist/SerializableProxy.java | 4 + .../test/immutable/ImmutableTest.java | 398 ++++- .../test/nonflushedchanges/GetLoadTest.java | 129 ++ .../hibernate/test/readonly/Container.java | 117 ++ .../hibernate/test/readonly/DataPoint.hbm.xml | 39 + .../hibernate/test/readonly/DataPoint.java | 15 +- .../org/hibernate/test/readonly/Info.java | 34 + .../org/hibernate/test/readonly/Owner.java | 34 + .../ReadOnlySessionLazyNonLazyTest.java | 1446 +++++++++++++++++ .../test/readonly/ReadOnlySessionTest.java | 456 ++++++ .../hibernate/test/readonly/ReadOnlyTest.java | 58 + 25 files changed, 3055 insertions(+), 40 deletions(-) create mode 100644 testsuite/src/test/java/org/hibernate/test/readonly/Container.java create mode 100644 testsuite/src/test/java/org/hibernate/test/readonly/Info.java create mode 100644 testsuite/src/test/java/org/hibernate/test/readonly/Owner.java create mode 100644 testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlySessionLazyNonLazyTest.java create mode 100644 testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlySessionTest.java diff --git a/core/src/main/java/org/hibernate/Query.java b/core/src/main/java/org/hibernate/Query.java index 21092dbe92..6bc3f641f7 100644 --- a/core/src/main/java/org/hibernate/Query.java +++ b/core/src/main/java/org/hibernate/Query.java @@ -175,11 +175,46 @@ public interface Query { public Query setFirstResult(int firstResult); /** - * Entities retrieved by this query will be loaded in - * a read-only mode where Hibernate will never dirty-check - * them or make changes persistent. + * Should entities and proxies loaded by this Query be put in read-only mode? If the + * read-only/modifiable setting was not initialized, then the default + * read-only/modifiable setting for the persistence context is returned instead. + * @see Query#setReadOnly(boolean) + * @see org.hibernate.engine.PersistenceContext#isDefaultReadOnly() * + * The read-only/modifiable setting has no impact on entities/proxies returned by the + * query that existed in the session before the query was executed. + * + * @return true, entities and proxies loaded by the query will be put in read-only mode + * false, entities and proxies loaded by the query will be put in modifiable mode */ + public boolean isReadOnly(); + + /** + * Set the read-only/modifiable mode for entities and proxies + * loaded by this Query. This setting overrides the default setting + * for the persistence context. + * @see org.hibernate.engine.PersistenceContext#isDefaultReadOnly() + * + * To set the default read-only/modifiable setting used for + * entities and proxies that are loaded into the session: + * @see org.hibernate.engine.PersistenceContext#setDefaultReadOnly(boolean) + * @see org.hibernate.Session#setDefaultReadOnly(boolean) + * + * Read-only entities are not dirty-checked and snapshots of persistent + * state are not maintained. Read-only entities can be modified, but + * changes are not persisted. + * + * When a proxy is initialized, the loaded entity will have the same + * read-only/modifiable setting as the uninitialized + * proxy has, regardless of the session's current setting. + * + * The read-only/modifiable setting has no impact on entities/proxies + * returned by the query that existed in the session before the query was executed. + * + * @return true, entities and proxies loaded by the query will be put in read-only mode + * false, entities and proxies loaded by the query will be put in modifiable mode + */ + public Query setReadOnly(boolean readOnly); /** diff --git a/core/src/main/java/org/hibernate/Session.java b/core/src/main/java/org/hibernate/Session.java index 2a2d06aa79..457d8cc551 100644 --- a/core/src/main/java/org/hibernate/Session.java +++ b/core/src/main/java/org/hibernate/Session.java @@ -231,6 +231,44 @@ public interface Session extends Serializable { */ public boolean isDirty() throws HibernateException; + /** + * Will entities and proxies that are loaded into this session be made + * read-only by default? + * + * To determine the read-only/modifiable setting for a particular entity + * or proxy: + * @see Session#isReadOnly(Object) + * + * @return true, loaded entities/proxies will be made read-only by default; + * false, loaded entities/proxies will be made modifiable by default. + */ + public boolean isDefaultReadOnly(); + + /** + * Change the default for entities and proxies loaded into this session + * from modifiable to read-only mode, or from modifiable to read-only mode. + * + * Read-only entities are not dirty-checked and snapshots of persistent + * state are not maintained. Read-only entities can be modified, but + * changes are not persisted. + * + * When a proxy is initialized, the loaded entity will have the same + * read-only/modifiable setting as the uninitialized + * proxy has, regardless of the session's current setting. + * + * To change the read-only/modifiable setting for a particular entity + * or proxy that is already in this session: + * @see Session#setReadOnly(Object,boolean) + * + * To override this session's read-only/modifiable setting for entities + * and proxies loaded by a Query: + * @see Query#setReadOnly(boolean) + * + * @param readOnly true, the default for loaded entities/proxies is read-only; + * false, the default for loaded entities/proxies is modifiable + */ + public void setDefaultReadOnly(boolean readOnly); + /** * Return the identifier value of the given entity as associated with this * session. An exception is thrown if the given entity instance is transient @@ -842,6 +880,11 @@ public interface Session extends Serializable { /** * Is the specified entity or proxy read-only? + * + * To get the default read-only/modifiable setting used for + * entities and proxies that are loaded into the session: + * @see org.hibernate.Session#isDefaultReadOnly() + * * @param entityOrProxy, an entity or HibernateProxy * @return true, the entity or proxy is read-only; * false, the entity or proxy is modifiable. @@ -850,16 +893,23 @@ public interface Session extends Serializable { /** * Set an unmodified persistent object to read-only mode, or a read-only - * object to modifiable mode. In read-only mode, no snapshot is maintained - * and the instance is never dirty checked. + * object to modifiable mode. In read-only mode, no snapshot is maintained, + * the instance is never dirty checked, and changes are not persisted. * * If the entity or proxy already has the specified read-only/modifiable * setting, then this method does nothing. * + * To set the default read-only/modifiable setting used for + * entities and proxies that are loaded into the session: + * @see org.hibernate.Session#setDefaultReadOnly(boolean) + * + * To override this session's read-only/modifiable setting for entities + * and proxies loaded by a Query: + * @see Query#setReadOnly(boolean) + * * @param entityOrProxy, an entity or HibernateProxy * @param readOnly, if true, the entity or proxy is made read-only; * if false, the entity or proxy is made modifiable. - * @see Query#setReadOnly(boolean) */ public void setReadOnly(Object entityOrProxy, boolean readOnly); diff --git a/core/src/main/java/org/hibernate/engine/PersistenceContext.java b/core/src/main/java/org/hibernate/engine/PersistenceContext.java index 9abd5fcb34..99ee56b3f9 100644 --- a/core/src/main/java/org/hibernate/engine/PersistenceContext.java +++ b/core/src/main/java/org/hibernate/engine/PersistenceContext.java @@ -476,23 +476,92 @@ public interface PersistenceContext { */ public boolean isPropertyNull(EntityKey ownerKey, String propertyName); + /** + * Will entities and proxies that are loaded into this persistence + * context be made read-only by default? + * + * To determine the read-only/modifiable setting for a particular entity + * or proxy: + * @see PersistenceContext#isReadOnly(Object) + * @see org.hibernate.Session#isReadOnly(Object) + * + * @return true, loaded entities/proxies will be made read-only by default; + * false, loaded entities/proxies will be made modifiable by default. + * + * @see org.hibernate.Session#isDefaultReadOnly() + */ + public boolean isDefaultReadOnly(); + + /** + * Change the default for entities and proxies loaded into this persistence + * context from modifiable to read-only mode, or from modifiable to read-only + * mode. + * + * Read-only entities are not dirty-checked and snapshots of persistent + * state are not maintained. Read-only entities can be modified, but + * changes are not persisted. + * + * When a proxy is initialized, the loaded entity will have the same + * read-only/modifiable setting as the uninitialized + * proxy has, regardless of the persistence context's current setting. + * + * To change the read-only/modifiable setting for a particular entity + * or proxy that is already in this session: ++ * @see PersistenceContext#setReadOnly(Object,boolean) + * @see org.hibernate.Session#setReadOnly(Object, boolean) + * + * To override this session's read-only/modifiable setting for entities + * and proxies loaded by a Query: + * @see org.hibernate.Query#setReadOnly(boolean) + * + * @param readOnly true, the default for loaded entities/proxies is read-only; + * false, the default for loaded entities/proxies is modifiable + * + * @see org.hibernate.Session#setDefaultReadOnly(boolean) + */ + public void setDefaultReadOnly(boolean readOnly); + /** * Is the entity or proxy read-only? * + * To get the default read-only/modifiable setting used for + * entities and proxies that are loaded into the session: + * @see org.hibernate.Session#isDefaultReadOnly() + * * @param entityOrProxy * @return true, the object is read-only; false, the object is modifiable. */ public boolean isReadOnly(Object entityOrProxy); /** - * Set the entity or proxy to read only and discard it's snapshot. + * Set an unmodified persistent object to read-only mode, or a read-only + * object to modifiable mode. + * + * Read-only entities are not dirty-checked and snapshots of persistent + * state are not maintained. Read-only entities can be modified, but + * changes are not persisted. + * + * When a proxy is initialized, the loaded entity will have the same + * read-only/modifiable setting as the uninitialized + * proxy has, regardless of the session's current setting. * * If the entity or proxy already has the specified read-only/modifiable * setting, then this method does nothing. * + * To set the default read-only/modifiable setting used for + * entities and proxies that are loaded into this persistence context: + * @see PersistenceContext#setDefaultReadOnly(boolean) + * @see org.hibernate.Session#setDefaultReadOnly(boolean) + * + * To override this persistence context's read-only/modifiable setting + * for entities and proxies loaded by a Query: + * @see org.hibernate.Query#setReadOnly(boolean) + * * @param entityOrProxy, an entity or HibernateProxy * @param readOnly, if true, the entity or proxy is made read-only; * if false, the entity or proxy is made modifiable. + * + * @see org.hibernate.Session#setReadOnly(Object, boolean) */ public void setReadOnly(Object entityOrProxy, boolean readOnly); diff --git a/core/src/main/java/org/hibernate/engine/QueryParameters.java b/core/src/main/java/org/hibernate/engine/QueryParameters.java index a80e2ca88d..004ba924c4 100644 --- a/core/src/main/java/org/hibernate/engine/QueryParameters.java +++ b/core/src/main/java/org/hibernate/engine/QueryParameters.java @@ -66,6 +66,7 @@ public final class QueryParameters { private Object optionalObject; private String optionalEntityName; private Serializable optionalId; + private boolean isReadOnlyInitialized; private boolean readOnly; private boolean callable = false; private boolean autodiscovertypes = false; @@ -124,6 +125,7 @@ public final class QueryParameters { null, false, false, + false, null, null, collectionKeys, @@ -149,6 +151,7 @@ public final class QueryParameters { lockOptions, rowSelection, false, + false, cacheable, cacheRegion, comment, @@ -164,6 +167,7 @@ public final class QueryParameters { final Map namedParameters, final LockOptions lockOptions, final RowSelection rowSelection, + final boolean isReadOnlyInitialized, final boolean readOnly, final boolean cacheable, final String cacheRegion, @@ -181,6 +185,7 @@ public final class QueryParameters { //this.forceCacheRefresh = forceCacheRefresh; this.comment = comment; this.collectionKeys = collectionKeys; + this.isReadOnlyInitialized = isReadOnlyInitialized; this.readOnly = readOnly; this.resultTransformer = transformer; } @@ -191,6 +196,7 @@ public final class QueryParameters { final Map namedParameters, final LockOptions lockOptions, final RowSelection rowSelection, + final boolean isReadOnlyInitialized, final boolean readOnly, final boolean cacheable, final String cacheRegion, @@ -207,6 +213,7 @@ public final class QueryParameters { namedParameters, lockOptions, rowSelection, + isReadOnlyInitialized, readOnly, cacheable, cacheRegion, @@ -351,12 +358,82 @@ public final class QueryParameters { this.optionalObject = optionalObject; } + /** + * Has the read-only/modifiable mode been explicitly set? + * @see QueryParameters#setReadOnly(boolean) + * @see QueryParameters#isReadOnly(SessionImplementor) + * + * @return true, the read-only/modifiable mode was explicitly set + * false, the read-only/modifiable mode was not explicitly set + */ + public boolean isReadOnlyInitialized() { + return isReadOnlyInitialized; + } + + /** + * Should entities and proxies loaded by the Query be put in read-only mode? The + * read-only/modifiable setting must be initialized via QueryParameters#setReadOnly(boolean) + * before calling this method. + * + * @see QueryParameters#isReadOnlyInitialized() + * @see QueryParameters#isReadOnly(SessionImplementor) + * @see QueryParameters#setReadOnly(boolean) + * + * The read-only/modifiable setting has no impact on entities/proxies returned by the + * query that existed in the session before the query was executed. + * + * @return true, entities and proxies loaded by the Query will be put in read-only mode + * false, entities and proxies loaded by the Query will be put in modifiable mode + * @throws IllegalStateException if the read-only/modifiable setting has not been + * initialized (i.e., isReadOnlyInitialized() == false). + */ public boolean isReadOnly() { + if ( ! isReadOnlyInitialized() ) { + throw new IllegalStateException( "cannot call isReadOnly() when isReadOnlyInitialized() returns false" ); + } return readOnly; } + /** + * Should entities and proxies loaded by the Query be put in read-only mode? If the + * read-only/modifiable setting was not initialized + * (i.e., QueryParameters#isReadOnlyInitialized() == false), then the default + * read-only/modifiable setting for the persistence context is returned instead. + * + * @see QueryParameters#isReadOnlyInitialized() + * @see QueryParameters#setReadOnly(boolean) + * @see org.hibernate.engine.PersistenceContext#isDefaultReadOnly() + * + * The read-only/modifiable setting has no impact on entities/proxies returned by the + * query that existed in the session before the query was executed. + * + * @return true, entities and proxies loaded by the query will be put in read-only mode + * false, entities and proxies loaded by the query will be put in modifiable mode + */ + public boolean isReadOnly(SessionImplementor session) { + return ( isReadOnlyInitialized ? + isReadOnly() : + session.getPersistenceContext().isDefaultReadOnly() + ); + } + + /** + * Set the read-only/modifiable mode for entities and proxies loaded by the query. + * * + * @see QueryParameters#isReadOnlyInitialized() + * @see QueryParameters#isReadOnly(SessionImplementor) + * @see QueryParameters#setReadOnly(boolean) + * @see org.hibernate.engine.PersistenceContext#isDefaultReadOnly() + * + * The read-only/modifiable setting has no impact on entities/proxies returned by the + * query that existed in the session before the query was executed. + * + * @return true, entities and proxies loaded by the query will be put in read-only mode + * false, entities and proxies loaded by the query will be put in modifiable mode + */ public void setReadOnly(boolean readOnly) { this.readOnly = readOnly; + this.isReadOnlyInitialized = true; } public void setCallable(boolean callable) { @@ -467,6 +544,7 @@ public final class QueryParameters { this.namedParameters, this.lockOptions, selection, + this.isReadOnlyInitialized, this.readOnly, this.cacheable, this.cacheRegion, diff --git a/core/src/main/java/org/hibernate/engine/StatefulPersistenceContext.java b/core/src/main/java/org/hibernate/engine/StatefulPersistenceContext.java index 6097d9fa3e..7367aac18b 100644 --- a/core/src/main/java/org/hibernate/engine/StatefulPersistenceContext.java +++ b/core/src/main/java/org/hibernate/engine/StatefulPersistenceContext.java @@ -127,6 +127,7 @@ public class StatefulPersistenceContext implements PersistenceContext { private int loadCounter = 0; private boolean flushing = false; + private boolean defaultReadOnly = false; private boolean hasNonReadOnlyEntities = false; private LoadContexts loadContexts; @@ -231,12 +232,27 @@ public class StatefulPersistenceContext implements PersistenceContext { if ( batchFetchQueue != null ) { batchFetchQueue.clear(); } + // defaultReadOnly is unaffected by clear() hasNonReadOnlyEntities = false; if ( loadContexts != null ) { loadContexts.cleanup(); } } - + + /** + * {@inheritDoc} + */ + public boolean isDefaultReadOnly() { + return defaultReadOnly; + } + + /** + * {@inheritDoc} + */ + public void setDefaultReadOnly(boolean defaultReadOnly) { + this.defaultReadOnly = defaultReadOnly; + } + public boolean hasNonReadOnlyEntities() { return hasNonReadOnlyEntities; } @@ -1396,6 +1412,7 @@ public class StatefulPersistenceContext implements PersistenceContext { public void serialize(ObjectOutputStream oos) throws IOException { log.trace( "serializing persistent-context" ); + oos.writeBoolean( defaultReadOnly ); oos.writeBoolean( hasNonReadOnlyEntities ); oos.writeInt( entitiesByKey.size() ); @@ -1491,6 +1508,7 @@ public class StatefulPersistenceContext implements PersistenceContext { // because serialization is used for different things. try { + rtn.defaultReadOnly = ois.readBoolean(); // todo : we can actually just determine this from the incoming EntityEntry-s rtn.hasNonReadOnlyEntities = ois.readBoolean(); diff --git a/core/src/main/java/org/hibernate/event/def/DefaultLoadEventListener.java b/core/src/main/java/org/hibernate/event/def/DefaultLoadEventListener.java index df9498def4..6fad0849ad 100644 --- a/core/src/main/java/org/hibernate/event/def/DefaultLoadEventListener.java +++ b/core/src/main/java/org/hibernate/event/def/DefaultLoadEventListener.java @@ -298,6 +298,9 @@ public class DefaultLoadEventListener extends AbstractLockUpgradeEventListener i Object proxy = persister.createProxy( event.getEntityId(), event.getSession() ); persistenceContext.getBatchFetchQueue().addBatchLoadableEntityKey(keyToLoad); persistenceContext.addProxy(keyToLoad, proxy); + ( ( HibernateProxy ) proxy ) + .getHibernateLazyInitializer() + .setReadOnly( event.getSession().isDefaultReadOnly() || ! persister.isMutable() ); return proxy; } } @@ -599,7 +602,10 @@ public class DefaultLoadEventListener extends AbstractLockUpgradeEventListener i final PersistenceContext persistenceContext = session.getPersistenceContext(); persistenceContext.addEntry( result, - Status.MANAGED, + ( session.isDefaultReadOnly() || ! persister.isMutable() ? + Status.READ_ONLY : + Status.MANAGED + ), values, null, id, diff --git a/core/src/main/java/org/hibernate/impl/AbstractQueryImpl.java b/core/src/main/java/org/hibernate/impl/AbstractQueryImpl.java index 650e181610..7701dc55d1 100644 --- a/core/src/main/java/org/hibernate/impl/AbstractQueryImpl.java +++ b/core/src/main/java/org/hibernate/impl/AbstractQueryImpl.java @@ -101,7 +101,7 @@ public abstract class AbstractQueryImpl implements Query { private FlushMode sessionFlushMode; private CacheMode sessionCacheMode; private Serializable collectionKey; - private boolean readOnly; + private Boolean readOnly; private ResultTransformer resultTransformer; public AbstractQueryImpl( @@ -202,12 +202,21 @@ public abstract class AbstractQueryImpl implements Query { return this; } + /** + * {@inheritDoc} + */ public boolean isReadOnly() { - return readOnly; + return ( readOnly == null ? + getSession().getPersistenceContext().isDefaultReadOnly() : + readOnly.booleanValue() + ); } + /** + * {@inheritDoc} + */ public Query setReadOnly(boolean readOnly) { - this.readOnly = readOnly; + this.readOnly = Boolean.valueOf( readOnly ); return this; } @@ -881,7 +890,8 @@ public abstract class AbstractQueryImpl implements Query { namedParams, getLockOptions(), getSelection(), - readOnly, + true, + isReadOnly(), cacheable, cacheRegion, comment, diff --git a/core/src/main/java/org/hibernate/impl/SessionImpl.java b/core/src/main/java/org/hibernate/impl/SessionImpl.java index 059dae53cc..7fef12ee95 100644 --- a/core/src/main/java/org/hibernate/impl/SessionImpl.java +++ b/core/src/main/java/org/hibernate/impl/SessionImpl.java @@ -1956,6 +1956,20 @@ public final class SessionImpl extends AbstractSessionImpl return true; } + /** + * {@inheritDoc} + */ + public boolean isDefaultReadOnly() { + return persistenceContext.isDefaultReadOnly(); + } + + /** + * {@inheritDoc} + */ + public void setDefaultReadOnly(boolean defaultReadOnly) { + persistenceContext.setDefaultReadOnly( defaultReadOnly ); + } + public boolean isReadOnly(Object entityOrProxy) { errorIfClosed(); checkTransactionSynchStatus(); diff --git a/core/src/main/java/org/hibernate/impl/StatelessSessionImpl.java b/core/src/main/java/org/hibernate/impl/StatelessSessionImpl.java index df5e087a1a..a630f793e7 100755 --- a/core/src/main/java/org/hibernate/impl/StatelessSessionImpl.java +++ b/core/src/main/java/org/hibernate/impl/StatelessSessionImpl.java @@ -483,6 +483,22 @@ public class StatelessSessionImpl extends AbstractSessionImpl return false; } + /** + * {@inheritDoc} + */ + public boolean isDefaultReadOnly() { + return false; + } + + /** + * {@inheritDoc} + */ + public void setDefaultReadOnly(boolean readOnly) throws HibernateException { + if ( readOnly == true ) { + throw new UnsupportedOperationException(); + } + } + ///////////////////////////////////////////////////////////////////////////////////////////////////// //TODO: COPY/PASTE FROM SessionImpl, pull up! diff --git a/core/src/main/java/org/hibernate/loader/Loader.java b/core/src/main/java/org/hibernate/loader/Loader.java index f3e04315a8..ea147ecc1f 100644 --- a/core/src/main/java/org/hibernate/loader/Loader.java +++ b/core/src/main/java/org/hibernate/loader/Loader.java @@ -253,15 +253,32 @@ public abstract class Loader { throws HibernateException, SQLException { final PersistenceContext persistenceContext = session.getPersistenceContext(); + boolean defaultReadOnlyOrig = persistenceContext.isDefaultReadOnly(); + if ( queryParameters.isReadOnlyInitialized() ) { + // The read-only/modifiable mode for the query was explicitly set. + // Temporarily set the default read-only/modifiable setting to the query's setting. + persistenceContext.setDefaultReadOnly( queryParameters.isReadOnly() ); + } + else { + // The read-only/modifiable setting for the query was not initialized. + // Use the default read-only/modifiable from the persistence context instead. + queryParameters.setReadOnly( persistenceContext.isDefaultReadOnly() ); + } persistenceContext.beforeLoad(); List result; try { - result = doQuery( session, queryParameters, returnProxies ); + try { + result = doQuery( session, queryParameters, returnProxies ); + } + finally { + persistenceContext.afterLoad(); + } + persistenceContext.initializeNonLazyCollections(); } finally { - persistenceContext.afterLoad(); + // Restore the original default + persistenceContext.setDefaultReadOnly( defaultReadOnlyOrig ); } - persistenceContext.initializeNonLazyCollections(); return result; } @@ -312,7 +329,7 @@ public abstract class Loader { hydratedObjects, resultSet, session, - queryParameters.isReadOnly() + queryParameters.isReadOnly( session ) ); session.getPersistenceContext().initializeNonLazyCollections(); return result; @@ -363,7 +380,7 @@ public abstract class Loader { hydratedObjects, resultSet, session, - queryParameters.isReadOnly() + queryParameters.isReadOnly( session ) ); session.getPersistenceContext().initializeNonLazyCollections(); return result; @@ -749,7 +766,7 @@ public abstract class Loader { session.getBatcher().closeQueryStatement( st, rs ); } - initializeEntitiesAndCollections( hydratedObjects, rs, session, queryParameters.isReadOnly() ); + initializeEntitiesAndCollections( hydratedObjects, rs, session, queryParameters.isReadOnly( session ) ); if ( createSubselects ) createSubselects( subselectResultKeys, queryParameters, session ); @@ -1884,7 +1901,7 @@ public abstract class Loader { try { result = doQueryAndInitializeNonLazyCollections( session, - new QueryParameters( + new QueryParameters( new Type[] { identifierType }, new Object[] { id }, optionalObject, diff --git a/core/src/main/java/org/hibernate/proxy/AbstractLazyInitializer.java b/core/src/main/java/org/hibernate/proxy/AbstractLazyInitializer.java index 25e4ae2bb6..67c7bba03d 100755 --- a/core/src/main/java/org/hibernate/proxy/AbstractLazyInitializer.java +++ b/core/src/main/java/org/hibernate/proxy/AbstractLazyInitializer.java @@ -65,11 +65,11 @@ public abstract class AbstractLazyInitializer implements LazyInitializer { protected AbstractLazyInitializer(String entityName, Serializable id, SessionImplementor session) { this.entityName = entityName; this.id = id; + this.readOnly = false; // initialize other fields depending on session state if ( session == null ) { // would be better to call unsetSession(), but it is not final... session = null; - readOnly = false; } else { setSession( session ); @@ -116,11 +116,11 @@ public abstract class AbstractLazyInitializer implements LazyInitializer { */ public final void setSession(SessionImplementor s) throws HibernateException { if ( s != session ) { + readOnly = false; // check for s == null first, since it is least expensive if ( s == null ){ // would be better to call unsetSession(), but it is not final... session = null; - readOnly = false; } else if ( isConnectedToSession() ) { //TODO: perhaps this should be some other RuntimeException... @@ -128,8 +128,6 @@ public abstract class AbstractLazyInitializer implements LazyInitializer { } else { session = s; - // NOTE: the proxy may not be connected to the session yet, so set readOnly directly - readOnly = ! session.getFactory().getEntityPersister( entityName ).isMutable(); } } } diff --git a/core/src/main/java/org/hibernate/proxy/pojo/cglib/CGLIBLazyInitializer.java b/core/src/main/java/org/hibernate/proxy/pojo/cglib/CGLIBLazyInitializer.java index 8217d0547b..43923da577 100644 --- a/core/src/main/java/org/hibernate/proxy/pojo/cglib/CGLIBLazyInitializer.java +++ b/core/src/main/java/org/hibernate/proxy/pojo/cglib/CGLIBLazyInitializer.java @@ -212,6 +212,7 @@ public final class CGLIBLazyInitializer extends BasicLazyInitializer implements persistentClass, interfaces, getIdentifier(), + ( getSession() != null && getSession().isOpen() ? isReadOnly() : false ), getIdentifierMethod, setIdentifierMethod, componentIdType diff --git a/core/src/main/java/org/hibernate/proxy/pojo/cglib/SerializableProxy.java b/core/src/main/java/org/hibernate/proxy/pojo/cglib/SerializableProxy.java index 4c33635dad..34fd2ea513 100644 --- a/core/src/main/java/org/hibernate/proxy/pojo/cglib/SerializableProxy.java +++ b/core/src/main/java/org/hibernate/proxy/pojo/cglib/SerializableProxy.java @@ -28,6 +28,7 @@ import java.io.Serializable; import java.lang.reflect.Method; import org.hibernate.HibernateException; +import org.hibernate.proxy.HibernateProxy; import org.hibernate.type.AbstractComponentType; /** @@ -39,6 +40,7 @@ public final class SerializableProxy implements Serializable { private Class persistentClass; private Class[] interfaces; private Serializable id; + private boolean readOnly; private Class getIdentifierMethodClass; private Class setIdentifierMethodClass; private String getIdentifierMethodName; @@ -53,6 +55,7 @@ public final class SerializableProxy implements Serializable { final Class persistentClass, final Class[] interfaces, final Serializable id, + final boolean readOnly, final Method getIdentifierMethod, final Method setIdentifierMethod, AbstractComponentType componentIdType @@ -61,6 +64,7 @@ public final class SerializableProxy implements Serializable { this.persistentClass = persistentClass; this.interfaces = interfaces; this.id = id; + this.readOnly = readOnly; if (getIdentifierMethod!=null) { getIdentifierMethodClass = getIdentifierMethod.getDeclaringClass(); getIdentifierMethodName = getIdentifierMethod.getName(); diff --git a/core/src/main/java/org/hibernate/proxy/pojo/javassist/JavassistLazyInitializer.java b/core/src/main/java/org/hibernate/proxy/pojo/javassist/JavassistLazyInitializer.java index b7a01399bf..46c0024c47 100644 --- a/core/src/main/java/org/hibernate/proxy/pojo/javassist/JavassistLazyInitializer.java +++ b/core/src/main/java/org/hibernate/proxy/pojo/javassist/JavassistLazyInitializer.java @@ -229,6 +229,7 @@ public class JavassistLazyInitializer extends BasicLazyInitializer implements Me persistentClass, interfaces, getIdentifier(), + ( getSession() != null && getSession().isOpen() ? isReadOnly() : false ), getIdentifierMethod, setIdentifierMethod, componentIdType diff --git a/core/src/main/java/org/hibernate/proxy/pojo/javassist/SerializableProxy.java b/core/src/main/java/org/hibernate/proxy/pojo/javassist/SerializableProxy.java index 30c00abdd9..1516a41a91 100644 --- a/core/src/main/java/org/hibernate/proxy/pojo/javassist/SerializableProxy.java +++ b/core/src/main/java/org/hibernate/proxy/pojo/javassist/SerializableProxy.java @@ -28,6 +28,7 @@ import java.io.Serializable; import java.lang.reflect.Method; import org.hibernate.HibernateException; +import org.hibernate.proxy.HibernateProxy; import org.hibernate.type.AbstractComponentType; /** @@ -39,6 +40,7 @@ public final class SerializableProxy implements Serializable { private Class persistentClass; private Class[] interfaces; private Serializable id; + private boolean readOnly; private Class getIdentifierMethodClass; private Class setIdentifierMethodClass; private String getIdentifierMethodName; @@ -53,6 +55,7 @@ public final class SerializableProxy implements Serializable { final Class persistentClass, final Class[] interfaces, final Serializable id, + final boolean readOnly, final Method getIdentifierMethod, final Method setIdentifierMethod, AbstractComponentType componentIdType @@ -61,6 +64,7 @@ public final class SerializableProxy implements Serializable { this.persistentClass = persistentClass; this.interfaces = interfaces; this.id = id; + this.readOnly = readOnly; if (getIdentifierMethod!=null) { getIdentifierMethodClass = getIdentifierMethod.getDeclaringClass(); getIdentifierMethodName = getIdentifierMethod.getName(); diff --git a/testsuite/src/test/java/org/hibernate/test/immutable/ImmutableTest.java b/testsuite/src/test/java/org/hibernate/test/immutable/ImmutableTest.java index fbdf1070b4..f9ea84847f 100755 --- a/testsuite/src/test/java/org/hibernate/test/immutable/ImmutableTest.java +++ b/testsuite/src/test/java/org/hibernate/test/immutable/ImmutableTest.java @@ -29,6 +29,7 @@ import java.util.Iterator; import junit.framework.Test; +import org.hibernate.Hibernate; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.Transaction; @@ -53,7 +54,234 @@ public class ImmutableTest extends FunctionalTestCase { return new FunctionalTestClassTestSuite( ImmutableTest.class ); } + public void testPersistImmutable() { + Contract c = new Contract("gavin", "phone"); + ContractVariation cv1 = new ContractVariation(1, c); + cv1.setText("expensive"); + ContractVariation cv2 = new ContractVariation(2, c); + cv2.setText("more expensive"); + Session s = openSession(); + Transaction t = s.beginTransaction(); + s.persist(c); + // c, cv1, and cv2 were added to s by s.persist(c) (not hibernate), so they are modifiable + assertFalse( s.isReadOnly( c ) ); + assertFalse( s.isReadOnly( cv1 ) ); + assertFalse( s.isReadOnly( cv2 ) ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + c = (Contract) s.createCriteria(Contract.class).uniqueResult(); + // c was loaded into s by hibernate, so it should be read-only + assertTrue( s.isReadOnly( c ) ); + assertEquals( c.getCustomerName(), "gavin" ); + assertEquals( c.getVariations().size(), 2 ); + Iterator it = c.getVariations().iterator(); + cv1 = (ContractVariation) it.next(); + assertEquals( cv1.getText(), "expensive" ); + cv2 = (ContractVariation) it.next(); + assertEquals( cv2.getText(), "more expensive" ); + // cv1 and cv2 were loaded into s by hibernate, so they should be read-only + assertTrue( s.isReadOnly( cv1 ) ); + assertTrue( s.isReadOnly( cv2 ) ); + s.delete(c); + assertEquals( s.createCriteria(Contract.class).setProjection( Projections.rowCount() ).uniqueResult(), new Long(0) ); + assertEquals( s.createCriteria(ContractVariation.class).setProjection( Projections.rowCount() ).uniqueResult(), new Long(0) ); + t.commit(); + s.close(); + } + + public void testSaveImmutable() { + Contract c = new Contract("gavin", "phone"); + ContractVariation cv1 = new ContractVariation(1, c); + cv1.setText("expensive"); + ContractVariation cv2 = new ContractVariation(2, c); + cv2.setText("more expensive"); + Session s = openSession(); + Transaction t = s.beginTransaction(); + s.save(c); + // c, cv1, and cv2 were added to s by s.persist(c) (not hibernate), so they are modifiable + assertFalse( s.isReadOnly( c ) ); + assertFalse( s.isReadOnly( cv1 ) ); + assertFalse( s.isReadOnly( cv2 ) ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + c = (Contract) s.createCriteria(Contract.class).uniqueResult(); + // c was loaded into s by hibernate, so it should be read-only + assertTrue( s.isReadOnly( c ) ); + assertEquals( c.getCustomerName(), "gavin" ); + assertEquals( c.getVariations().size(), 2 ); + Iterator it = c.getVariations().iterator(); + cv1 = (ContractVariation) it.next(); + assertEquals( cv1.getText(), "expensive" ); + cv2 = (ContractVariation) it.next(); + assertEquals( cv2.getText(), "more expensive" ); + // cv1 and cv2 were loaded into s by hibernate, so they should be read-only + assertTrue( s.isReadOnly( cv1 ) ); + assertTrue( s.isReadOnly( cv2 ) ); + s.delete(c); + assertEquals( s.createCriteria(Contract.class).setProjection( Projections.rowCount() ).uniqueResult(), new Long(0) ); + assertEquals( s.createCriteria(ContractVariation.class).setProjection( Projections.rowCount() ).uniqueResult(), new Long(0) ); + t.commit(); + s.close(); + } + + public void testSaveOrUpdateImmutable() { + Contract c = new Contract("gavin", "phone"); + ContractVariation cv1 = new ContractVariation(1, c); + cv1.setText("expensive"); + ContractVariation cv2 = new ContractVariation(2, c); + cv2.setText("more expensive"); + Session s = openSession(); + Transaction t = s.beginTransaction(); + s.saveOrUpdate(c); + // c, cv1, and cv2 were added to s by s.persist(c) (not hibernate), so they are modifiable + assertFalse( s.isReadOnly( c ) ); + assertFalse( s.isReadOnly( cv1 ) ); + assertFalse( s.isReadOnly( cv2 ) ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + c = (Contract) s.createCriteria(Contract.class).uniqueResult(); + // c was loaded into s by hibernate, so it should be read-only + assertTrue( s.isReadOnly( c ) ); + assertEquals( c.getCustomerName(), "gavin" ); + assertEquals( c.getVariations().size(), 2 ); + Iterator it = c.getVariations().iterator(); + cv1 = (ContractVariation) it.next(); + assertEquals( cv1.getText(), "expensive" ); + cv2 = (ContractVariation) it.next(); + assertEquals( cv2.getText(), "more expensive" ); + // cv1 and cv2 were loaded into s by hibernate, so they should be read-only + assertTrue( s.isReadOnly( cv1 ) ); + assertTrue( s.isReadOnly( cv2 ) ); + s.delete(c); + assertEquals( s.createCriteria(Contract.class).setProjection( Projections.rowCount() ).uniqueResult(), new Long(0) ); + assertEquals( s.createCriteria(ContractVariation.class).setProjection( Projections.rowCount() ).uniqueResult(), new Long(0) ); + t.commit(); + s.close(); + } + public void testImmutable() { + Contract c = new Contract("gavin", "phone"); + ContractVariation cv1 = new ContractVariation(1, c); + cv1.setText("expensive"); + ContractVariation cv2 = new ContractVariation(2, c); + cv2.setText("more expensive"); + Session s = openSession(); + Transaction t = s.beginTransaction(); + s.persist(c); + // c, cv1, and cv2 were added to s by s.persist(c) (not hibernate), so they are modifiable + assertFalse( s.isReadOnly( c ) ); + assertFalse( s.isReadOnly( cv1 ) ); + assertFalse( s.isReadOnly( cv2 ) ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + c = (Contract) s.createCriteria(Contract.class).uniqueResult(); + // c was loaded into s, so it should be read-only + assertTrue( s.isReadOnly( c ) ); + c.setCustomerName("foo bar"); + c.getVariations().add( new ContractVariation(3, c) ); + cv1 = (ContractVariation) c.getVariations().iterator().next(); + cv1.setText("blah blah"); + // cv1 and cv2 were loaded into s by hibernate, so they should be read-only + assertTrue( s.isReadOnly( cv1 ) ); + assertFalse( s.contains( cv2 ) ); + t.commit(); + assertTrue( s.isReadOnly( c ) ); + assertTrue( s.isReadOnly( cv1 ) ); + assertFalse( s.contains( cv2 ) ); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + c = (Contract) s.createCriteria(Contract.class).uniqueResult(); + // c was loaded into s by hibernate, so it should be read-only + assertTrue( s.isReadOnly( c ) ); + assertEquals( c.getCustomerName(), "gavin" ); + assertEquals( c.getVariations().size(), 2 ); + Iterator it = c.getVariations().iterator(); + cv1 = (ContractVariation) it.next(); + assertEquals( cv1.getText(), "expensive" ); + cv2 = (ContractVariation) it.next(); + assertEquals( cv2.getText(), "more expensive" ); + // cv1 and cv2 were loaded into s by hibernate, so they should be read-only + assertTrue( s.isReadOnly( cv1 ) ); + assertTrue( s.isReadOnly( cv2 ) ); + s.delete(c); + assertEquals( s.createCriteria(Contract.class).setProjection( Projections.rowCount() ).uniqueResult(), new Long(0) ); + assertEquals( s.createCriteria(ContractVariation.class).setProjection( Projections.rowCount() ).uniqueResult(), new Long(0) ); + t.commit(); + s.close(); + } + + public void testPersistAndUpdateImmutable() { + Contract c = new Contract("gavin", "phone"); + ContractVariation cv1 = new ContractVariation(1, c); + cv1.setText("expensive"); + ContractVariation cv2 = new ContractVariation(2, c); + cv2.setText("more expensive"); + Session s = openSession(); + Transaction t = s.beginTransaction(); + s.persist(c); + // c, cv1, and cv2 were added to s by s.persist(c) (not hibernate), so they are modifiable + assertFalse( s.isReadOnly( c ) ); + assertFalse( s.isReadOnly( cv1 ) ); + assertFalse( s.isReadOnly( cv2 ) ); + c.setCustomerName( "Sherman" ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + c = (Contract) s.createCriteria(Contract.class).uniqueResult(); + // c was loaded into s, so it should be read-only + assertTrue( s.isReadOnly( c ) ); + c.setCustomerName("foo bar"); + c.getVariations().add( new ContractVariation(3, c) ); + cv1 = (ContractVariation) c.getVariations().iterator().next(); + cv1.setText("blah blah"); + // cv1 and cv2 were loaded into s by hibernate, so they should be read-only + assertTrue( s.isReadOnly( cv1 ) ); + assertFalse( s.contains( cv2 ) ); + t.commit(); + assertTrue( s.isReadOnly( c ) ); + assertTrue( s.isReadOnly( cv1 ) ); + assertFalse( s.contains( cv2 ) ); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + c = (Contract) s.createCriteria(Contract.class).uniqueResult(); + // c was loaded into s by hibernate, so it should be read-only + assertTrue( s.isReadOnly( c ) ); + assertEquals( c.getCustomerName(), "gavin" ); + assertEquals( c.getVariations().size(), 2 ); + Iterator it = c.getVariations().iterator(); + cv1 = (ContractVariation) it.next(); + assertEquals( cv1.getText(), "expensive" ); + cv2 = (ContractVariation) it.next(); + assertEquals( cv2.getText(), "more expensive" ); + // cv1 and cv2 were loaded into s by hibernate, so they should be read-only + assertTrue( s.isReadOnly( cv1 ) ); + assertTrue( s.isReadOnly( cv2 ) ); + s.delete(c); + assertEquals( s.createCriteria(Contract.class).setProjection( Projections.rowCount() ).uniqueResult(), new Long(0) ); + assertEquals( s.createCriteria(ContractVariation.class).setProjection( Projections.rowCount() ).uniqueResult(), new Long(0) ); + t.commit(); + s.close(); + } + + public void testUpdateAndDeleteManagedImmutable() { Contract c = new Contract("gavin", "phone"); ContractVariation cv1 = new ContractVariation(1, c); cv1.setText("expensive"); @@ -64,20 +292,12 @@ public class ImmutableTest extends FunctionalTestCase { s.persist(c); t.commit(); s.close(); - - s = openSession(); - t = s.beginTransaction(); - c = (Contract) s.createCriteria(Contract.class).uniqueResult(); - c.setCustomerName("foo bar"); - c.getVariations().add( new ContractVariation(3, c) ); - cv1 = (ContractVariation) c.getVariations().iterator().next(); - cv1.setText("blah blah"); - t.commit(); - s.close(); - + s = openSession(); t = s.beginTransaction(); c = (Contract) s.createCriteria(Contract.class).uniqueResult(); + // c was loaded into s by hibernate, so it should be read-only + assertTrue( s.isReadOnly( c ) ); assertEquals( c.getCustomerName(), "gavin" ); assertEquals( c.getVariations().size(), 2 ); Iterator it = c.getVariations().iterator(); @@ -85,6 +305,10 @@ public class ImmutableTest extends FunctionalTestCase { assertEquals( cv1.getText(), "expensive" ); cv2 = (ContractVariation) it.next(); assertEquals( cv2.getText(), "more expensive" ); + // cv1 and cv2 were loaded into s by hibernate, so they should be read-only + assertTrue( s.isReadOnly( cv1 ) ); + assertTrue( s.isReadOnly( cv2 ) ); + c.setCustomerName( "Sherman" ); s.delete(c); assertEquals( s.createCriteria(Contract.class).setProjection( Projections.rowCount() ).uniqueResult(), new Long(0) ); assertEquals( s.createCriteria(ContractVariation.class).setProjection( Projections.rowCount() ).uniqueResult(), new Long(0) ); @@ -92,6 +316,117 @@ public class ImmutableTest extends FunctionalTestCase { s.close(); } + public void testGetAndDeleteManagedImmutable() { + Contract c = new Contract("gavin", "phone"); + ContractVariation cv1 = new ContractVariation(1, c); + cv1.setText("expensive"); + ContractVariation cv2 = new ContractVariation(2, c); + cv2.setText("more expensive"); + Session s = openSession(); + Transaction t = s.beginTransaction(); + s.persist(c); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + c = (Contract) s.get( Contract.class, c.getId() ); + // c was loaded into s by hibernate, so it should be read-only + assertTrue( s.isReadOnly( c ) ); + assertEquals( c.getCustomerName(), "gavin" ); + assertEquals( c.getVariations().size(), 2 ); + Iterator it = c.getVariations().iterator(); + cv1 = (ContractVariation) it.next(); + assertEquals( cv1.getText(), "expensive" ); + cv2 = (ContractVariation) it.next(); + assertEquals( cv2.getText(), "more expensive" ); + // cv1 and cv2 were loaded into s by hibernate, so they should be read-only + assertTrue( s.isReadOnly( cv1 ) ); + assertTrue( s.isReadOnly( cv2 ) ); + c.setCustomerName( "Sherman" ); + s.delete(c); + assertEquals( s.createCriteria(Contract.class).setProjection( Projections.rowCount() ).uniqueResult(), new Long(0) ); + assertEquals( s.createCriteria(ContractVariation.class).setProjection( Projections.rowCount() ).uniqueResult(), new Long(0) ); + t.commit(); + s.close(); + } + + public void testDeleteDetachedImmutable() { + Contract c = new Contract("gavin", "phone"); + ContractVariation cv1 = new ContractVariation(1, c); + cv1.setText("expensive"); + ContractVariation cv2 = new ContractVariation(2, c); + cv2.setText("more expensive"); + Session s = openSession(); + Transaction t = s.beginTransaction(); + s.persist(c); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.delete( c ); + /* + c = (Contract) s.createCriteria(Contract.class).uniqueResult(); + // c was loaded into s by hibernate, so it should be read-only + assertTrue( s.isReadOnly( c ) ); + assertEquals( c.getCustomerName(), "gavin" ); + assertEquals( c.getVariations().size(), 2 ); + Iterator it = c.getVariations().iterator(); + cv1 = (ContractVariation) it.next(); + assertEquals( cv1.getText(), "expensive" ); + cv2 = (ContractVariation) it.next(); + assertEquals( cv2.getText(), "more expensive" ); + // cv1 and cv2 were loaded into s by hibernate, so they should be read-only + assertTrue( s.isReadOnly( cv1 ) ); + assertTrue( s.isReadOnly( cv2 ) ); + s.delete(c); + assertEquals( s.createCriteria(Contract.class).setProjection( Projections.rowCount() ).uniqueResult(), new Long(0) ); + assertEquals( s.createCriteria(ContractVariation.class).setProjection( Projections.rowCount() ).uniqueResult(), new Long(0) ); + */ + t.commit(); + s.close(); + } + + public void testDeleteDetachedModifiedImmutable() { + Contract c = new Contract("gavin", "phone"); + ContractVariation cv1 = new ContractVariation(1, c); + cv1.setText("expensive"); + ContractVariation cv2 = new ContractVariation(2, c); + cv2.setText("more expensive"); + Session s = openSession(); + Transaction t = s.beginTransaction(); + s.persist(c); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + c.setCustomerName( "sherman" ); + s.delete( c ); + /* + c = (Contract) s.createCriteria(Contract.class).uniqueResult(); + // c was loaded into s by hibernate, so it should be read-only + assertTrue( s.isReadOnly( c ) ); + assertEquals( c.getCustomerName(), "gavin" ); + assertEquals( c.getVariations().size(), 2 ); + Iterator it = c.getVariations().iterator(); + cv1 = (ContractVariation) it.next(); + assertEquals( cv1.getText(), "expensive" ); + cv2 = (ContractVariation) it.next(); + assertEquals( cv2.getText(), "more expensive" ); + // cv1 and cv2 were loaded into s by hibernate, so they should be read-only + assertTrue( s.isReadOnly( cv1 ) ); + assertTrue( s.isReadOnly( cv2 ) ); + s.delete(c); + assertEquals( s.createCriteria(Contract.class).setProjection( Projections.rowCount() ).uniqueResult(), new Long(0) ); + assertEquals( s.createCriteria(ContractVariation.class).setProjection( Projections.rowCount() ).uniqueResult(), new Long(0) ); + */ + t.commit(); + s.close(); + } + + public void testImmutableParentEntityWithUpdate() { Contract c = new Contract("gavin", "phone"); ContractVariation cv1 = new ContractVariation(1, c); @@ -108,7 +443,15 @@ public class ImmutableTest extends FunctionalTestCase { t = s.beginTransaction(); c.setCustomerName("foo bar"); s.update( c ); + // c was not loaded into s by hibernate, so it should be modifiable + assertFalse( s.isReadOnly( c ) ); + assertFalse( s.contains( cv1 ) ); + assertFalse( s.contains( cv2 ) ); t.commit(); + // c, cv1, and cv2 were not loaded into s by hibernate, so they are modifiable + assertFalse( s.isReadOnly( c ) ); + assertFalse( s.isReadOnly( cv1 ) ); + assertFalse( s.isReadOnly( cv2 ) ); s.close(); s = openSession(); @@ -145,7 +488,14 @@ public class ImmutableTest extends FunctionalTestCase { cv1 = (ContractVariation) c.getVariations().iterator().next(); cv1.setText("blah blah"); s.update( c ); + // c was not loaded into s by hibernate, so it should be modifiable + assertFalse( s.isReadOnly( c ) ); + assertFalse( s.contains( cv1 ) ); + assertFalse( s.contains( cv2 ) ); t.commit(); + assertFalse( s.isReadOnly( c ) ); + assertFalse( s.isReadOnly( cv1 ) ); + assertFalse( s.isReadOnly( cv2 ) ); s.close(); s = openSession(); @@ -224,7 +574,16 @@ public class ImmutableTest extends FunctionalTestCase { s = openSession(); t = s.beginTransaction(); c.setCustomerName("foo bar"); - s.merge( c ); + c = ( Contract ) s.merge( c ); + // c was loaded into s by hibernate in the merge process, so it is read-only + assertTrue( s.isReadOnly( c ) ); + assertTrue( Hibernate.isInitialized( c.getVariations() ) ); + Iterator it = c.getVariations().iterator(); + cv1 = (ContractVariation) it.next(); + cv2 = (ContractVariation) it.next(); + // cv1 and cv2 were loaded into s by hibernate in the merge process, so they are read-only + assertTrue( s.isReadOnly( c ) ); + assertTrue( s.isReadOnly( c ) ); t.commit(); s.close(); @@ -233,7 +592,7 @@ public class ImmutableTest extends FunctionalTestCase { c = (Contract) s.createCriteria(Contract.class).uniqueResult(); assertEquals( c.getCustomerName(), "gavin" ); assertEquals( c.getVariations().size(), 2 ); - Iterator it = c.getVariations().iterator(); + it = c.getVariations().iterator(); cv1 = (ContractVariation) it.next(); assertEquals( cv1.getText(), "expensive" ); cv2 = (ContractVariation) it.next(); @@ -261,7 +620,16 @@ public class ImmutableTest extends FunctionalTestCase { t = s.beginTransaction(); cv1 = (ContractVariation) c.getVariations().iterator().next(); cv1.setText("blah blah"); - s.merge( c ); + c = ( Contract ) s.merge( c ); + // c was loaded into s by hibernate in the merge process, so it is read-only + assertTrue( s.isReadOnly( c ) ); + assertTrue( Hibernate.isInitialized( c.getVariations() ) ); + Iterator it = c.getVariations().iterator(); + cv1 = (ContractVariation) it.next(); + cv2 = (ContractVariation) it.next(); + // cv1 and cv2 were loaded into s by hibernate in the merge process, so they are read-only + assertTrue( s.isReadOnly( c ) ); + assertTrue( s.isReadOnly( c ) ); t.commit(); s.close(); @@ -270,7 +638,7 @@ public class ImmutableTest extends FunctionalTestCase { c = (Contract) s.createCriteria(Contract.class).uniqueResult(); assertEquals( c.getCustomerName(), "gavin" ); assertEquals( c.getVariations().size(), 2 ); - Iterator it = c.getVariations().iterator(); + it = c.getVariations().iterator(); cv1 = (ContractVariation) it.next(); assertEquals( cv1.getText(), "expensive" ); cv2 = (ContractVariation) it.next(); diff --git a/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/GetLoadTest.java b/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/GetLoadTest.java index cf7f7fd15a..3d2c0f812d 100755 --- a/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/GetLoadTest.java +++ b/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/GetLoadTest.java @@ -1,6 +1,9 @@ //$Id: GetLoadTest.java 10977 2006-12-12 23:28:04Z steve.ebersole@jboss.com $ package org.hibernate.test.nonflushedchanges; +import java.util.Iterator; +import java.util.List; + import junit.framework.Test; import org.hibernate.Hibernate; @@ -8,6 +11,7 @@ import org.hibernate.Session; import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Environment; import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.proxy.HibernateProxy; import org.hibernate.test.tm.SimpleJtaTransactionManagerImpl; @@ -92,6 +96,131 @@ public class GetLoadTest extends AbstractOperationTestCase { SimpleJtaTransactionManagerImpl.getInstance().commit(); assertFetchCount( 0 ); + + SimpleJtaTransactionManagerImpl.getInstance().begin(); + s = openSession(); + s.createQuery( "delete from Employer" ).executeUpdate(); + List list = s.createQuery( "from Node" ).list(); + for ( Iterator it=list.iterator(); it.hasNext(); ) { + s.delete( it.next() ); + } + SimpleJtaTransactionManagerImpl.getInstance().commit(); + } + + public void testGetReadOnly() throws Exception { + clearCounts(); + + SimpleJtaTransactionManagerImpl.getInstance().begin(); + Session s = openSession(); + Employer emp = new Employer(); + s.persist( emp ); + Node node = new Node( "foo" ); + Node parent = new Node( "bar" ); + parent.addChild( node ); + s.persist( parent ); + SimpleJtaTransactionManagerImpl.getInstance().commit(); + + SimpleJtaTransactionManagerImpl.getInstance().begin(); + s = openSession(); + assertFalse( s.isDefaultReadOnly() ); + s.setDefaultReadOnly( true ); + emp = ( Employer ) s.get( Employer.class, emp.getId() ); + assertTrue( s.isDefaultReadOnly() ); + s = applyNonFlushedChangesToNewSessionCloseOldSession( s ); + assertTrue( s.isDefaultReadOnly() ); + emp = ( Employer ) getOldToNewEntityRefMap().get( emp ); + assertTrue( Hibernate.isInitialized( emp ) ); + assertFalse( Hibernate.isInitialized( emp.getEmployees() ) ); + node = ( Node ) s.get( Node.class, node.getName() ); + assertTrue( s.isReadOnly( emp ) ); + assertTrue( s.isReadOnly( node ) ); + s.setDefaultReadOnly( false ); + s = applyNonFlushedChangesToNewSessionCloseOldSession( s ); + assertFalse( s.isDefaultReadOnly() ); + node = ( Node ) getOldToNewEntityRefMap().get( node ); + emp = ( Employer ) getOldToNewEntityRefMap().get( emp ); + assertTrue( Hibernate.isInitialized( node ) ); + assertTrue( s.isReadOnly( node ) ); + assertFalse( Hibernate.isInitialized( node.getParent() ) ); + assertTrue( s.isReadOnly( emp ) ); + assertFalse( Hibernate.isInitialized( node.getChildren() ) ); + Hibernate.initialize( node.getChildren() ); + for ( Iterator it=node.getChildren().iterator(); it.hasNext(); ) { + assertFalse( s.isReadOnly( it.next() ) ); + } + assertFalse( Hibernate.isInitialized( node.getParent() ) ); + assertNull( s.get( Node.class, "xyz" ) ); + SimpleJtaTransactionManagerImpl.getInstance().commit(); + + SimpleJtaTransactionManagerImpl.getInstance().begin(); + s = openSession(); + assertFalse( s.isDefaultReadOnly() ); + emp = ( Employer ) s.get( "org.hibernate.test.nonflushedchanges.Employer", emp.getId() ); + s = applyNonFlushedChangesToNewSessionCloseOldSession( s ); + assertFalse( s.isDefaultReadOnly() ); + emp = ( Employer ) getOldToNewEntityRefMap().get( emp ); + assertTrue( Hibernate.isInitialized( emp ) ); + assertFalse( s.isReadOnly( emp ) ); + s.setReadOnly( emp, true ); + node = ( Node ) s.get( "org.hibernate.test.nonflushedchanges.Node", node.getName() ); + assertFalse( s.isReadOnly( node ) ); + s.setReadOnly( node, true ); + s = applyNonFlushedChangesToNewSessionCloseOldSession( s ); + emp = ( Employer ) getOldToNewEntityRefMap().get( emp ); + assertTrue( s.isReadOnly( emp ) ); + node = ( Node ) getOldToNewEntityRefMap().get( node ); + assertTrue( Hibernate.isInitialized( node ) ); + assertTrue( s.isReadOnly( node ) ); + SimpleJtaTransactionManagerImpl.getInstance().commit(); + + assertFetchCount( 0 ); + + SimpleJtaTransactionManagerImpl.getInstance().begin(); + s = openSession(); + s.createQuery( "delete from Employer" ).executeUpdate(); + List list = s.createQuery( "from Node" ).list(); + for ( Iterator it=list.iterator(); it.hasNext(); ) { + s.delete( it.next() ); + } + SimpleJtaTransactionManagerImpl.getInstance().commit(); + } + + public void testLoadReadOnlyFailureExpected() throws Exception { + clearCounts(); + + SimpleJtaTransactionManagerImpl.getInstance().begin(); + Session s = openSession(); + Employer emp = new Employer(); + s.persist( emp ); + Node node = new Node( "foo" ); + Node parent = new Node( "bar" ); + parent.addChild( node ); + s.persist( parent ); + SimpleJtaTransactionManagerImpl.getInstance().commit(); + + SimpleJtaTransactionManagerImpl.getInstance().begin(); + s = openSession(); + assertFalse( s.isDefaultReadOnly() ); + s.setDefaultReadOnly( true ); + emp = ( Employer ) s.load( Employer.class, emp.getId() ); + assertFalse( Hibernate.isInitialized( emp ) ); + assertTrue( s.isReadOnly( emp ) ); + assertTrue( s.isDefaultReadOnly() ); + s = applyNonFlushedChangesToNewSessionCloseOldSession( s ); + assertTrue( s.isDefaultReadOnly() ); + emp = ( Employer ) getOldToNewEntityRefMap().get( emp ); + assertFalse( Hibernate.isInitialized( emp ) ); + assertTrue( s.isReadOnly( emp ) ); + SimpleJtaTransactionManagerImpl.getInstance().commit(); + + SimpleJtaTransactionManagerImpl.getInstance().begin(); + s = openSession(); + s.createQuery( "delete from Employer" ).executeUpdate(); + List list = s.createQuery( "from Node" ).list(); + for ( Iterator it=list.iterator(); it.hasNext(); ) { + s.delete( it.next() ); + } + SimpleJtaTransactionManagerImpl.getInstance().commit(); } public void testGetAfterDelete() throws Exception { diff --git a/testsuite/src/test/java/org/hibernate/test/readonly/Container.java b/testsuite/src/test/java/org/hibernate/test/readonly/Container.java new file mode 100644 index 0000000000..ba6bca84c0 --- /dev/null +++ b/testsuite/src/test/java/org/hibernate/test/readonly/Container.java @@ -0,0 +1,117 @@ +package org.hibernate.test.readonly; + +import java.util.Set; +import java.util.HashSet; +import java.io.Serializable; + +/** + * @author Steve Ebersole, Gail Badner (adapted this from "proxy" tests version) + */ +public class Container implements Serializable { + private Long id; + private String name; + private Owner noProxyOwner; + private Owner proxyOwner; + private Owner nonLazyOwner; + private Info noProxyInfo; + private Info proxyInfo; + private Info nonLazyInfo; + private Set lazyDataPoints = new HashSet(); + private Set nonLazyJoinDataPoints = new HashSet(); + private Set nonLazySelectDataPoints = new HashSet(); + + public Container() { + } + + public Container(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Owner getNoProxyOwner() { + return noProxyOwner; + } + + public void setNoProxyOwner(Owner noProxyOwner) { + this.noProxyOwner = noProxyOwner; + } + + public Owner getProxyOwner() { + return proxyOwner; + } + + public void setProxyOwner(Owner proxyOwner) { + this.proxyOwner = proxyOwner; + } + + public Owner getNonLazyOwner() { + return nonLazyOwner; + } + + public void setNonLazyOwner(Owner nonLazyOwner) { + this.nonLazyOwner = nonLazyOwner; + } + + public Info getNoProxyInfo() { + return noProxyInfo; + } + + public void setNoProxyInfo(Info noProxyInfo) { + this.noProxyInfo = noProxyInfo; + } + + public Info getProxyInfo() { + return proxyInfo; + } + + public void setProxyInfo(Info proxyInfo) { + this.proxyInfo = proxyInfo; + } + + public Info getNonLazyInfo() { + return nonLazyInfo; + } + + public void setNonLazyInfo(Info nonLazyInfo) { + this.nonLazyInfo = nonLazyInfo; + } + + public Set getLazyDataPoints() { + return lazyDataPoints; + } + + public void setLazyDataPoints(Set lazyDataPoints) { + this.lazyDataPoints = lazyDataPoints; + } + + public Set getNonLazyJoinDataPoints() { + return nonLazyJoinDataPoints; + } + + public void setNonLazyJoinDataPoints(Set nonLazyJoinDataPoints) { + this.nonLazyJoinDataPoints = nonLazyJoinDataPoints; + } + + public Set getNonLazySelectDataPoints() { + return nonLazySelectDataPoints; + } + + public void setNonLazySelectDataPoints(Set nonLazySelectDataPoints) { + this.nonLazySelectDataPoints = nonLazySelectDataPoints; + } +} \ No newline at end of file diff --git a/testsuite/src/test/java/org/hibernate/test/readonly/DataPoint.hbm.xml b/testsuite/src/test/java/org/hibernate/test/readonly/DataPoint.hbm.xml index 1a37d667a8..9c0d4f7330 100755 --- a/testsuite/src/test/java/org/hibernate/test/readonly/DataPoint.hbm.xml +++ b/testsuite/src/test/java/org/hibernate/test/readonly/DataPoint.hbm.xml @@ -21,4 +21,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/testsuite/src/test/java/org/hibernate/test/readonly/DataPoint.java b/testsuite/src/test/java/org/hibernate/test/readonly/DataPoint.java index 5e241720bd..471ed35545 100755 --- a/testsuite/src/test/java/org/hibernate/test/readonly/DataPoint.java +++ b/testsuite/src/test/java/org/hibernate/test/readonly/DataPoint.java @@ -2,15 +2,25 @@ package org.hibernate.test.readonly; import java.math.BigDecimal; +import java.io.Serializable; /** * @author Gavin King */ -public class DataPoint { +public class DataPoint implements Serializable { private long id; private BigDecimal x; private BigDecimal y; private String description; + + public DataPoint() {} + + public DataPoint(BigDecimal x, BigDecimal y, String description) { + this.x = x; + this.y = y; + this.description = description; + } + /** * @return Returns the description. */ @@ -59,4 +69,7 @@ public class DataPoint { public void setY(BigDecimal y) { this.y = y; } + void exception() throws Exception { + throw new Exception("foo"); + } } diff --git a/testsuite/src/test/java/org/hibernate/test/readonly/Info.java b/testsuite/src/test/java/org/hibernate/test/readonly/Info.java new file mode 100644 index 0000000000..a18dbfb11e --- /dev/null +++ b/testsuite/src/test/java/org/hibernate/test/readonly/Info.java @@ -0,0 +1,34 @@ +package org.hibernate.test.readonly; + +/** + * todo: describe Info + * + * @author Steve Ebersole, Gail Badner (adapted this from "proxy" tests version) + */ +public class Info { + private Long id; + private String details; + + public Info() { + } + + public Info(String details) { + this.details = details; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getDetails() { + return details; + } + + public void setDetails(String details) { + this.details = details; + } +} \ No newline at end of file diff --git a/testsuite/src/test/java/org/hibernate/test/readonly/Owner.java b/testsuite/src/test/java/org/hibernate/test/readonly/Owner.java new file mode 100644 index 0000000000..93a921bb97 --- /dev/null +++ b/testsuite/src/test/java/org/hibernate/test/readonly/Owner.java @@ -0,0 +1,34 @@ +package org.hibernate.test.readonly; + +import java.io.Serializable; + +/** + * @author Steve Ebersole, Gail Badner (adapted this from "proxy" tests version) + */ +public class Owner implements Serializable { + private Long id; + private String name; + + public Owner() { + } + + public Owner(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} \ No newline at end of file diff --git a/testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlySessionLazyNonLazyTest.java b/testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlySessionLazyNonLazyTest.java new file mode 100644 index 0000000000..4200035ee1 --- /dev/null +++ b/testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlySessionLazyNonLazyTest.java @@ -0,0 +1,1446 @@ +//$Id: ReadOnlyTest.java 10977 2006-12-12 23:28:04Z steve.ebersole@jboss.com $ +/* + * 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.test.readonly; + +import java.math.BigDecimal; +import java.util.List; +import java.util.Set; +import java.util.HashSet; +import java.util.Arrays; +import java.util.Iterator; + +import junit.framework.Test; + +import org.hibernate.CacheMode; +import org.hibernate.Hibernate; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.proxy.HibernateProxy; +import org.hibernate.engine.SessionImplementor; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * Model: + * + * Container + * |-- N : 1 -- noProxyOwner (property-ref="name" lazy="no-proxy" cascade="all") + * |-- N : 1 -- proxyOwner (property-ref="name" lazy="proxy" cascade="all") + * |-- N : 1 -- nonLazyOwner (property-ref="name" lazy="false" cascade="all") + * |-- N : 1 -- noProxyInfo" (lazy="no-proxy" cascade="all") + * |-- N : 1 -- proxyInfo (lazy="proxy" cascade="all" + * |-- N : 1 -- nonLazyInfo" (lazy="false" cascade="all") + * | + * |-- 1 : N -- lazyDataPoints" (lazy="true" inverse="false" cascade="all") + * |-- 1 : N -- nonLazySelectDataPoints" (lazy="false" inverse="false" cascade="all" fetch="select") + * |-- 1 : N -- nonLazyJoinDataPoints" (lazy="false" inverse="false" cascade="all" fetch="join") + * + * Note: the following many-to-one properties use a property-ref so they are + * initialized, regardless of how the lazy attribute is mapped: + * noProxyOwner, proxyOwner, nonLazyOwner + * + * @author Gail Badner + */ +public class ReadOnlySessionLazyNonLazyTest extends FunctionalTestCase { + + public ReadOnlySessionLazyNonLazyTest(String str) { + super(str); + } + + public String[] getMappings() { + return new String[] { "readonly/DataPoint.hbm.xml" }; + } + + public void configure(Configuration cfg) { + cfg.setProperty(Environment.STATEMENT_BATCH_SIZE, "20"); + } + + public String getCacheConcurrencyStrategy() { + return null; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( ReadOnlySessionLazyNonLazyTest.class ); + } + + public void testExistingModifiableAfterSetSessionReadOnly() { + + Container cOrig = createContainer(); + Set expectedInitializedObjects = + new HashSet( + Arrays.asList( new Object[ ] { + cOrig, cOrig.getNoProxyInfo(), cOrig.getProxyInfo(), cOrig.getNonLazyInfo(), + cOrig.getNoProxyOwner(), cOrig.getProxyOwner(), cOrig.getNonLazyOwner(), + cOrig.getLazyDataPoints().iterator().next(), + cOrig.getNonLazyJoinDataPoints().iterator().next(), + cOrig.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + Set expectedReadOnlyObjects = new HashSet(); + + Session s = openSession(); + assertFalse( s.isDefaultReadOnly() ); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + s.save( cOrig ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + s.setDefaultReadOnly( true ); + assertTrue( s.isDefaultReadOnly() ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + t.commit(); + + t = s.beginTransaction(); + assertTrue( s.isDefaultReadOnly() ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + Container c = ( Container ) s.load( Container.class, cOrig.getId() ); + assertSame( cOrig, c ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + c = ( Container ) s.get( Container.class, cOrig.getId() ); + assertSame( cOrig, c ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + //s.refresh( cOrig ); + assertSame( cOrig, c ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + s.evict( cOrig ); + c = ( Container ) s.get( Container.class, cOrig.getId() ); + assertNotSame( cOrig, c ); + expectedInitializedObjects = + new HashSet( + Arrays.asList( new Object[ ] { + c, c.getNonLazyInfo(), + c.getNoProxyOwner(), c.getProxyOwner(), c.getNonLazyOwner(), + c.getNonLazyJoinDataPoints().iterator().next(), + c.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + expectedReadOnlyObjects = + new HashSet( + Arrays.asList( new Object[ ] { + c, c.getNoProxyInfo(), c.getProxyInfo(), c.getNonLazyInfo(), + c.getNoProxyOwner(), c.getProxyOwner(), c.getNonLazyOwner(), + //c.getLazyDataPoints(), + c.getNonLazyJoinDataPoints().iterator().next(), + c.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + assertFalse( Hibernate.isInitialized( c.getNoProxyInfo() ) ); + Hibernate.initialize( c.getNoProxyInfo() ); + expectedInitializedObjects.add( c.getNoProxyInfo() ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + assertFalse( Hibernate.isInitialized( c.getProxyInfo() ) ); + Hibernate.initialize( c.getProxyInfo() ); + expectedInitializedObjects.add( c.getProxyInfo() ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + assertFalse( Hibernate.isInitialized( c.getLazyDataPoints() ) ); + Hibernate.initialize( c.getLazyDataPoints() ); + expectedInitializedObjects.add( c.getLazyDataPoints().iterator().next() ); + expectedReadOnlyObjects.add(c.getLazyDataPoints().iterator().next() ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + t.commit(); + s.close(); + s = openSession(); + t = s.beginTransaction(); + s.createQuery("delete from DataPoint").executeUpdate(); + s.createQuery("delete from Container").executeUpdate(); + s.createQuery("delete from Info").executeUpdate(); + s.createQuery("delete from Owner").executeUpdate(); + t.commit(); + s.close(); + + } + + public void testExistingReadOnlyAfterSetSessionModifiable() { + + Container cOrig = createContainer(); + Set expectedInitializedObjects = + new HashSet( + Arrays.asList( new Object[ ] { + cOrig, cOrig.getNoProxyInfo(), cOrig.getProxyInfo(), cOrig.getNonLazyInfo(), + cOrig.getNoProxyOwner(), cOrig.getProxyOwner(), cOrig.getNonLazyOwner(), + cOrig.getLazyDataPoints().iterator().next(), + cOrig.getNonLazyJoinDataPoints().iterator().next(), + cOrig.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + Set expectedReadOnlyObjects = new HashSet(); + Session s = openSession(); + assertFalse( s.isDefaultReadOnly() ); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + s.save( cOrig ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + s.setDefaultReadOnly( true ); + assertTrue( s.isDefaultReadOnly() ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.setDefaultReadOnly( true ); + Container c = ( Container ) s.get( Container.class, cOrig.getId() ); + assertNotSame( cOrig, c ); + expectedInitializedObjects = + new HashSet( + Arrays.asList( new Object[ ] { + c, c.getNonLazyInfo(), + c.getNoProxyOwner(), c.getProxyOwner(), c.getNonLazyOwner(), + c.getNonLazyJoinDataPoints().iterator().next(), + c.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + expectedReadOnlyObjects = + new HashSet( + Arrays.asList( new Object[ ] { + c, c.getNoProxyInfo(), c.getProxyInfo(), c.getNonLazyInfo(), + c.getNoProxyOwner(), c.getProxyOwner(), c.getNonLazyOwner(), + //c.getLazyDataPoints(), + c.getNonLazyJoinDataPoints().iterator().next(), + c.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + s.setDefaultReadOnly( false ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + assertFalse( Hibernate.isInitialized( c.getNoProxyInfo() ) ); + Hibernate.initialize( c.getNoProxyInfo() ); + expectedInitializedObjects.add( c.getNoProxyInfo() ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + assertFalse( Hibernate.isInitialized( c.getProxyInfo() ) ); + Hibernate.initialize( c.getProxyInfo() ); + expectedInitializedObjects.add( c.getProxyInfo() ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + assertFalse( Hibernate.isInitialized( c.getLazyDataPoints() ) ); + Hibernate.initialize( c.getLazyDataPoints() ); + expectedInitializedObjects.add( c.getLazyDataPoints().iterator().next() ); + //expectedReadOnlyObjects.add(c.getLazyDataPoints().iterator().next() ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + t.commit(); + s.close(); + s = openSession(); + t = s.beginTransaction(); + s.createQuery("delete from DataPoint").executeUpdate(); + s.createQuery("delete from Container").executeUpdate(); + s.createQuery("delete from Info").executeUpdate(); + s.createQuery("delete from Owner").executeUpdate(); + t.commit(); + s.close(); + + } + + public void testExistingReadOnlyAfterSetSessionModifiableExisting() { + + Container cOrig = createContainer(); + Set expectedInitializedObjects = + new HashSet( + Arrays.asList( new Object[ ] { + cOrig, cOrig.getNoProxyInfo(), cOrig.getProxyInfo(), cOrig.getNonLazyInfo(), + cOrig.getNoProxyOwner(), cOrig.getProxyOwner(), cOrig.getNonLazyOwner(), + cOrig.getLazyDataPoints().iterator().next(), + cOrig.getNonLazyJoinDataPoints().iterator().next(), + cOrig.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + Set expectedReadOnlyObjects = new HashSet(); + DataPoint lazyDataPointOrig = ( DataPoint ) cOrig.getLazyDataPoints().iterator().next(); + Session s = openSession(); + assertFalse( s.isDefaultReadOnly() ); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + s.save( cOrig ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + s.setDefaultReadOnly( true ); + assertTrue( s.isDefaultReadOnly() ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.setDefaultReadOnly( true ); + Container c = ( Container ) s.get( Container.class, cOrig.getId() ); + assertNotSame( cOrig, c ); + expectedInitializedObjects = + new HashSet( + Arrays.asList( new Object[ ] { + c, c.getNonLazyInfo(), + c.getNoProxyOwner(), c.getProxyOwner(), c.getNonLazyOwner(), + c.getNonLazyJoinDataPoints().iterator().next(), + c.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + expectedReadOnlyObjects = + new HashSet( + Arrays.asList( new Object[ ] { + c, c.getNoProxyInfo(), c.getProxyInfo(), c.getNonLazyInfo(), + c.getNoProxyOwner(), c.getProxyOwner(), c.getNonLazyOwner(), + //c.getLazyDataPoints(), + c.getNonLazyJoinDataPoints().iterator().next(), + c.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + s.setDefaultReadOnly( false ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + assertFalse( Hibernate.isInitialized( c.getNoProxyInfo() ) ); + Hibernate.initialize( c.getNoProxyInfo() ); + expectedInitializedObjects.add( c.getNoProxyInfo() ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + assertFalse( Hibernate.isInitialized( c.getProxyInfo() ) ); + Hibernate.initialize( c.getProxyInfo() ); + expectedInitializedObjects.add( c.getProxyInfo() ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + DataPoint lazyDataPoint = ( DataPoint ) s.get( DataPoint.class, lazyDataPointOrig.getId() ); + assertFalse( Hibernate.isInitialized( c.getLazyDataPoints() ) ); + Hibernate.initialize( c.getLazyDataPoints() ); + assertSame( lazyDataPoint, c.getLazyDataPoints().iterator().next() ); + expectedInitializedObjects.add( c.getLazyDataPoints().iterator().next() ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + t.commit(); + s.close(); + s = openSession(); + t = s.beginTransaction(); + s.createQuery("delete from DataPoint").executeUpdate(); + s.createQuery("delete from Container").executeUpdate(); + s.createQuery("delete from Info").executeUpdate(); + s.createQuery("delete from Owner").executeUpdate(); + t.commit(); + s.close(); + + } + + public void testExistingReadOnlyAfterSetSessionModifiableExistingEntityReadOnly() { + + Container cOrig = createContainer(); + Set expectedInitializedObjects = + new HashSet( + Arrays.asList( new Object[ ] { + cOrig, cOrig.getNoProxyInfo(), cOrig.getProxyInfo(), cOrig.getNonLazyInfo(), + cOrig.getNoProxyOwner(), cOrig.getProxyOwner(), cOrig.getNonLazyOwner(), + cOrig.getLazyDataPoints().iterator().next(), + cOrig.getNonLazyJoinDataPoints().iterator().next(), + cOrig.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + Set expectedReadOnlyObjects = new HashSet(); + DataPoint lazyDataPointOrig = ( DataPoint ) cOrig.getLazyDataPoints().iterator().next(); + Session s = openSession(); + assertFalse( s.isDefaultReadOnly() ); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + s.save( cOrig ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + s.setDefaultReadOnly( true ); + assertTrue( s.isDefaultReadOnly() ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.setDefaultReadOnly( true ); + Container c = ( Container ) s.get( Container.class, cOrig.getId() ); + assertNotSame( cOrig, c ); + expectedInitializedObjects = + new HashSet( + Arrays.asList( new Object[ ] { + c, c.getNonLazyInfo(), + c.getNoProxyOwner(), c.getProxyOwner(), c.getNonLazyOwner(), + c.getNonLazyJoinDataPoints().iterator().next(), + c.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + expectedReadOnlyObjects = + new HashSet( + Arrays.asList( new Object[ ] { + c, c.getNoProxyInfo(), c.getProxyInfo(), c.getNonLazyInfo(), + c.getNoProxyOwner(), c.getProxyOwner(), c.getNonLazyOwner(), + //c.getLazyDataPoints(), + c.getNonLazyJoinDataPoints().iterator().next(), + c.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + s.setDefaultReadOnly( false ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + assertFalse( Hibernate.isInitialized( c.getNoProxyInfo() ) ); + Hibernate.initialize( c.getNoProxyInfo() ); + expectedInitializedObjects.add( c.getNoProxyInfo() ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + assertFalse( Hibernate.isInitialized( c.getProxyInfo() ) ); + Hibernate.initialize( c.getProxyInfo() ); + expectedInitializedObjects.add( c.getProxyInfo() ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + s.setDefaultReadOnly( true ); + DataPoint lazyDataPoint = ( DataPoint ) s.get( DataPoint.class, lazyDataPointOrig.getId() ); + s.setDefaultReadOnly( false ); + assertFalse( Hibernate.isInitialized( c.getLazyDataPoints() ) ); + Hibernate.initialize( c.getLazyDataPoints() ); + assertSame( lazyDataPoint, c.getLazyDataPoints().iterator().next() ); + expectedInitializedObjects.add( c.getLazyDataPoints().iterator().next() ); + expectedReadOnlyObjects.add( lazyDataPoint ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + t.commit(); + s.close(); + s = openSession(); + t = s.beginTransaction(); + s.createQuery("delete from DataPoint").executeUpdate(); + s.createQuery("delete from Container").executeUpdate(); + s.createQuery("delete from Info").executeUpdate(); + s.createQuery("delete from Owner").executeUpdate(); + t.commit(); + s.close(); + } + + + public void testExistingReadOnlyAfterSetSessionModifiableProxyExisting() { + + Container cOrig = createContainer(); + Set expectedInitializedObjects = + new HashSet( + Arrays.asList( new Object[ ] { + cOrig, cOrig.getNoProxyInfo(), cOrig.getProxyInfo(), cOrig.getNonLazyInfo(), + cOrig.getNoProxyOwner(), cOrig.getProxyOwner(), cOrig.getNonLazyOwner(), + cOrig.getLazyDataPoints().iterator().next(), + cOrig.getNonLazyJoinDataPoints().iterator().next(), + cOrig.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + Set expectedReadOnlyObjects = new HashSet(); + DataPoint lazyDataPointOrig = ( DataPoint ) cOrig.getLazyDataPoints().iterator().next(); + Session s = openSession(); + assertFalse( s.isDefaultReadOnly() ); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + s.save( cOrig ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + s.setDefaultReadOnly( true ); + assertTrue( s.isDefaultReadOnly() ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.setDefaultReadOnly( true ); + Container c = ( Container ) s.get( Container.class, cOrig.getId() ); + assertNotSame( cOrig, c ); + expectedInitializedObjects = + new HashSet( + Arrays.asList( new Object[ ] { + c, c.getNonLazyInfo(), + c.getNoProxyOwner(), c.getProxyOwner(), c.getNonLazyOwner(), + c.getNonLazyJoinDataPoints().iterator().next(), + c.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + expectedReadOnlyObjects = + new HashSet( + Arrays.asList( new Object[ ] { + c, c.getNoProxyInfo(), c.getProxyInfo(), c.getNonLazyInfo(), + c.getNoProxyOwner(), c.getProxyOwner(), c.getNonLazyOwner(), + //c.getLazyDataPoints(), + c.getNonLazyJoinDataPoints().iterator().next(), + c.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + s.setDefaultReadOnly( false ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + assertFalse( Hibernate.isInitialized( c.getNoProxyInfo() ) ); + Hibernate.initialize( c.getNoProxyInfo() ); + expectedInitializedObjects.add( c.getNoProxyInfo() ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + assertFalse( Hibernate.isInitialized( c.getProxyInfo() ) ); + Hibernate.initialize( c.getProxyInfo() ); + expectedInitializedObjects.add( c.getProxyInfo() ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + DataPoint lazyDataPoint = ( DataPoint ) s.load( DataPoint.class, lazyDataPointOrig.getId() ); + assertFalse( Hibernate.isInitialized( c.getLazyDataPoints() ) ); + Hibernate.initialize( c.getLazyDataPoints() ); + assertSame( lazyDataPoint, c.getLazyDataPoints().iterator().next() ); + expectedInitializedObjects.add( c.getLazyDataPoints().iterator().next() ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + t.commit(); + s.close(); + s = openSession(); + t = s.beginTransaction(); + s.createQuery("delete from DataPoint").executeUpdate(); + s.createQuery("delete from Container").executeUpdate(); + s.createQuery("delete from Info").executeUpdate(); + s.createQuery("delete from Owner").executeUpdate(); + t.commit(); + s.close(); + + } + + public void testExistingReadOnlyAfterSetSessionModifiableExistingProxyReadOnly() { + + Container cOrig = createContainer(); + Set expectedInitializedObjects = + new HashSet( + Arrays.asList( new Object[ ] { + cOrig, cOrig.getNoProxyInfo(), cOrig.getProxyInfo(), cOrig.getNonLazyInfo(), + cOrig.getNoProxyOwner(), cOrig.getProxyOwner(), cOrig.getNonLazyOwner(), + cOrig.getLazyDataPoints().iterator().next(), + cOrig.getNonLazyJoinDataPoints().iterator().next(), + cOrig.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + Set expectedReadOnlyObjects = new HashSet(); + DataPoint lazyDataPointOrig = ( DataPoint ) cOrig.getLazyDataPoints().iterator().next(); + Session s = openSession(); + assertFalse( s.isDefaultReadOnly() ); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + s.save( cOrig ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + s.setDefaultReadOnly( true ); + assertTrue( s.isDefaultReadOnly() ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.setDefaultReadOnly( true ); + Container c = ( Container ) s.get( Container.class, cOrig.getId() ); + assertNotSame( cOrig, c ); + expectedInitializedObjects = + new HashSet( + Arrays.asList( new Object[ ] { + c, c.getNonLazyInfo(), + c.getNoProxyOwner(), c.getProxyOwner(), c.getNonLazyOwner(), + c.getNonLazyJoinDataPoints().iterator().next(), + c.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + expectedReadOnlyObjects = + new HashSet( + Arrays.asList( new Object[ ] { + c, c.getNoProxyInfo(), c.getProxyInfo(), c.getNonLazyInfo(), + c.getNoProxyOwner(), c.getProxyOwner(), c.getNonLazyOwner(), + //c.getLazyDataPoints(), + c.getNonLazyJoinDataPoints().iterator().next(), + c.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + s.setDefaultReadOnly( false ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + assertFalse( Hibernate.isInitialized( c.getNoProxyInfo() ) ); + Hibernate.initialize( c.getNoProxyInfo() ); + expectedInitializedObjects.add( c.getNoProxyInfo() ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + assertFalse( Hibernate.isInitialized( c.getProxyInfo() ) ); + Hibernate.initialize( c.getProxyInfo() ); + expectedInitializedObjects.add( c.getProxyInfo() ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + s.setDefaultReadOnly( true ); + DataPoint lazyDataPoint = ( DataPoint ) s.load( DataPoint.class, lazyDataPointOrig.getId() ); + s.setDefaultReadOnly( false ); + assertFalse( Hibernate.isInitialized( c.getLazyDataPoints() ) ); + Hibernate.initialize( c.getLazyDataPoints() ); + assertSame( lazyDataPoint, c.getLazyDataPoints().iterator().next() ); + expectedInitializedObjects.add( c.getLazyDataPoints().iterator().next() ); + expectedReadOnlyObjects.add( lazyDataPoint ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + t.commit(); + s.close(); + s = openSession(); + t = s.beginTransaction(); + s.createQuery("delete from DataPoint").executeUpdate(); + s.createQuery("delete from Container").executeUpdate(); + s.createQuery("delete from Info").executeUpdate(); + s.createQuery("delete from Owner").executeUpdate(); + t.commit(); + s.close(); + } + + public void testDefaultModifiableWithReadOnlyQueryForEntity() { + Container cOrig = createContainer(); + Set expectedInitializedObjects = + new HashSet( + Arrays.asList( new Object[ ] { + cOrig, cOrig.getNoProxyInfo(), cOrig.getProxyInfo(), cOrig.getNonLazyInfo(), + cOrig.getNoProxyOwner(), cOrig.getProxyOwner(), cOrig.getNonLazyOwner(), + cOrig.getLazyDataPoints().iterator().next(), + cOrig.getNonLazyJoinDataPoints().iterator().next(), + cOrig.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + Set expectedReadOnlyObjects = new HashSet(); + + Session s = openSession(); + assertFalse( s.isDefaultReadOnly() ); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + s.save( cOrig ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + s.setDefaultReadOnly( true ); + assertTrue( s.isDefaultReadOnly() ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + assertFalse( s.isDefaultReadOnly() ); + Container c = ( Container ) s.createQuery( "from Container where id=" + cOrig.getId() ) + .setReadOnly( true ).uniqueResult(); + expectedInitializedObjects = + new HashSet( + Arrays.asList( new Object[ ] { + c, c.getNonLazyInfo(), + c.getNoProxyOwner(), c.getProxyOwner(), c.getNonLazyOwner(), + c.getNonLazyJoinDataPoints().iterator().next(), + c.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + expectedReadOnlyObjects = + new HashSet( + Arrays.asList( new Object[ ] { + c, c.getNoProxyInfo(), c.getProxyInfo(), c.getNonLazyInfo(), + c.getNoProxyOwner(), c.getProxyOwner(), c.getNonLazyOwner(), + //c.getLazyDataPoints(), + c.getNonLazyJoinDataPoints().iterator().next(), + c.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + assertFalse( Hibernate.isInitialized( c.getNoProxyInfo() ) ); + Hibernate.initialize( c.getNoProxyInfo() ); + expectedInitializedObjects.add( c.getNoProxyInfo() ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + assertFalse( Hibernate.isInitialized( c.getProxyInfo() ) ); + Hibernate.initialize( c.getProxyInfo() ); + expectedInitializedObjects.add( c.getProxyInfo() ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + assertFalse( Hibernate.isInitialized( c.getLazyDataPoints() ) ); + Hibernate.initialize( c.getLazyDataPoints() ); + expectedInitializedObjects.add( c.getLazyDataPoints().iterator().next() ); + //expectedReadOnlyObjects.add(c.getLazyDataPoints().iterator().next() ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + t.commit(); + s.close(); + s = openSession(); + t = s.beginTransaction(); + s.createQuery("delete from DataPoint").executeUpdate(); + s.createQuery("delete from Container").executeUpdate(); + s.createQuery("delete from Info").executeUpdate(); + s.createQuery("delete from Owner").executeUpdate(); + t.commit(); + s.close(); + } + + public void testDefaultReadOnlyWithModifiableQueryForEntity() { + Container cOrig = createContainer(); + Set expectedInitializedObjects = + new HashSet( + Arrays.asList( new Object[ ] { + cOrig, cOrig.getNoProxyInfo(), cOrig.getProxyInfo(), cOrig.getNonLazyInfo(), + cOrig.getNoProxyOwner(), cOrig.getProxyOwner(), cOrig.getNonLazyOwner(), + cOrig.getLazyDataPoints().iterator().next(), + cOrig.getNonLazyJoinDataPoints().iterator().next(), + cOrig.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + Set expectedReadOnlyObjects = new HashSet(); + + Session s = openSession(); + assertFalse( s.isDefaultReadOnly() ); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + s.save( cOrig ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + s.setDefaultReadOnly( true ); + assertTrue( s.isDefaultReadOnly() ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.setDefaultReadOnly( true ); + assertTrue( s.isDefaultReadOnly() ); + Container c = ( Container ) s.createQuery( "from Container where id=" + cOrig.getId() ) + .setReadOnly( false ).uniqueResult(); + expectedInitializedObjects = + new HashSet( + Arrays.asList( new Object[ ] { + c, c.getNonLazyInfo(), + c.getNoProxyOwner(), c.getProxyOwner(), c.getNonLazyOwner(), + c.getNonLazyJoinDataPoints().iterator().next(), + c.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + expectedReadOnlyObjects = new HashSet(); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + assertFalse( Hibernate.isInitialized( c.getNoProxyInfo() ) ); + Hibernate.initialize( c.getNoProxyInfo() ); + expectedInitializedObjects.add( c.getNoProxyInfo() ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + assertFalse( Hibernate.isInitialized( c.getProxyInfo() ) ); + Hibernate.initialize( c.getProxyInfo() ); + expectedInitializedObjects.add( c.getProxyInfo() ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + assertFalse( Hibernate.isInitialized( c.getLazyDataPoints() ) ); + Hibernate.initialize( c.getLazyDataPoints() ); + expectedInitializedObjects.add( c.getLazyDataPoints().iterator().next() ); + expectedReadOnlyObjects.add(c.getLazyDataPoints().iterator().next() ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + t.commit(); + s.close(); + s = openSession(); + t = s.beginTransaction(); + s.createQuery("delete from DataPoint").executeUpdate(); + s.createQuery("delete from Container").executeUpdate(); + s.createQuery("delete from Info").executeUpdate(); + s.createQuery("delete from Owner").executeUpdate(); + t.commit(); + s.close(); + } + + public void testDefaultReadOnlyWithQueryForEntity() { + Container cOrig = createContainer(); + Set expectedInitializedObjects = + new HashSet( + Arrays.asList( new Object[ ] { + cOrig, cOrig.getNoProxyInfo(), cOrig.getProxyInfo(), cOrig.getNonLazyInfo(), + cOrig.getNoProxyOwner(), cOrig.getProxyOwner(), cOrig.getNonLazyOwner(), + cOrig.getLazyDataPoints().iterator().next(), + cOrig.getNonLazyJoinDataPoints().iterator().next(), + cOrig.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + Set expectedReadOnlyObjects = new HashSet(); + + Session s = openSession(); + assertFalse( s.isDefaultReadOnly() ); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + s.save( cOrig ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + s.setDefaultReadOnly( true ); + assertTrue( s.isDefaultReadOnly() ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.setDefaultReadOnly( true ); + assertTrue( s.isDefaultReadOnly() ); + Container c = ( Container ) s.createQuery( "from Container where id=" + cOrig.getId() ) + .uniqueResult(); + expectedInitializedObjects = + new HashSet( + Arrays.asList( new Object[ ] { + c, c.getNonLazyInfo(), + c.getNoProxyOwner(), c.getProxyOwner(), c.getNonLazyOwner(), + c.getNonLazyJoinDataPoints().iterator().next(), + c.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + expectedReadOnlyObjects = + new HashSet( + Arrays.asList( new Object[ ] { + c, c.getNoProxyInfo(), c.getProxyInfo(), c.getNonLazyInfo(), + c.getNoProxyOwner(), c.getProxyOwner(), c.getNonLazyOwner(), + //c.getLazyDataPoints(), + c.getNonLazyJoinDataPoints().iterator().next(), + c.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + assertFalse( Hibernate.isInitialized( c.getNoProxyInfo() ) ); + Hibernate.initialize( c.getNoProxyInfo() ); + expectedInitializedObjects.add( c.getNoProxyInfo() ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + assertFalse( Hibernate.isInitialized( c.getProxyInfo() ) ); + Hibernate.initialize( c.getProxyInfo() ); + expectedInitializedObjects.add( c.getProxyInfo() ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + assertFalse( Hibernate.isInitialized( c.getLazyDataPoints() ) ); + Hibernate.initialize( c.getLazyDataPoints() ); + expectedInitializedObjects.add( c.getLazyDataPoints().iterator().next() ); + expectedReadOnlyObjects.add(c.getLazyDataPoints().iterator().next() ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + t.commit(); + s.close(); + s = openSession(); + t = s.beginTransaction(); + s.createQuery("delete from DataPoint").executeUpdate(); + s.createQuery("delete from Container").executeUpdate(); + s.createQuery("delete from Info").executeUpdate(); + s.createQuery("delete from Owner").executeUpdate(); + t.commit(); + s.close(); + } + + public void testDefaultModifiableWithQueryForEntity() { + Container cOrig = createContainer(); + Set expectedInitializedObjects = + new HashSet( + Arrays.asList( new Object[ ] { + cOrig, cOrig.getNoProxyInfo(), cOrig.getProxyInfo(), cOrig.getNonLazyInfo(), + cOrig.getNoProxyOwner(), cOrig.getProxyOwner(), cOrig.getNonLazyOwner(), + cOrig.getLazyDataPoints().iterator().next(), + cOrig.getNonLazyJoinDataPoints().iterator().next(), + cOrig.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + Set expectedReadOnlyObjects = new HashSet(); + + Session s = openSession(); + assertFalse( s.isDefaultReadOnly() ); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + s.save( cOrig ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + s.setDefaultReadOnly( true ); + assertTrue( s.isDefaultReadOnly() ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + assertFalse( s.isDefaultReadOnly() ); + Container c = ( Container ) s.createQuery( "from Container where id=" + cOrig.getId() ) + .uniqueResult(); + expectedInitializedObjects = + new HashSet( + Arrays.asList( new Object[ ] { + c, c.getNonLazyInfo(), + c.getNoProxyOwner(), c.getProxyOwner(), c.getNonLazyOwner(), + c.getNonLazyJoinDataPoints().iterator().next(), + c.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + expectedReadOnlyObjects = new HashSet(); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + assertFalse( Hibernate.isInitialized( c.getNoProxyInfo() ) ); + Hibernate.initialize( c.getNoProxyInfo() ); + expectedInitializedObjects.add( c.getNoProxyInfo() ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + assertFalse( Hibernate.isInitialized( c.getProxyInfo() ) ); + Hibernate.initialize( c.getProxyInfo() ); + expectedInitializedObjects.add( c.getProxyInfo() ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + assertFalse( Hibernate.isInitialized( c.getLazyDataPoints() ) ); + Hibernate.initialize( c.getLazyDataPoints() ); + expectedInitializedObjects.add( c.getLazyDataPoints().iterator().next() ); + //expectedReadOnlyObjects.add(c.getLazyDataPoints().iterator().next() ); + checkContainer( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + t.commit(); + s.close(); + s = openSession(); + t = s.beginTransaction(); + s.createQuery("delete from DataPoint").executeUpdate(); + s.createQuery("delete from Container").executeUpdate(); + s.createQuery("delete from Info").executeUpdate(); + s.createQuery("delete from Owner").executeUpdate(); + t.commit(); + s.close(); + } + + public void testDefaultModifiableWithReadOnlyQueryForCollectionEntities() { + Container cOrig = createContainer(); + Set expectedInitializedObjects = + new HashSet( + Arrays.asList( new Object[ ] { + cOrig, cOrig.getNoProxyInfo(), cOrig.getProxyInfo(), cOrig.getNonLazyInfo(), + cOrig.getNoProxyOwner(), cOrig.getProxyOwner(), cOrig.getNonLazyOwner(), + cOrig.getLazyDataPoints().iterator().next(), + cOrig.getNonLazyJoinDataPoints().iterator().next(), + cOrig.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + Set expectedReadOnlyObjects = new HashSet(); + + Session s = openSession(); + assertFalse( s.isDefaultReadOnly() ); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + s.save( cOrig ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + s.setDefaultReadOnly( true ); + assertTrue( s.isDefaultReadOnly() ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + assertFalse( s.isDefaultReadOnly() ); + DataPoint dp = ( DataPoint ) s.createQuery( "select c.lazyDataPoints from Container c join c.lazyDataPoints where c.id=" + cOrig.getId() ) + .setReadOnly( true ).uniqueResult(); + assertTrue( s.isReadOnly( dp ) ); + t.commit(); + s.close(); + s = openSession(); + t = s.beginTransaction(); + s.createQuery("delete from DataPoint").executeUpdate(); + s.createQuery("delete from Container").executeUpdate(); + s.createQuery("delete from Info").executeUpdate(); + s.createQuery("delete from Owner").executeUpdate(); + t.commit(); + s.close(); + } + + public void testDefaultReadOnlyWithModifiableFilterCollectionEntities() { + Container cOrig = createContainer(); + Set expectedInitializedObjects = + new HashSet( + Arrays.asList( new Object[ ] { + cOrig, cOrig.getNoProxyInfo(), cOrig.getProxyInfo(), cOrig.getNonLazyInfo(), + cOrig.getNoProxyOwner(), cOrig.getProxyOwner(), cOrig.getNonLazyOwner(), + cOrig.getLazyDataPoints().iterator().next(), + cOrig.getNonLazyJoinDataPoints().iterator().next(), + cOrig.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + Set expectedReadOnlyObjects = new HashSet(); + + Session s = openSession(); + assertFalse( s.isDefaultReadOnly() ); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + s.save( cOrig ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + s.setDefaultReadOnly( true ); + assertTrue( s.isDefaultReadOnly() ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.setDefaultReadOnly( true ); + assertTrue( s.isDefaultReadOnly() ); + Container c = ( Container ) s.get( Container.class, cOrig.getId() ); + assertNotSame( cOrig, c ); + expectedInitializedObjects = + new HashSet( + Arrays.asList( new Object[ ] { + c, c.getNonLazyInfo(), + c.getNoProxyOwner(), c.getProxyOwner(), c.getNonLazyOwner(), + c.getNonLazyJoinDataPoints().iterator().next(), + c.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + expectedReadOnlyObjects = + new HashSet( + Arrays.asList( new Object[ ] { + c, c.getNoProxyInfo(), c.getProxyInfo(), c.getNonLazyInfo(), + c.getNoProxyOwner(), c.getProxyOwner(), c.getNonLazyOwner(), + //c.getLazyDataPoints(), + c.getNonLazyJoinDataPoints().iterator().next(), + c.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + List list = ( List ) s.createFilter( c.getLazyDataPoints(), "" ) + .setMaxResults(1) + .setReadOnly( false ) + .list(); + assertEquals( 1, list.size() ); + assertFalse( s.isReadOnly( list.get( 0 ) ) ); + list = ( List ) s.createFilter( c.getNonLazyJoinDataPoints(), "" ) + .setMaxResults(1) + .setReadOnly( false ) + .list(); + assertEquals( 1, list.size() ); + assertTrue( s.isReadOnly( list.get( 0 ) ) ); + list = ( List ) s.createFilter( c.getNonLazySelectDataPoints(), "" ) + .setMaxResults(1) + .setReadOnly( false ) + .list(); + assertEquals( 1, list.size() ); + assertTrue( s.isReadOnly( list.get( 0 ) ) ); + t.commit(); + s.close(); + s = openSession(); + t = s.beginTransaction(); + s.createQuery("delete from DataPoint").executeUpdate(); + s.createQuery("delete from Container").executeUpdate(); + s.createQuery("delete from Info").executeUpdate(); + s.createQuery("delete from Owner").executeUpdate(); + t.commit(); + s.close(); + } + + public void testDefaultModifiableWithReadOnlyFilterCollectionEntities() { + Container cOrig = createContainer(); + Set expectedInitializedObjects = + new HashSet( + Arrays.asList( new Object[ ] { + cOrig, cOrig.getNoProxyInfo(), cOrig.getProxyInfo(), cOrig.getNonLazyInfo(), + cOrig.getNoProxyOwner(), cOrig.getProxyOwner(), cOrig.getNonLazyOwner(), + cOrig.getLazyDataPoints().iterator().next(), + cOrig.getNonLazyJoinDataPoints().iterator().next(), + cOrig.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + Set expectedReadOnlyObjects = new HashSet(); + + Session s = openSession(); + assertFalse( s.isDefaultReadOnly() ); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + s.save( cOrig ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + s.setDefaultReadOnly( true ); + assertTrue( s.isDefaultReadOnly() ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + assertFalse( s.isDefaultReadOnly() ); + Container c = ( Container ) s.get( Container.class, cOrig.getId() ); + assertNotSame( cOrig, c ); + expectedInitializedObjects = + new HashSet( + Arrays.asList( new Object[ ] { + c, c.getNonLazyInfo(), + c.getNoProxyOwner(), c.getProxyOwner(), c.getNonLazyOwner(), + c.getNonLazyJoinDataPoints().iterator().next(), + c.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + expectedReadOnlyObjects = new HashSet(); + List list = ( List ) s.createFilter( c.getLazyDataPoints(), "" ) + .setMaxResults(1) + .setReadOnly( true ) + .list(); + assertEquals( 1, list.size() ); + assertTrue( s.isReadOnly( list.get( 0 ) ) ); + list = ( List ) s.createFilter( c.getNonLazyJoinDataPoints(), "" ) + .setMaxResults(1) + .setReadOnly( true ) + .list(); + assertEquals( 1, list.size() ); + assertFalse( s.isReadOnly( list.get( 0 ) ) ); + list = ( List ) s.createFilter( c.getNonLazySelectDataPoints(), "" ) + .setMaxResults(1) + .setReadOnly( true ) + .list(); + assertEquals( 1, list.size() ); + assertFalse( s.isReadOnly( list.get( 0 ) ) ); + t.commit(); + s.close(); + s = openSession(); + t = s.beginTransaction(); + s.createQuery("delete from DataPoint").executeUpdate(); + s.createQuery("delete from Container").executeUpdate(); + s.createQuery("delete from Info").executeUpdate(); + s.createQuery("delete from Owner").executeUpdate(); + t.commit(); + s.close(); + } + + public void testDefaultReadOnlyWithFilterCollectionEntities() { + Container cOrig = createContainer(); + Set expectedInitializedObjects = + new HashSet( + Arrays.asList( new Object[ ] { + cOrig, cOrig.getNoProxyInfo(), cOrig.getProxyInfo(), cOrig.getNonLazyInfo(), + cOrig.getNoProxyOwner(), cOrig.getProxyOwner(), cOrig.getNonLazyOwner(), + cOrig.getLazyDataPoints().iterator().next(), + cOrig.getNonLazyJoinDataPoints().iterator().next(), + cOrig.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + Set expectedReadOnlyObjects = new HashSet(); + + Session s = openSession(); + assertFalse( s.isDefaultReadOnly() ); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + s.save( cOrig ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + s.setDefaultReadOnly( true ); + assertTrue( s.isDefaultReadOnly() ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.setDefaultReadOnly( true ); + assertTrue( s.isDefaultReadOnly() ); + Container c = ( Container ) s.get( Container.class, cOrig.getId() ); + assertNotSame( cOrig, c ); + expectedInitializedObjects = + new HashSet( + Arrays.asList( new Object[ ] { + c, c.getNonLazyInfo(), + c.getNoProxyOwner(), c.getProxyOwner(), c.getNonLazyOwner(), + c.getNonLazyJoinDataPoints().iterator().next(), + c.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + expectedReadOnlyObjects = + new HashSet( + Arrays.asList( new Object[ ] { + c, c.getNoProxyInfo(), c.getProxyInfo(), c.getNonLazyInfo(), + c.getNoProxyOwner(), c.getProxyOwner(), c.getNonLazyOwner(), + //c.getLazyDataPoints(), + c.getNonLazyJoinDataPoints().iterator().next(), + c.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + List list = ( List ) s.createFilter( c.getLazyDataPoints(), "" ) + .setMaxResults(1) + .list(); + assertEquals( 1, list.size() ); + assertTrue( s.isReadOnly( list.get( 0 ) ) ); + list = ( List ) s.createFilter( c.getNonLazyJoinDataPoints(), "" ) + .setMaxResults(1) + .list(); + assertEquals( 1, list.size() ); + assertTrue( s.isReadOnly( list.get( 0 ) ) ); + list = ( List ) s.createFilter( c.getNonLazySelectDataPoints(), "" ) + .setMaxResults(1) + .list(); + assertEquals( 1, list.size() ); + assertTrue( s.isReadOnly( list.get( 0 ) ) ); + t.commit(); + s.close(); + s = openSession(); + t = s.beginTransaction(); + s.createQuery("delete from DataPoint").executeUpdate(); + s.createQuery("delete from Container").executeUpdate(); + s.createQuery("delete from Info").executeUpdate(); + s.createQuery("delete from Owner").executeUpdate(); + t.commit(); + s.close(); + } + + public void testDefaultModifiableWithFilterCollectionEntities() { + Container cOrig = createContainer(); + Set expectedInitializedObjects = + new HashSet( + Arrays.asList( new Object[ ] { + cOrig, cOrig.getNoProxyInfo(), cOrig.getProxyInfo(), cOrig.getNonLazyInfo(), + cOrig.getNoProxyOwner(), cOrig.getProxyOwner(), cOrig.getNonLazyOwner(), + cOrig.getLazyDataPoints().iterator().next(), + cOrig.getNonLazyJoinDataPoints().iterator().next(), + cOrig.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + Set expectedReadOnlyObjects = new HashSet(); + + Session s = openSession(); + assertFalse( s.isDefaultReadOnly() ); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + s.save( cOrig ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + s.setDefaultReadOnly( true ); + assertTrue( s.isDefaultReadOnly() ); + checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + assertFalse( s.isDefaultReadOnly() ); + Container c = ( Container ) s.get( Container.class, cOrig.getId() ); + assertNotSame( cOrig, c ); + expectedInitializedObjects = + new HashSet( + Arrays.asList( new Object[ ] { + c, c.getNonLazyInfo(), + c.getNoProxyOwner(), c.getProxyOwner(), c.getNonLazyOwner(), + c.getNonLazyJoinDataPoints().iterator().next(), + c.getNonLazySelectDataPoints().iterator().next() + } + ) + ); + expectedReadOnlyObjects = new HashSet(); + List list = ( List ) s.createFilter( c.getLazyDataPoints(), "" ) + .setMaxResults(1) + .list(); + assertEquals( 1, list.size() ); + assertFalse( s.isReadOnly( list.get( 0 ) ) ); + list = ( List ) s.createFilter( c.getNonLazyJoinDataPoints(), "" ) + .setMaxResults(1) + .list(); + assertEquals( 1, list.size() ); + assertFalse( s.isReadOnly( list.get( 0 ) ) ); + list = ( List ) s.createFilter( c.getNonLazySelectDataPoints(), "" ) + .setMaxResults(1) + .list(); + assertEquals( 1, list.size() ); + assertFalse( s.isReadOnly( list.get( 0 ) ) ); + t.commit(); + s.close(); + s = openSession(); + t = s.beginTransaction(); + s.createQuery("delete from DataPoint").executeUpdate(); + s.createQuery("delete from Container").executeUpdate(); + s.createQuery("delete from Info").executeUpdate(); + s.createQuery("delete from Owner").executeUpdate(); + t.commit(); + s.close(); + } + +/* + public void testQueryReadOnlyModeExplicitLeftOuterJoinNonLazy() { + + Container cOrig = createContainer(); + Session s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + s.save( cOrig ); + t.commit(); + s.close(); + + s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + t = s.beginTransaction(); + List list = s.createQuery( "from Container c left outer join c.nonLazyInfo where c.id = :id" ) + .setLong( "id", cOrig.getId() ) + .setReadOnly( true ) + .list(); + assertEquals( 1, list.size() ); + Container c = ( Container ) list.get( 0 ); + check( c, true, s ); + check( c.getNoProxyInfo(), false, s ); + check( c.getProxyInfo(), false, s ); + check( c.getNonLazyInfo(), true, s ); + + //check( c.getNoProxyOwner(), true, s ); + //check( c.getProxyOwner(), true, s ); + //check( c.getNonLazyOwner(), true, s ); + check( c.getLazyDataPoints(), false, s ); + //check( c.getNonLazyJoinDataPoints(), true, s ); + //check( c.getNonLazySelectDataPoints(), true, s ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.createQuery("delete from DataPoint").executeUpdate(); + s.createQuery("delete from Container").executeUpdate(); + s.createQuery("delete from Info").executeUpdate(); + s.createQuery("delete from Owner").executeUpdate(); + t.commit(); + s.close(); + + } + + public void testQueryReadOnlyModeExplicitLeftJoinFetchNonLazy() { + + Container cOrig = createContainer(); + Session s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + s.save( cOrig ); + t.commit(); + s.close(); + + s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + t = s.beginTransaction(); + List list = s.createQuery( "from Container c left join fetch c.nonLazyInfo where c.id = :id" ) + .setLong( "id", cOrig.getId() ) + .setReadOnly( true ) + .list(); + assertEquals( 1, list.size() ); + Container c = ( Container ) list.get( 0 ); + check( c, true, s ); + check( c.getNoProxyInfo(), false, s ); + check( c.getProxyInfo(), false, s ); + check( c.getNonLazyInfo(), true, s ); + + // note that Container the following many-to-one properties use a property-ref + // so they are initialized, regardless of how the lazy attribute is mapped: + // noProxyOwner, proxyOwner, nonLazyOwner + //check( c.getNoProxyOwner(), true, s ); + //check( c.getProxyOwner(), true, s ); + //check( c.getNonLazyOwner(), true, s ); + check( c.getLazyDataPoints(), false, s ); + //check( c.getNonLazyJoinDataPoints(), true, s ); + //check( c.getNonLazySelectDataPoints(), true, s ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.createQuery("delete from DataPoint").executeUpdate(); + s.createQuery("delete from Container").executeUpdate(); + s.createQuery("delete from Info").executeUpdate(); + s.createQuery("delete from Owner").executeUpdate(); + t.commit(); + s.close(); + + } + + public void testEntityReadOnlyMode() { + + Container cOrig = createContainer(); + Session s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + s.save( cOrig ); + t.commit(); + s.close(); + + s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + t = s.beginTransaction(); + Container c = ( Container ) s.get( Container.class, cOrig.getId() ); + assertNotNull( c ); + s.setReadOnly( c, true ); + check( c, true, s ); + check( c.getNoProxyInfo(), false, s ); + check( c.getProxyInfo(), false, s ); + check( c.getNonLazyInfo(), true, s ); + + // note that Container the following many-to-one properties use a property-ref + // so they are initialized, regardless of how the lazy attribute is mapped: + // noProxyOwner, proxyOwner, nonLazyOwner + check( c.getNoProxyOwner(), true, s ); + check( c.getProxyOwner(), true, s ); + check( c.getNonLazyOwner(), true, s ); + check( c.getLazyDataPoints(), false, s ); + check( c.getNonLazyJoinDataPoints(), true, s ); + check( c.getNonLazySelectDataPoints(), true, s ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.createQuery("delete from DataPoint").executeUpdate(); + s.createQuery("delete from Container").executeUpdate(); + s.createQuery("delete from Info").executeUpdate(); + s.createQuery("delete from Owner").executeUpdate(); + t.commit(); + s.close(); + + } +*/ + + private Container createContainer() { + Container c = new Container( "container" ); + c.setNoProxyInfo( new Info( "no-proxy info" ) ); + c.setProxyInfo( new Info( "proxy info" ) ); + c.setNonLazyInfo( new Info( "non-lazy info" ) ); + c.setNoProxyOwner( new Owner( "no-proxy owner" ) ); + c.setProxyOwner( new Owner( "proxy owner" ) ); + c.setNonLazyOwner( new Owner( "non-lazy owner" ) ); + c.getLazyDataPoints().add( new DataPoint( new BigDecimal( 1 ), new BigDecimal( 1 ), "lazy data point" ) ); + c.getNonLazyJoinDataPoints().add( new DataPoint( new BigDecimal( 2 ), new BigDecimal( 2 ), "non-lazy join data point" ) ); + c.getNonLazySelectDataPoints().add( new DataPoint( new BigDecimal( 3 ), new BigDecimal( 3 ), "non-lazy select data point" ) ); + return c; + } + + private void checkContainer(Container c, Set expectedInitializedObjects, Set expectedReadOnlyObjects, Session s) { + checkObject( c, expectedInitializedObjects, expectedReadOnlyObjects, s ); + if ( ! expectedInitializedObjects.contains( c ) ) { + return; + } + checkObject( c.getNoProxyInfo(), expectedInitializedObjects, expectedReadOnlyObjects, s); + checkObject( c.getProxyInfo(), expectedInitializedObjects, expectedReadOnlyObjects, s); + checkObject( c.getNonLazyInfo(), expectedInitializedObjects, expectedReadOnlyObjects, s ); + checkObject( c.getNoProxyOwner(), expectedInitializedObjects, expectedReadOnlyObjects, s ); + checkObject( c.getProxyOwner(), expectedInitializedObjects, expectedReadOnlyObjects, s ); + checkObject( c.getNonLazyOwner(), expectedInitializedObjects, expectedReadOnlyObjects, s ); + if ( Hibernate.isInitialized( c.getLazyDataPoints() ) ) { + for ( Iterator it=c.getLazyDataPoints().iterator(); it.hasNext(); ) { + checkObject( it.next(), expectedInitializedObjects, expectedReadOnlyObjects, s ); + } + } + for ( Iterator it=c.getNonLazyJoinDataPoints().iterator(); it.hasNext(); ) { + checkObject( it.next(), expectedInitializedObjects, expectedReadOnlyObjects, s ); + } + for ( Iterator it=c.getNonLazySelectDataPoints().iterator(); it.hasNext(); ) { + checkObject( it.next(), expectedInitializedObjects, expectedReadOnlyObjects, s ); + } + } + + private void checkObject(Object entityOrProxy, Set expectedInitializedObjects, Set expectedReadOnlyObjects, Session s) { + boolean isExpectedToBeInitialized = expectedInitializedObjects.contains( entityOrProxy ); + boolean isExpectedToBeReadOnly = expectedReadOnlyObjects.contains( entityOrProxy ); + SessionImplementor si = ( SessionImplementor ) s; + assertEquals( isExpectedToBeInitialized, Hibernate.isInitialized( entityOrProxy ) ); + assertEquals( isExpectedToBeReadOnly, s.isReadOnly( entityOrProxy ) ); + if ( Hibernate.isInitialized( entityOrProxy ) ) { + Object entity = ( entityOrProxy instanceof HibernateProxy ? + ( ( HibernateProxy ) entityOrProxy ).getHibernateLazyInitializer().getImplementation( si ) : + entityOrProxy + ); + assertNotNull( entity ); + assertEquals( isExpectedToBeReadOnly, s.isReadOnly( entity )); + } + } + +} \ No newline at end of file diff --git a/testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlySessionTest.java b/testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlySessionTest.java new file mode 100644 index 0000000000..da180ef75e --- /dev/null +++ b/testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlySessionTest.java @@ -0,0 +1,456 @@ +//$Id: ReadOnlyTest.java 10977 2006-12-12 23:28:04Z steve.ebersole@jboss.com $ +/* + * 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.test.readonly; + +import java.math.BigDecimal; +import java.util.List; + +import junit.framework.Test; + +import org.hibernate.CacheMode; +import org.hibernate.Hibernate; +import org.hibernate.ScrollMode; +import org.hibernate.ScrollableResults; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * + * @author Gail Badner + */ +public class ReadOnlySessionTest extends FunctionalTestCase { + + public ReadOnlySessionTest(String str) { + super(str); + } + + public String[] getMappings() { + return new String[] { "readonly/DataPoint.hbm.xml", "readonly/TextHolder.hbm.xml" }; + } + + public void configure(Configuration cfg) { + cfg.setProperty(Environment.STATEMENT_BATCH_SIZE, "20"); + } + + public String getCacheConcurrencyStrategy() { + return null; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( ReadOnlySessionTest.class ); + } + + public void testReadOnlyOnProxies() { + Session s = openSession(); + s.setCacheMode( CacheMode.IGNORE ); + s.beginTransaction(); + DataPoint dp = new DataPoint(); + dp.setX( new BigDecimal( 0.1d ).setScale(19, BigDecimal.ROUND_DOWN) ); + dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale(19, BigDecimal.ROUND_DOWN) ); + dp.setDescription( "original" ); + s.save( dp ); + long dpId = dp.getId(); + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + s.beginTransaction(); + s.setDefaultReadOnly( true ); + assertTrue( s.isDefaultReadOnly() ); + dp = ( DataPoint ) s.load( DataPoint.class, new Long( dpId ) ); + s.setDefaultReadOnly( false ); + assertFalse( "was initialized", Hibernate.isInitialized( dp ) ); + assertTrue( s.isReadOnly( dp ) ); + assertFalse( "was initialized during isReadOnly", Hibernate.isInitialized( dp ) ); + dp.setDescription( "changed" ); + assertTrue( "was not initialized during mod", Hibernate.isInitialized( dp ) ); + assertEquals( "desc not changed in memory", "changed", dp.getDescription() ); + s.flush(); + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.beginTransaction(); + List list = s.createQuery( "from DataPoint where description = 'changed'" ).list(); + assertEquals( "change written to database", 0, list.size() ); + s.createQuery("delete from DataPoint").executeUpdate(); + s.getTransaction().commit(); + s.close(); + } + + public void testReadOnlyMode() { + + Session s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + for ( int i=0; i<100; 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); + } + t.commit(); + s.close(); + + s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + t = s.beginTransaction(); + s.setDefaultReadOnly( true ); + int i = 0; + ScrollableResults sr = s.createQuery("from DataPoint dp order by dp.x asc") + .scroll(ScrollMode.FORWARD_ONLY); + while ( sr.next() ) { + DataPoint dp = (DataPoint) sr.get(0); + if (++i==50) { + s.setReadOnly(dp, false); + } + dp.setDescription("done!"); + } + t.commit(); + s.clear(); + t = s.beginTransaction(); + List single = s.createQuery("from DataPoint where description='done!'").list(); + assertEquals( single.size(), 1 ); + s.createQuery("delete from DataPoint").executeUpdate(); + t.commit(); + s.close(); + } + + public void testReadOnlyQueryScrollChangeToModifiableBeforeIterate() { + + Session s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + for ( int i=0; i<100; 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); + } + t.commit(); + s.close(); + + s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + t = s.beginTransaction(); + s.setDefaultReadOnly( true ); + int i = 0; + ScrollableResults sr = s.createQuery("from DataPoint dp order by dp.x asc") + .scroll(ScrollMode.FORWARD_ONLY); + s.setDefaultReadOnly( false ); + while ( sr.next() ) { + DataPoint dp = (DataPoint) sr.get(0); + if (++i==50) { + s.setReadOnly(dp, false); + } + dp.setDescription("done!"); + } + t.commit(); + s.clear(); + t = s.beginTransaction(); + List single = s.createQuery("from DataPoint where description='done!'").list(); + assertEquals( 1, single.size() ); + s.createQuery("delete from DataPoint").executeUpdate(); + t.commit(); + s.close(); + } + + public void testReadOnlyRefreshFailureExpected() { + + Session s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + DataPoint dp = new DataPoint(); + dp.setDescription( "original" ); + dp.setX( new BigDecimal(0.1d).setScale(19, BigDecimal.ROUND_DOWN) ); + dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale(19, BigDecimal.ROUND_DOWN) ); + s.save(dp); + t.commit(); + s.close(); + + s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + s.setDefaultReadOnly( true ); + t = s.beginTransaction(); + dp = ( DataPoint ) s.get( DataPoint.class, dp.getId() ); + assertEquals( "original", dp.getDescription() ); + dp.setDescription( "changed" ); + assertEquals( "changed", dp.getDescription() ); + s.setDefaultReadOnly( false ); + s.refresh( dp ); + assertEquals( "original", dp.getDescription() ); + dp.setDescription( "changed" ); + assertEquals( "changed", dp.getDescription() ); + t.commit(); + + s.clear(); + t = s.beginTransaction(); + dp = ( DataPoint ) s.get( DataPoint.class, dp.getId() ); + assertEquals( "original", dp.getDescription() ); + s.delete( dp ); + t.commit(); + s.close(); + + } + + public void testReadOnlyDelete() { + + Session s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + DataPoint dp = new DataPoint(); + dp.setX( new BigDecimal(0.1d).setScale(19, BigDecimal.ROUND_DOWN) ); + dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale(19, BigDecimal.ROUND_DOWN) ); + s.save(dp); + t.commit(); + s.close(); + + s = openSession(); + s.setDefaultReadOnly( true ); + s.setCacheMode(CacheMode.IGNORE); + t = s.beginTransaction(); + dp = ( DataPoint ) s.get( DataPoint.class, dp.getId() ); + s.setDefaultReadOnly( false ); + assertTrue( s.isReadOnly( dp ) ); + s.delete( dp ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + List list = s.createQuery("from DataPoint where id=" + dp.getId() ).list(); + assertTrue( list.isEmpty() ); + t.commit(); + s.close(); + + } + + public void testReadOnlyGetModifyAndDelete() { + + Session s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + DataPoint dp = new DataPoint(); + dp.setX( new BigDecimal(0.1d).setScale(19, BigDecimal.ROUND_DOWN) ); + dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale(19, BigDecimal.ROUND_DOWN) ); + s.save(dp); + t.commit(); + s.close(); + + s = openSession(); + s.setDefaultReadOnly( true ); + s.setCacheMode(CacheMode.IGNORE); + t = s.beginTransaction(); + dp = ( DataPoint ) s.get( DataPoint.class, dp.getId() ); + s.setDefaultReadOnly( true ); + dp.setDescription( "a DataPoint" ); + s.delete( dp ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + List list = s.createQuery("from DataPoint where id=" + dp.getId() ).list(); + assertTrue( list.isEmpty() ); + t.commit(); + s.close(); + + } + + public void testReadOnlyModeWithExistingModifiableEntity() { + + Session s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + DataPoint dp = null; + for ( int i=0; i<100; i++ ) { + 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); + } + t.commit(); + s.close(); + + s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + t = s.beginTransaction(); + DataPoint dpLast = ( DataPoint ) s.get( DataPoint.class, dp.getId() ); + assertFalse( s.isReadOnly( dpLast ) ); + s.setDefaultReadOnly( true ); + int i = 0; + ScrollableResults sr = s.createQuery("from DataPoint dp order by dp.x asc") + .scroll(ScrollMode.FORWARD_ONLY); + s.setDefaultReadOnly( false ); + int nExpectedChanges = 0; + while ( sr.next() ) { + dp = (DataPoint) sr.get(0); + if ( dp.getId() == dpLast.getId() ) { + //dpLast existed in the session before executing the read-only query + assertFalse( s.isReadOnly( dp ) ); + } + else { + assertTrue( s.isReadOnly( dp ) ); + } + if (++i==50) { + s.setReadOnly(dp, false); + nExpectedChanges = ( dp == dpLast ? 1 : 2 ); + } + dp.setDescription("done!"); + } + t.commit(); + s.clear(); + t = s.beginTransaction(); + List list = s.createQuery("from DataPoint where description='done!'").list(); + assertEquals( nExpectedChanges, list.size() ); + s.createQuery("delete from DataPoint").executeUpdate(); + t.commit(); + s.close(); + } + + public void testModifiableModeWithExistingReadOnlyEntity() { + + Session s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + DataPoint dp = null; + for ( int i=0; i<100; i++ ) { + 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); + } + t.commit(); + s.close(); + + s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + t = s.beginTransaction(); + s.setDefaultReadOnly( true ); + DataPoint dpLast = ( DataPoint ) s.get( DataPoint.class, dp.getId() ); + assertTrue( s.isReadOnly( dpLast ) ); + int i = 0; + ScrollableResults sr = s.createQuery("from DataPoint dp order by dp.x asc") + .setReadOnly(false) + .scroll(ScrollMode.FORWARD_ONLY); + int nExpectedChanges = 0; + while ( sr.next() ) { + dp = (DataPoint) sr.get(0); + if ( dp.getId() == dpLast.getId() ) { + //dpLast existed in the session before executing the read-only query + assertTrue( s.isReadOnly( dp ) ); + } + else { + assertFalse( s.isReadOnly( dp ) ); + } + if (++i==50) { + s.setReadOnly(dp, true); + nExpectedChanges = ( dp == dpLast ? 99 : 98 ); + } + dp.setDescription("done!"); + } + t.commit(); + s.clear(); + t = s.beginTransaction(); + List list = s.createQuery("from DataPoint where description='done!'").list(); + assertEquals( nExpectedChanges, list.size() ); + s.createQuery("delete from DataPoint").executeUpdate(); + t.commit(); + s.close(); + } + + public void testReadOnlyOnTextType() { + final String origText = "some huge text string"; + final String newText = "some even bigger text string"; + + Session s = openSession(); + s.beginTransaction(); + s.setCacheMode( CacheMode.IGNORE ); + TextHolder holder = new TextHolder( origText ); + s.save( holder ); + Long id = holder.getId(); + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.beginTransaction(); + s.setDefaultReadOnly( true ); + s.setCacheMode( CacheMode.IGNORE ); + holder = ( TextHolder ) s.get( TextHolder.class, id ); + s.setDefaultReadOnly( false ); + holder.setTheText( newText ); + s.flush(); + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.beginTransaction(); + holder = ( TextHolder ) s.get( TextHolder.class, id ); + assertEquals( "change written to database", origText, holder.getTheText() ); + s.delete( holder ); + s.getTransaction().commit(); + s.close(); + } + + public void testMergeWithReadOnlyEntity() { + + Session s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + DataPoint dp = new DataPoint(); + dp.setX( new BigDecimal(0.1d).setScale(19, BigDecimal.ROUND_DOWN) ); + dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale(19, BigDecimal.ROUND_DOWN) ); + s.save(dp); + t.commit(); + s.close(); + + dp.setDescription( "description" ); + + s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + t = s.beginTransaction(); + s.setDefaultReadOnly( true ); + DataPoint dpManaged = ( DataPoint ) s.get( DataPoint.class, new Long( dp.getId() ) ); + DataPoint dpMerged = ( DataPoint ) s.merge( dp ); + assertSame( dpManaged, dpMerged ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + dpManaged = ( DataPoint ) s.get( DataPoint.class, new Long( dp.getId() ) ); + assertNull( dpManaged.getDescription() ); + s.delete( dpManaged ); + t.commit(); + s.close(); + + } +} \ No newline at end of file diff --git a/testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlyTest.java b/testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlyTest.java index d251357e67..16f6613bc3 100755 --- a/testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlyTest.java +++ b/testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlyTest.java @@ -26,6 +26,7 @@ package org.hibernate.test.readonly; import java.math.BigDecimal; +import java.util.Iterator; import java.util.List; import junit.framework.Test; @@ -44,6 +45,7 @@ import org.hibernate.junit.functional.FunctionalTestClassTestSuite; /** * * @author Gavin King + * @author Gail Badner */ public class ReadOnlyTest extends FunctionalTestCase { @@ -142,6 +144,31 @@ public class ReadOnlyTest extends FunctionalTestCase { } + public void testReadOnlyModeAutoFlushOnQuery() { + + Session s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + DataPoint dpFirst = null; + for ( int i=0; i<100; 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); + } + ScrollableResults sr = s.createQuery("from DataPoint dp order by dp.x asc") + .setReadOnly(true) + .scroll(ScrollMode.FORWARD_ONLY); + while ( sr.next() ) { + DataPoint dp = (DataPoint) sr.get(0); + assertFalse( s.isReadOnly( dp ) ); + s.delete( dp ); + } + t.commit(); + s.close(); + + } + public void testReadOnlyRefreshFailureExpected() { Session s = openSession(); @@ -209,6 +236,37 @@ public class ReadOnlyTest extends FunctionalTestCase { } + public void testReadOnlyGetModifyAndDelete() { + + Session s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + DataPoint dp = new DataPoint(); + dp.setX( new BigDecimal(0.1d).setScale(19, BigDecimal.ROUND_DOWN) ); + dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale(19, BigDecimal.ROUND_DOWN) ); + s.save(dp); + t.commit(); + s.close(); + + s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + t = s.beginTransaction(); + dp = ( DataPoint ) s.get( DataPoint.class, dp.getId() ); + s.setReadOnly( dp, true ); + dp.setDescription( "a DataPoint" ); + s.delete( dp ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + List list = s.createQuery("from DataPoint where description='done!'").list(); + assertTrue( list.isEmpty() ); + t.commit(); + s.close(); + + } + public void testReadOnlyModeWithExistingModifiableEntity() { Session s = openSession();