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)
|
@Message(value = "update timestamps cache misses: %s", id = 435)
|
||||||
void timestampCacheMisses(long updateTimestampsCachePutCount);
|
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.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
|
|
||||||
import org.hibernate.AssertionFailure;
|
import org.hibernate.AssertionFailure;
|
||||||
import org.hibernate.CacheMode;
|
import org.hibernate.CacheMode;
|
||||||
|
@ -114,6 +113,8 @@ import org.hibernate.proxy.HibernateProxy;
|
||||||
import org.hibernate.service.jta.platform.spi.JtaPlatform;
|
import org.hibernate.service.jta.platform.spi.JtaPlatform;
|
||||||
import org.hibernate.transform.BasicTransformerAdapter;
|
import org.hibernate.transform.BasicTransformerAdapter;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:gavin@hibernate.org">Gavin King</a>
|
* @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 );
|
entityManagerSpecificProperties.add( QueryHints.SPEC_HINT_TIMEOUT );
|
||||||
}
|
}
|
||||||
|
|
||||||
private EntityManagerFactoryImpl entityManagerFactory;
|
private transient EntityManagerFactoryImpl entityManagerFactory;
|
||||||
protected transient TransactionImpl tx = new TransactionImpl( this );
|
protected transient TransactionImpl tx = new TransactionImpl( this );
|
||||||
protected PersistenceContextType persistenceContextType;
|
protected PersistenceContextType persistenceContextType;
|
||||||
private PersistenceUnitTransactionType transactionType;
|
private PersistenceUnitTransactionType transactionType;
|
||||||
|
@ -1235,10 +1236,12 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
|
||||||
|
|
||||||
private void writeObject(ObjectOutputStream oos) throws IOException {
|
private void writeObject(ObjectOutputStream oos) throws IOException {
|
||||||
oos.defaultWriteObject();
|
oos.defaultWriteObject();
|
||||||
|
entityManagerFactory.serialize(oos);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
|
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
|
||||||
ois.defaultReadObject();
|
ois.defaultReadObject();
|
||||||
|
entityManagerFactory = (EntityManagerFactoryImpl)EntityManagerFactoryImpl.deserialize(ois);
|
||||||
tx = new TransactionImpl( this );
|
tx = new TransactionImpl( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -307,6 +307,11 @@ public class AvailableSettings {
|
||||||
*/
|
*/
|
||||||
public static final String PACKAGE_NAMES = "hibernate.ejb.packages";
|
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
|
* List of classes names
|
||||||
* Internal use only
|
* Internal use only
|
||||||
|
@ -318,4 +323,5 @@ public class AvailableSettings {
|
||||||
public static final String JACC_PREFIX = "hibernate.jacc";
|
public static final String JACC_PREFIX = "hibernate.jacc";
|
||||||
public static final String JACC_ENABLED = "hibernate.jacc.enabled";
|
public static final String JACC_ENABLED = "hibernate.jacc.enabled";
|
||||||
public static final String PERSISTENCE_UNIT_NAME = "hibernate.ejb.persistenceUnitName";
|
public static final String PERSISTENCE_UNIT_NAME = "hibernate.ejb.persistenceUnitName";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,19 +23,6 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.ejb;
|
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.BufferedInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -58,12 +45,21 @@ import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.StringTokenizer;
|
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.dom4j.Element;
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
import org.xml.sax.EntityResolver;
|
|
||||||
import org.xml.sax.InputSource;
|
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.Interceptor;
|
import org.hibernate.Interceptor;
|
||||||
import org.hibernate.MappingException;
|
import org.hibernate.MappingException;
|
||||||
|
@ -109,6 +105,9 @@ import org.hibernate.service.ServiceRegistry;
|
||||||
import org.hibernate.service.ServiceRegistryBuilder;
|
import org.hibernate.service.ServiceRegistryBuilder;
|
||||||
import org.hibernate.service.internal.StandardServiceRegistryImpl;
|
import org.hibernate.service.internal.StandardServiceRegistryImpl;
|
||||||
import org.hibernate.service.jdbc.connections.internal.DatasourceConnectionProviderImpl;
|
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
|
* Allow a fine tuned configuration of an EJB 3.0 EntityManagerFactory
|
||||||
|
@ -902,12 +901,13 @@ public class Ejb3Configuration implements Serializable, Referenceable {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final ServiceRegistry serviceRegistry = buildLifecycleControledServiceRegistry( builder );
|
final ServiceRegistry serviceRegistry = buildLifecycleControledServiceRegistry( builder );
|
||||||
return new EntityManagerFactoryImpl(
|
return new EntityManagerFactoryImpl(
|
||||||
transactionType,
|
transactionType,
|
||||||
discardOnClose,
|
discardOnClose,
|
||||||
getSessionInterceptorClass( cfg.getProperties() ),
|
getSessionInterceptorClass( cfg.getProperties() ),
|
||||||
cfg,
|
cfg,
|
||||||
serviceRegistry
|
serviceRegistry,
|
||||||
|
persistenceUnitName
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
catch (HibernateException e) {
|
catch (HibernateException e) {
|
||||||
|
|
|
@ -21,25 +21,31 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.ejb;
|
package org.hibernate.ejb;
|
||||||
|
|
||||||
import javax.persistence.Cache;
|
import java.io.IOException;
|
||||||
import javax.persistence.EntityManager;
|
import java.io.InvalidObjectException;
|
||||||
import javax.persistence.PersistenceContextType;
|
import java.io.ObjectInputStream;
|
||||||
import javax.persistence.PersistenceUnitUtil;
|
import java.io.ObjectOutputStream;
|
||||||
import javax.persistence.criteria.CriteriaBuilder;
|
|
||||||
import javax.persistence.metamodel.Metamodel;
|
|
||||||
import javax.persistence.spi.LoadState;
|
|
||||||
import javax.persistence.spi.PersistenceUnitTransactionType;
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
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.Hibernate;
|
||||||
import org.hibernate.SessionFactory;
|
import org.hibernate.SessionFactory;
|
||||||
import org.hibernate.cfg.Configuration;
|
import org.hibernate.cfg.Configuration;
|
||||||
import org.hibernate.ejb.criteria.CriteriaBuilderImpl;
|
import org.hibernate.ejb.criteria.CriteriaBuilderImpl;
|
||||||
|
import org.hibernate.ejb.internal.EntityManagerFactoryRegistry;
|
||||||
import org.hibernate.ejb.metamodel.MetamodelImpl;
|
import org.hibernate.ejb.metamodel.MetamodelImpl;
|
||||||
import org.hibernate.ejb.util.PersistenceUtilHelper;
|
import org.hibernate.ejb.util.PersistenceUtilHelper;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
|
@ -63,6 +69,7 @@ public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
|
||||||
private final Metamodel metamodel;
|
private final Metamodel metamodel;
|
||||||
private final HibernatePersistenceUnitUtil util;
|
private final HibernatePersistenceUnitUtil util;
|
||||||
private final Map<String,Object> properties;
|
private final Map<String,Object> properties;
|
||||||
|
private final String entityManagerFactoryName;
|
||||||
|
|
||||||
private final PersistenceUtilHelper.MetadataCache cache = new PersistenceUtilHelper.MetadataCache();
|
private final PersistenceUtilHelper.MetadataCache cache = new PersistenceUtilHelper.MetadataCache();
|
||||||
|
|
||||||
|
@ -72,7 +79,8 @@ public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
|
||||||
boolean discardOnClose,
|
boolean discardOnClose,
|
||||||
Class sessionInterceptorClass,
|
Class sessionInterceptorClass,
|
||||||
Configuration cfg,
|
Configuration cfg,
|
||||||
ServiceRegistry serviceRegistry) {
|
ServiceRegistry serviceRegistry,
|
||||||
|
String persistenceUnitName) {
|
||||||
this.sessionFactory = cfg.buildSessionFactory( serviceRegistry );
|
this.sessionFactory = cfg.buildSessionFactory( serviceRegistry );
|
||||||
this.transactionType = transactionType;
|
this.transactionType = transactionType;
|
||||||
this.discardOnClose = discardOnClose;
|
this.discardOnClose = discardOnClose;
|
||||||
|
@ -92,6 +100,12 @@ public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
|
||||||
addAll( props, ( (SessionFactoryImplementor) sessionFactory ).getProperties() );
|
addAll( props, ( (SessionFactoryImplementor) sessionFactory ).getProperties() );
|
||||||
addAll( props, cfg.getProperties() );
|
addAll( props, cfg.getProperties() );
|
||||||
this.properties = Collections.unmodifiableMap( props );
|
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) {
|
private static void addAll(HashMap<String, Object> propertyMap, Properties properties) {
|
||||||
|
@ -124,6 +138,7 @@ public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
|
||||||
|
|
||||||
public void close() {
|
public void close() {
|
||||||
sessionFactory.close();
|
sessionFactory.close();
|
||||||
|
EntityManagerFactoryRegistry.INSTANCE.removeEntityManagerFactory(entityManagerFactoryName, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, Object> getProperties() {
|
public Map<String, Object> getProperties() {
|
||||||
|
@ -153,6 +168,10 @@ public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
|
||||||
return sessionFactory;
|
return sessionFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getEntityManagerFactoryName() {
|
||||||
|
return entityManagerFactoryName;
|
||||||
|
}
|
||||||
|
|
||||||
private static class JPACache implements Cache {
|
private static class JPACache implements Cache {
|
||||||
private SessionFactory sessionFactory;
|
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 static class HibernatePersistenceUnitUtil implements PersistenceUnitUtil, Serializable {
|
||||||
private final HibernateEntityManagerFactory emf;
|
private final HibernateEntityManagerFactory emf;
|
||||||
private transient PersistenceUtilHelper.MetadataCache cache;
|
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;
|
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.hibernate.ejb.test.BaseEntityManagerFunctionalTestCase;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.junit.Test;
|
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;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -50,60 +50,65 @@ public class UpgradeLockTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testUpgradeReadLockToOptimisticForceIncrement() throws Exception {
|
public void testUpgradeReadLockToOptimisticForceIncrement() throws Exception {
|
||||||
Lock lock = new Lock(); //
|
|
||||||
lock.setName( "name" );
|
|
||||||
EntityManager em = getOrCreateEntityManager();
|
EntityManager em = getOrCreateEntityManager();
|
||||||
final EntityManager em2 = createIsolatedEntityManager();
|
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 {
|
try {
|
||||||
|
Lock lock = new Lock(); //
|
||||||
|
lock.setName( "name" );
|
||||||
|
|
||||||
|
|
||||||
|
em.getTransaction().begin(); // create the test entity first
|
||||||
|
em.persist( lock );
|
||||||
|
|
||||||
em.getTransaction().commit();
|
em.getTransaction().commit();
|
||||||
}
|
|
||||||
catch (Throwable expectedToFail) {
|
em.getTransaction().begin(); // start tx1
|
||||||
while(expectedToFail != null &&
|
lock = em.getReference( Lock.class, lock.getId() );
|
||||||
!(expectedToFail instanceof javax.persistence.OptimisticLockException)) {
|
final Integer id = lock.getId();
|
||||||
expectedToFail = expectedToFail.getCause();
|
|
||||||
|
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;
|
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.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import javax.persistence.EntityManager;
|
||||||
|
import javax.persistence.EntityManagerFactory;
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
|
|
||||||
import org.hibernate.cfg.Configuration;
|
import org.hibernate.cfg.Configuration;
|
||||||
import org.hibernate.cfg.Environment;
|
import org.hibernate.cfg.Environment;
|
||||||
|
@ -46,12 +40,11 @@ import org.hibernate.internal.SessionFactoryImpl;
|
||||||
import org.hibernate.service.BootstrapServiceRegistryBuilder;
|
import org.hibernate.service.BootstrapServiceRegistryBuilder;
|
||||||
import org.hibernate.service.ServiceRegistryBuilder;
|
import org.hibernate.service.ServiceRegistryBuilder;
|
||||||
import org.hibernate.service.internal.StandardServiceRegistryImpl;
|
import org.hibernate.service.internal.StandardServiceRegistryImpl;
|
||||||
|
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
|
||||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A base class for all ejb tests.
|
* A base class for all ejb tests.
|
||||||
*
|
*
|
||||||
|
@ -116,7 +109,9 @@ public abstract class BaseEntityManagerFunctionalTestCase extends BaseUnitTestCa
|
||||||
}
|
}
|
||||||
ejb3Configuration
|
ejb3Configuration
|
||||||
.getHibernateConfiguration()
|
.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
|
ejb3Configuration
|
||||||
.getHibernateConfiguration()
|
.getHibernateConfiguration()
|
||||||
.setProperty( Environment.DIALECT, getDialect().getClass().getName() );
|
.setProperty( Environment.DIALECT, getDialect().getClass().getName() );
|
||||||
|
|
Loading…
Reference in New Issue