diff --git a/core/src/main/java/org/hibernate/engine/ActionQueue.java b/core/src/main/java/org/hibernate/engine/ActionQueue.java index ccc22bccf1..48b087b964 100644 --- a/core/src/main/java/org/hibernate/engine/ActionQueue.java +++ b/core/src/main/java/org/hibernate/engine/ActionQueue.java @@ -375,10 +375,13 @@ public void clearFromFlushNeededCheck(int previousCollectionRemovalSize) { } public boolean hasAfterTransactionActions() { - // todo : method is not used anywhere; why is it here? return afterTransactionProcesses.processes.size() > 0; } + public boolean hasBeforeTransactionActions() { + return beforeTransactionProcesses.processes.size() > 0; + } + public boolean hasAnyQueuedActions() { return updates.size() > 0 || insertions.size() > 0 || diff --git a/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java b/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java index 42bd3518e3..72167a41dc 100755 --- a/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java +++ b/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java @@ -35,6 +35,7 @@ import java.util.Map; import javax.persistence.CacheRetrieveMode; import javax.persistence.CacheStoreMode; +import javax.persistence.EntityManager; import javax.persistence.EntityNotFoundException; import javax.persistence.EntityTransaction; import javax.persistence.FlushModeType; @@ -895,16 +896,16 @@ public void joinTransaction() { } public T unwrap(Class clazz) { - if ( clazz.equals( Session.class ) ) { + if ( Session.class.isAssignableFrom( clazz ) ) { return ( T ) getSession(); } - if ( clazz.equals( SessionImplementor.class ) ) { + if ( SessionImplementor.class.isAssignableFrom( clazz ) ) { return ( T ) getSession(); } - else { - //unknown class type - throw new PersistenceException( "Hibernate cannot unwrap " + clazz); + if ( EntityManager.class.isAssignableFrom( clazz ) ) { + return (T) this; } + throw new PersistenceException( "Hibernate cannot unwrap " + clazz); } private void joinTransaction(boolean ignoreNotJoining) { diff --git a/entitymanager/src/test/java/org/hibernate/ejb/test/TestCase.java b/entitymanager/src/test/java/org/hibernate/ejb/test/TestCase.java index 72df658104..83298cc450 100644 --- a/entitymanager/src/test/java/org/hibernate/ejb/test/TestCase.java +++ b/entitymanager/src/test/java/org/hibernate/ejb/test/TestCase.java @@ -193,9 +193,14 @@ public Map getConfig() { dds.addAll( Arrays.asList( getEjb3DD() ) ); config.put( AvailableSettings.XML_FILE_NAMES, dds ); } + + addConfigOptions( config ); return config; } + protected void addConfigOptions(Map options) { + } + @Override public void runBare() throws Throwable { if ( !appliesTo( Dialect.getDialect() ) ) { diff --git a/entitymanager/src/test/java/org/hibernate/ejb/test/lock/Lockable.java b/entitymanager/src/test/java/org/hibernate/ejb/test/lock/Lockable.java new file mode 100644 index 0000000000..f78ba2245f --- /dev/null +++ b/entitymanager/src/test/java/org/hibernate/ejb/test/lock/Lockable.java @@ -0,0 +1,75 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.ejb.test.lock; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Version; + +/** + * TODO : javadoc + * + * @author Steve Ebersole + */ +@Entity +public class Lockable { + private Integer id; + private Integer version; + private String name; + + public Lockable() { + } + + public Lockable(String name) { + this.name = name; + } + + @Id + @GeneratedValue + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Version + public Integer getVersion() { + return version; + } + + public void setVersion(Integer version) { + this.version = version; + } +} diff --git a/entitymanager/src/test/java/org/hibernate/ejb/test/lock/QueryLockingTest.java b/entitymanager/src/test/java/org/hibernate/ejb/test/lock/QueryLockingTest.java index f446ac095d..fe63860cc2 100644 --- a/entitymanager/src/test/java/org/hibernate/ejb/test/lock/QueryLockingTest.java +++ b/entitymanager/src/test/java/org/hibernate/ejb/test/lock/QueryLockingTest.java @@ -23,14 +23,16 @@ */ package org.hibernate.ejb.test.lock; +import java.util.Map; import javax.persistence.EntityManager; import javax.persistence.LockModeType; import org.hibernate.LockMode; -import org.hibernate.Session; +import org.hibernate.cfg.AnnotationConfiguration; import org.hibernate.ejb.AvailableSettings; import org.hibernate.ejb.QueryImpl; import org.hibernate.ejb.test.TestCase; +import org.hibernate.impl.SessionImpl; /** * TODO : javadoc @@ -41,13 +43,19 @@ public class QueryLockingTest extends TestCase { @Override protected Class[] getAnnotatedClasses() { - return new Class[] { Lock.class }; + return new Class[] { Lockable.class }; + } + + @Override + @SuppressWarnings({ "unchecked" }) + protected void addConfigOptions(Map options) { + options.put( AnnotationConfiguration.USE_NEW_ID_GENERATOR_MAPPINGS, "true" ); } public void testOverallLockMode() { EntityManager em = getOrCreateEntityManager(); em.getTransaction().begin(); - QueryImpl jpaQuery = em.createQuery( "from Lock_ l" ).unwrap( QueryImpl.class ); + QueryImpl jpaQuery = em.createQuery( "from Lockable l" ).unwrap( QueryImpl.class ); org.hibernate.impl.QueryImpl hqlQuery = (org.hibernate.impl.QueryImpl) jpaQuery.getHibernateQuery(); assertEquals( LockMode.NONE, hqlQuery.getLockOptions().getLockMode() ); @@ -69,10 +77,10 @@ public void testOverallLockMode() { em.close(); } - public void testForcedIncrementOverall() { + public void testPessimisticForcedIncrementOverall() { EntityManager em = getOrCreateEntityManager(); em.getTransaction().begin(); - Lock lock = new Lock( "name" ); + Lockable lock = new Lockable( "name" ); em.persist( lock ); em.getTransaction().commit(); em.close(); @@ -81,14 +89,148 @@ public void testForcedIncrementOverall() { em = getOrCreateEntityManager(); em.getTransaction().begin(); - Lock reread = em.createQuery( "from Lock_", Lock.class ).setLockMode( LockModeType.PESSIMISTIC_FORCE_INCREMENT ).getSingleResult(); + Lockable reread = em.createQuery( "from Lockable", Lockable.class ).setLockMode( LockModeType.PESSIMISTIC_FORCE_INCREMENT ).getSingleResult(); + assertFalse( reread.getVersion().equals( initial ) ); + em.getTransaction().commit(); + em.close(); + + em = getOrCreateEntityManager(); + em.getTransaction().begin(); + em.remove( em.getReference( Lockable.class, reread.getId() ) ); + em.getTransaction().commit(); + em.close(); + } + + public void testPessimisticForcedIncrementSpecific() { + EntityManager em = getOrCreateEntityManager(); + em.getTransaction().begin(); + Lockable lock = new Lockable( "name" ); + em.persist( lock ); + em.getTransaction().commit(); + em.close(); + Integer initial = lock.getVersion(); + assertNotNull( initial ); + + em = getOrCreateEntityManager(); + em.getTransaction().begin(); + Lockable reread = em.createQuery( "from Lockable l", Lockable.class ) + .setHint( AvailableSettings.ALIAS_SPECIFIC_LOCK_MODE+".l", LockModeType.PESSIMISTIC_FORCE_INCREMENT ) + .getSingleResult(); + assertFalse( reread.getVersion().equals( initial ) ); + em.getTransaction().commit(); + em.close(); + + em = getOrCreateEntityManager(); + em.getTransaction().begin(); + em.remove( em.getReference( Lockable.class, reread.getId() ) ); + em.getTransaction().commit(); + em.close(); + } + + public void testOptimisticForcedIncrementOverall() { + EntityManager em = getOrCreateEntityManager(); + em.getTransaction().begin(); + Lockable lock = new Lockable( "name" ); + em.persist( lock ); + em.getTransaction().commit(); + em.close(); + Integer initial = lock.getVersion(); + assertNotNull( initial ); + + em = getOrCreateEntityManager(); + em.getTransaction().begin(); + Lockable reread = em.createQuery( "from Lockable", Lockable.class ).setLockMode( LockModeType.OPTIMISTIC_FORCE_INCREMENT ).getSingleResult(); + assertEquals( initial, reread.getVersion() ); em.getTransaction().commit(); em.close(); assertFalse( reread.getVersion().equals( initial ) ); em = getOrCreateEntityManager(); em.getTransaction().begin(); - em.remove( em.getReference( Lock.class, reread.getId() ) ); + em.remove( em.getReference( Lockable.class, reread.getId() ) ); + em.getTransaction().commit(); + em.close(); + } + + public void testOptimisticForcedIncrementSpecific() { + EntityManager em = getOrCreateEntityManager(); + em.getTransaction().begin(); + Lockable lock = new Lockable( "name" ); + em.persist( lock ); + em.getTransaction().commit(); + em.close(); + Integer initial = lock.getVersion(); + assertNotNull( initial ); + + em = getOrCreateEntityManager(); + em.getTransaction().begin(); + Lockable reread = em.createQuery( "from Lockable l", Lockable.class ) + .setHint( AvailableSettings.ALIAS_SPECIFIC_LOCK_MODE+".l", LockModeType.OPTIMISTIC_FORCE_INCREMENT ) + .getSingleResult(); + assertEquals( initial, reread.getVersion() ); + em.getTransaction().commit(); + em.close(); + assertFalse( reread.getVersion().equals( initial ) ); + + em = getOrCreateEntityManager(); + em.getTransaction().begin(); + em.remove( em.getReference( Lockable.class, reread.getId() ) ); + em.getTransaction().commit(); + em.close(); + } + + public void testOptimisticOverall() { + EntityManager em = getOrCreateEntityManager(); + em.getTransaction().begin(); + Lockable lock = new Lockable( "name" ); + em.persist( lock ); + em.getTransaction().commit(); + em.close(); + Integer initial = lock.getVersion(); + assertNotNull( initial ); + + em = getOrCreateEntityManager(); + em.getTransaction().begin(); + Lockable reread = em.createQuery( "from Lockable", Lockable.class ) + .setLockMode( LockModeType.OPTIMISTIC ) + .getSingleResult(); + assertEquals( initial, reread.getVersion() ); + assertTrue( em.unwrap( SessionImpl.class ).getActionQueue().hasBeforeTransactionActions() ); + em.getTransaction().commit(); + em.close(); + assertEquals( initial, reread.getVersion() ); + + em = getOrCreateEntityManager(); + em.getTransaction().begin(); + em.remove( em.getReference( Lockable.class, reread.getId() ) ); + em.getTransaction().commit(); + em.close(); + } + + public void testOptimisticSpecific() { + EntityManager em = getOrCreateEntityManager(); + em.getTransaction().begin(); + Lockable lock = new Lockable( "name" ); + em.persist( lock ); + em.getTransaction().commit(); + em.close(); + Integer initial = lock.getVersion(); + assertNotNull( initial ); + + em = getOrCreateEntityManager(); + em.getTransaction().begin(); + Lockable reread = em.createQuery( "from Lockable l", Lockable.class ) + .setHint( AvailableSettings.ALIAS_SPECIFIC_LOCK_MODE+".l", LockModeType.OPTIMISTIC ) + .getSingleResult(); + assertEquals( initial, reread.getVersion() ); + assertTrue( em.unwrap( SessionImpl.class ).getActionQueue().hasBeforeTransactionActions() ); + em.getTransaction().commit(); + em.close(); + assertEquals( initial, reread.getVersion() ); + + em = getOrCreateEntityManager(); + em.getTransaction().begin(); + em.remove( em.getReference( Lockable.class, reread.getId() ) ); em.getTransaction().commit(); em.close(); }