HHH-6897 serialization of the EntityManager should be possible
This commit is contained in:
parent
d02864bac6
commit
e18d087592
|
@ -1547,4 +1547,9 @@ public interface CoreMessageLogger extends BasicLogger {
|
|||
@Message(value = "update timestamps cache misses: %s", id = 435)
|
||||
void timestampCacheMisses(long updateTimestampsCachePutCount);
|
||||
|
||||
@LogMessage(level = WARN)
|
||||
@Message(value = "Entity manager factory name (%s) is already registered. If entity manager will be clustered "+
|
||||
"or passivated, specify a unique value for property '%s'", id = 436)
|
||||
void entityManagerFactoryAlreadyRegistered(String emfName, String propertyName);
|
||||
|
||||
}
|
||||
|
|
|
@ -63,7 +63,6 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.CacheMode;
|
||||
|
@ -114,6 +113,8 @@ import org.hibernate.proxy.HibernateProxy;
|
|||
import org.hibernate.service.jta.platform.spi.JtaPlatform;
|
||||
import org.hibernate.transform.BasicTransformerAdapter;
|
||||
import org.hibernate.type.Type;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:gavin@hibernate.org">Gavin King</a>
|
||||
|
@ -138,7 +139,7 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
|
|||
entityManagerSpecificProperties.add( QueryHints.SPEC_HINT_TIMEOUT );
|
||||
}
|
||||
|
||||
private EntityManagerFactoryImpl entityManagerFactory;
|
||||
private transient EntityManagerFactoryImpl entityManagerFactory;
|
||||
protected transient TransactionImpl tx = new TransactionImpl( this );
|
||||
protected PersistenceContextType persistenceContextType;
|
||||
private PersistenceUnitTransactionType transactionType;
|
||||
|
@ -1235,10 +1236,12 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
|
|||
|
||||
private void writeObject(ObjectOutputStream oos) throws IOException {
|
||||
oos.defaultWriteObject();
|
||||
entityManagerFactory.serialize(oos);
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
|
||||
ois.defaultReadObject();
|
||||
entityManagerFactory = (EntityManagerFactoryImpl)EntityManagerFactoryImpl.deserialize(ois);
|
||||
tx = new TransactionImpl( this );
|
||||
}
|
||||
|
||||
|
|
|
@ -307,6 +307,11 @@ public class AvailableSettings {
|
|||
*/
|
||||
public static final String PACKAGE_NAMES = "hibernate.ejb.packages";
|
||||
|
||||
/**
|
||||
* EntityManagerFactory name
|
||||
*/
|
||||
public static final String ENTITY_MANAGER_FACTORY_NAME = "hibernate.ejb.entitymanager_factory_name";
|
||||
|
||||
/**
|
||||
* List of classes names
|
||||
* Internal use only
|
||||
|
@ -318,4 +323,5 @@ public class AvailableSettings {
|
|||
public static final String JACC_PREFIX = "hibernate.jacc";
|
||||
public static final String JACC_ENABLED = "hibernate.jacc.enabled";
|
||||
public static final String PERSISTENCE_UNIT_NAME = "hibernate.ejb.persistenceUnitName";
|
||||
|
||||
}
|
||||
|
|
|
@ -23,19 +23,6 @@
|
|||
*/
|
||||
package org.hibernate.ejb;
|
||||
|
||||
import javax.naming.BinaryRefAddr;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.Reference;
|
||||
import javax.naming.Referenceable;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.EntityNotFoundException;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.persistence.spi.PersistenceUnitInfo;
|
||||
import javax.persistence.spi.PersistenceUnitTransactionType;
|
||||
import javax.sql.DataSource;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
|
@ -58,12 +45,21 @@ import java.util.Map;
|
|||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import javax.naming.BinaryRefAddr;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.Reference;
|
||||
import javax.naming.Referenceable;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.EntityNotFoundException;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.persistence.spi.PersistenceUnitInfo;
|
||||
import javax.persistence.spi.PersistenceUnitTransactionType;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.dom4j.Element;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.xml.sax.EntityResolver;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Interceptor;
|
||||
import org.hibernate.MappingException;
|
||||
|
@ -109,6 +105,9 @@ import org.hibernate.service.ServiceRegistry;
|
|||
import org.hibernate.service.ServiceRegistryBuilder;
|
||||
import org.hibernate.service.internal.StandardServiceRegistryImpl;
|
||||
import org.hibernate.service.jdbc.connections.internal.DatasourceConnectionProviderImpl;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.xml.sax.EntityResolver;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
/**
|
||||
* Allow a fine tuned configuration of an EJB 3.0 EntityManagerFactory
|
||||
|
@ -902,12 +901,13 @@ public class Ejb3Configuration implements Serializable, Referenceable {
|
|||
|
||||
try {
|
||||
final ServiceRegistry serviceRegistry = buildLifecycleControledServiceRegistry( builder );
|
||||
return new EntityManagerFactoryImpl(
|
||||
return new EntityManagerFactoryImpl(
|
||||
transactionType,
|
||||
discardOnClose,
|
||||
getSessionInterceptorClass( cfg.getProperties() ),
|
||||
cfg,
|
||||
serviceRegistry
|
||||
serviceRegistry,
|
||||
persistenceUnitName
|
||||
);
|
||||
}
|
||||
catch (HibernateException e) {
|
||||
|
|
|
@ -21,25 +21,31 @@
|
|||
*/
|
||||
package org.hibernate.ejb;
|
||||
|
||||
import javax.persistence.Cache;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceContextType;
|
||||
import javax.persistence.PersistenceUnitUtil;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.metamodel.Metamodel;
|
||||
import javax.persistence.spi.LoadState;
|
||||
import javax.persistence.spi.PersistenceUnitTransactionType;
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import javax.persistence.Cache;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.PersistenceContextType;
|
||||
import javax.persistence.PersistenceUnitUtil;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.metamodel.Metamodel;
|
||||
import javax.persistence.spi.LoadState;
|
||||
import javax.persistence.spi.PersistenceUnitTransactionType;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.ejb.criteria.CriteriaBuilderImpl;
|
||||
import org.hibernate.ejb.internal.EntityManagerFactoryRegistry;
|
||||
import org.hibernate.ejb.metamodel.MetamodelImpl;
|
||||
import org.hibernate.ejb.util.PersistenceUtilHelper;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
|
@ -63,6 +69,7 @@ public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
|
|||
private final Metamodel metamodel;
|
||||
private final HibernatePersistenceUnitUtil util;
|
||||
private final Map<String,Object> properties;
|
||||
private final String entityManagerFactoryName;
|
||||
|
||||
private final PersistenceUtilHelper.MetadataCache cache = new PersistenceUtilHelper.MetadataCache();
|
||||
|
||||
|
@ -72,7 +79,8 @@ public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
|
|||
boolean discardOnClose,
|
||||
Class sessionInterceptorClass,
|
||||
Configuration cfg,
|
||||
ServiceRegistry serviceRegistry) {
|
||||
ServiceRegistry serviceRegistry,
|
||||
String persistenceUnitName) {
|
||||
this.sessionFactory = cfg.buildSessionFactory( serviceRegistry );
|
||||
this.transactionType = transactionType;
|
||||
this.discardOnClose = discardOnClose;
|
||||
|
@ -92,6 +100,12 @@ public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
|
|||
addAll( props, ( (SessionFactoryImplementor) sessionFactory ).getProperties() );
|
||||
addAll( props, cfg.getProperties() );
|
||||
this.properties = Collections.unmodifiableMap( props );
|
||||
String entityManagerFactoryName = (String)this.properties.get(AvailableSettings.ENTITY_MANAGER_FACTORY_NAME);
|
||||
if (entityManagerFactoryName == null) {
|
||||
entityManagerFactoryName = persistenceUnitName;
|
||||
}
|
||||
this.entityManagerFactoryName = entityManagerFactoryName;
|
||||
EntityManagerFactoryRegistry.INSTANCE.addEntityManagerFactory(entityManagerFactoryName, this);
|
||||
}
|
||||
|
||||
private static void addAll(HashMap<String, Object> propertyMap, Properties properties) {
|
||||
|
@ -124,6 +138,7 @@ public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
|
|||
|
||||
public void close() {
|
||||
sessionFactory.close();
|
||||
EntityManagerFactoryRegistry.INSTANCE.removeEntityManagerFactory(entityManagerFactoryName, this);
|
||||
}
|
||||
|
||||
public Map<String, Object> getProperties() {
|
||||
|
@ -153,6 +168,10 @@ public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
|
|||
return sessionFactory;
|
||||
}
|
||||
|
||||
public String getEntityManagerFactoryName() {
|
||||
return entityManagerFactoryName;
|
||||
}
|
||||
|
||||
private static class JPACache implements Cache {
|
||||
private SessionFactory sessionFactory;
|
||||
|
||||
|
@ -180,6 +199,39 @@ public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom serialization hook used during EntityManager serialization.
|
||||
*
|
||||
* @param oos The stream to which to write the factory
|
||||
* @throws IOException Indicates problems writing out the serial data stream
|
||||
*/
|
||||
void serialize(ObjectOutputStream oos) throws IOException {
|
||||
if (entityManagerFactoryName == null) {
|
||||
throw new InvalidObjectException( "could not serialize entity manager factory with null entityManagerFactoryName" );
|
||||
}
|
||||
oos.writeUTF( entityManagerFactoryName );
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom deserialization hook used during EntityManager deserialization.
|
||||
*
|
||||
* @param ois The stream from which to "read" the factory
|
||||
* @return The deserialized factory
|
||||
* @throws IOException indicates problems reading back serial data stream
|
||||
* @throws ClassNotFoundException indicates problems reading back serial data stream
|
||||
*/
|
||||
static EntityManagerFactory deserialize(ObjectInputStream ois) throws IOException, ClassNotFoundException {
|
||||
final String entityManagerFactoryName = ois.readUTF();
|
||||
Object result = EntityManagerFactoryRegistry.INSTANCE.getNamedEntityManagerFactory(entityManagerFactoryName);
|
||||
|
||||
if ( result == null ) {
|
||||
throw new InvalidObjectException( "could not resolve entity manager factory during entity manager deserialization [name=" + entityManagerFactoryName + "]" );
|
||||
}
|
||||
|
||||
return (EntityManagerFactory)result;
|
||||
}
|
||||
|
||||
|
||||
private static class HibernatePersistenceUnitUtil implements PersistenceUnitUtil, Serializable {
|
||||
private final HibernateEntityManagerFactory emf;
|
||||
private transient PersistenceUtilHelper.MetadataCache cache;
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.ejb.internal;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.ejb.AvailableSettings;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
/**
|
||||
* An internal registry of all {@link org.hibernate.ejb.EntityManagerFactoryImpl} instances for the same
|
||||
* classloader as this class.
|
||||
*
|
||||
* This registry is used for serialization/deserialization of entity managers.
|
||||
*
|
||||
* @author Scott Marlow
|
||||
*/
|
||||
public class EntityManagerFactoryRegistry {
|
||||
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
|
||||
CoreMessageLogger.class,
|
||||
EntityManagerFactoryRegistry.class.getName()
|
||||
);
|
||||
|
||||
public static final EntityManagerFactoryRegistry INSTANCE = new EntityManagerFactoryRegistry();
|
||||
|
||||
private final ConcurrentHashMap<String, Set<EntityManagerFactory>> entityManagerFactoryMap = new ConcurrentHashMap<String, Set<EntityManagerFactory>>();
|
||||
|
||||
public EntityManagerFactoryRegistry() {
|
||||
LOG.debugf( "Initializing EntityManagerFactoryRegistry : %s", this );
|
||||
}
|
||||
|
||||
/**
|
||||
* register the specified entity manager factory
|
||||
*
|
||||
* @param name to register the passed entity manager factory
|
||||
* @param entityManagerFactory
|
||||
*/
|
||||
public void addEntityManagerFactory(String name, EntityManagerFactory entityManagerFactory) {
|
||||
LOG.debugf( "Registering EntityManagerFactory: %s ", name );
|
||||
if (name == null) { // allow unit tests that don't specify the pu name to succeed
|
||||
LOG.tracef( "not registering EntityManagerFactory because name is null");
|
||||
return;
|
||||
}
|
||||
Set<EntityManagerFactory> entityManagerFactorySet = new HashSet<EntityManagerFactory>();
|
||||
entityManagerFactorySet.add(entityManagerFactory);
|
||||
Set<EntityManagerFactory> previous = entityManagerFactoryMap.putIfAbsent( name, entityManagerFactorySet);
|
||||
|
||||
// if multiple entries are found, give warning and add EMF to existing set
|
||||
// later, if EntityManagerFactoryImpl.deserialize is called for an EM returned from any EMF in the set
|
||||
// an exception will be thrown (failing the deserialization attempt).
|
||||
if (previous != null) {
|
||||
LOG.entityManagerFactoryAlreadyRegistered(name, AvailableSettings.ENTITY_MANAGER_FACTORY_NAME);
|
||||
boolean done = false;
|
||||
while( !done) {
|
||||
synchronized (previous) {
|
||||
if (entityManagerFactoryMap.get(name) == previous) { // compare and add EMF if same
|
||||
previous.add(entityManagerFactory);
|
||||
done = true;
|
||||
}
|
||||
else { // else it was removed or a new set added
|
||||
previous = entityManagerFactoryMap.get(name); // get the set added by another thread
|
||||
if (null == previous) { // or add it here if not
|
||||
entityManagerFactoryMap.putIfAbsent( name, new HashSet<EntityManagerFactory>());
|
||||
previous = entityManagerFactoryMap.get(name);// use the current set
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* remove the specified entity manager factory from the EntityManagerFactoryRegistry
|
||||
* @param name
|
||||
* @param entityManagerFactory
|
||||
* @throws HibernateException if the specified entity manager factory could not be found in the registry
|
||||
*/
|
||||
public void removeEntityManagerFactory(String name, EntityManagerFactory entityManagerFactory) throws HibernateException {
|
||||
LOG.debugf( "Remove: name=%s", name );
|
||||
|
||||
if (name == null) { // allow unit tests that don't specify the pu name to succeed
|
||||
LOG.tracef( "not removing EntityManagerFactory from registry because name is null");
|
||||
return;
|
||||
}
|
||||
|
||||
Set<EntityManagerFactory> entityManagerFactorySet = entityManagerFactoryMap.get(name);
|
||||
if (entityManagerFactorySet == null) {
|
||||
throw new HibernateException( "registry does not contain entity manager factory: " + name);
|
||||
}
|
||||
synchronized (entityManagerFactorySet) {
|
||||
boolean removed = entityManagerFactorySet.remove(entityManagerFactory);
|
||||
|
||||
if (entityManagerFactorySet.size() == 0) {
|
||||
entityManagerFactoryMap.remove( name );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup the specified entity manager factory by name
|
||||
* @param name
|
||||
* @return
|
||||
* @throws HibernateException if entity manager factory is not found or if more than one
|
||||
* entity manager factory was registered with name.
|
||||
*/
|
||||
public EntityManagerFactory getNamedEntityManagerFactory(String name) throws HibernateException {
|
||||
LOG.debugf( "Lookup: name=%s", name );
|
||||
Set<EntityManagerFactory> entityManagerFactorySet = entityManagerFactoryMap.get(name);
|
||||
|
||||
if (entityManagerFactorySet == null) {
|
||||
throw new HibernateException( "registry does not contain entity manager factory: " + name);
|
||||
}
|
||||
|
||||
if (entityManagerFactorySet.size() > 1) {
|
||||
throw new HibernateException( "registry contains more than one (" + entityManagerFactorySet.size()+ ") entity manager factories: " + name);
|
||||
}
|
||||
return entityManagerFactorySet.iterator().next();
|
||||
}
|
||||
}
|
|
@ -23,15 +23,15 @@
|
|||
*/
|
||||
package org.hibernate.ejb.test.lock;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.LockModeType;
|
||||
|
||||
import org.hibernate.ejb.test.BaseEntityManagerFunctionalTestCase;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.LockModeType;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
|
@ -50,60 +50,65 @@ public class UpgradeLockTest extends BaseEntityManagerFunctionalTestCase {
|
|||
*/
|
||||
@Test
|
||||
public void testUpgradeReadLockToOptimisticForceIncrement() throws Exception {
|
||||
Lock lock = new Lock(); //
|
||||
lock.setName( "name" );
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
final EntityManager em2 = createIsolatedEntityManager();
|
||||
|
||||
em.getTransaction().begin(); // create the test entity first
|
||||
em.persist( lock );
|
||||
|
||||
em.getTransaction().commit();
|
||||
|
||||
em.getTransaction().begin(); // start tx1
|
||||
lock = em.getReference( Lock.class, lock.getId() );
|
||||
final Integer id = lock.getId();
|
||||
|
||||
em.lock( lock, LockModeType.READ ); // start with READ lock in tx1
|
||||
// upgrade to OPTIMISTIC_FORCE_INCREMENT in tx1
|
||||
em.lock( lock, LockModeType.OPTIMISTIC_FORCE_INCREMENT);
|
||||
lock.setName( "surname" ); // don't end tx1 yet
|
||||
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
Thread t = new Thread( new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
em2.getTransaction().begin(); // start tx2
|
||||
Lock lock2 = em2.getReference( Lock.class, id );
|
||||
lock2.setName("renamed"); // change entity
|
||||
}
|
||||
finally {
|
||||
em2.getTransaction().commit();
|
||||
latch.countDown(); // signal that tx2 is committed
|
||||
em2.close();
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
t.setDaemon( true );
|
||||
t.setName("testUpgradeReadLockToOptimisticForceIncrement tx2");
|
||||
t.start();
|
||||
log.info("testUpgradeReadLockToOptimisticForceIncrement: wait on BG thread");
|
||||
boolean latchSet = latch.await( 10, TimeUnit.SECONDS );
|
||||
assertTrue( "background test thread finished (lock timeout is broken)", latchSet );
|
||||
// tx2 is complete, try to commit tx1
|
||||
try {
|
||||
Lock lock = new Lock(); //
|
||||
lock.setName( "name" );
|
||||
|
||||
|
||||
em.getTransaction().begin(); // create the test entity first
|
||||
em.persist( lock );
|
||||
|
||||
em.getTransaction().commit();
|
||||
}
|
||||
catch (Throwable expectedToFail) {
|
||||
while(expectedToFail != null &&
|
||||
!(expectedToFail instanceof javax.persistence.OptimisticLockException)) {
|
||||
expectedToFail = expectedToFail.getCause();
|
||||
|
||||
em.getTransaction().begin(); // start tx1
|
||||
lock = em.getReference( Lock.class, lock.getId() );
|
||||
final Integer id = lock.getId();
|
||||
|
||||
em.lock( lock, LockModeType.READ ); // start with READ lock in tx1
|
||||
// upgrade to OPTIMISTIC_FORCE_INCREMENT in tx1
|
||||
em.lock( lock, LockModeType.OPTIMISTIC_FORCE_INCREMENT);
|
||||
lock.setName( "surname" ); // don't end tx1 yet
|
||||
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
Thread t = new Thread( new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
em2.getTransaction().begin(); // start tx2
|
||||
Lock lock2 = em2.getReference( Lock.class, id );
|
||||
lock2.setName("renamed"); // change entity
|
||||
}
|
||||
finally {
|
||||
em2.getTransaction().commit();
|
||||
latch.countDown(); // signal that tx2 is committed
|
||||
em2.close();
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
t.setDaemon( true );
|
||||
t.setName("testUpgradeReadLockToOptimisticForceIncrement tx2");
|
||||
t.start();
|
||||
log.info("testUpgradeReadLockToOptimisticForceIncrement: wait on BG thread");
|
||||
boolean latchSet = latch.await( 10, TimeUnit.SECONDS );
|
||||
assertTrue( "background test thread finished (lock timeout is broken)", latchSet );
|
||||
// tx2 is complete, try to commit tx1
|
||||
try {
|
||||
em.getTransaction().commit();
|
||||
}
|
||||
catch (Throwable expectedToFail) {
|
||||
while(expectedToFail != null &&
|
||||
!(expectedToFail instanceof javax.persistence.OptimisticLockException)) {
|
||||
expectedToFail = expectedToFail.getCause();
|
||||
}
|
||||
assertTrue("upgrade to OPTIMISTIC_FORCE_INCREMENT is expected to fail at end of transaction1 since tranaction2 already updated the entity",
|
||||
expectedToFail instanceof javax.persistence.OptimisticLockException);
|
||||
}
|
||||
assertTrue("upgrade to OPTIMISTIC_FORCE_INCREMENT is expected to fail at end of transaction1 since tranaction2 already updated the entity",
|
||||
expectedToFail instanceof javax.persistence.OptimisticLockException);
|
||||
}
|
||||
em.close();
|
||||
finally {
|
||||
em.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -23,18 +23,12 @@
|
|||
*/
|
||||
package org.hibernate.ejb.test;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.Persistence;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
|
@ -46,12 +40,11 @@ import org.hibernate.internal.SessionFactoryImpl;
|
|||
import org.hibernate.service.BootstrapServiceRegistryBuilder;
|
||||
import org.hibernate.service.ServiceRegistryBuilder;
|
||||
import org.hibernate.service.internal.StandardServiceRegistryImpl;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
|
||||
/**
|
||||
* A base class for all ejb tests.
|
||||
*
|
||||
|
@ -116,7 +109,9 @@ public abstract class BaseEntityManagerFunctionalTestCase extends BaseUnitTestCa
|
|||
}
|
||||
ejb3Configuration
|
||||
.getHibernateConfiguration()
|
||||
.setProperty( org.hibernate.cfg.AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, "true" );
|
||||
.setProperty( org.hibernate.cfg.AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, "true")
|
||||
.setProperty( AvailableSettings.ENTITY_MANAGER_FACTORY_NAME, "EMF_BaseEntityManagerFunctionalTestCase");
|
||||
|
||||
ejb3Configuration
|
||||
.getHibernateConfiguration()
|
||||
.setProperty( Environment.DIALECT, getDialect().getClass().getName() );
|
||||
|
|
Loading…
Reference in New Issue