From cac26d30773d1073f66240417c5f347c9f7b0da2 Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Mon, 2 Nov 2015 21:35:28 -0800 Subject: [PATCH] HHH-10202 : Delay resolving TypeScopeImpl#factory after deserialization until resolveFactory() is called. (cherry picked from commit c835cf11ec72353bd1cfc96b69942b81a4ae0f8d) --- .../java/org/hibernate/type/TypeFactory.java | 26 ++- .../TypeFactorySerializationTest.java | 189 ++++++++++++++++++ 2 files changed, 213 insertions(+), 2 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/serialization/TypeFactorySerializationTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/type/TypeFactory.java b/hibernate-core/src/main/java/org/hibernate/type/TypeFactory.java index 92eca04b34..17c2882dc7 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/TypeFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/type/TypeFactory.java @@ -12,9 +12,11 @@ import java.util.Properties; import org.hibernate.HibernateException; import org.hibernate.MappingException; +import org.hibernate.boot.cfgxml.spi.CfgXmlAccessService; import org.hibernate.classic.Lifecycle; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.internal.CoreMessageLogger; +import org.hibernate.internal.SessionFactoryRegistry; import org.hibernate.internal.util.ReflectHelper; import org.hibernate.tuple.component.ComponentMetamodel; import org.hibernate.usertype.CompositeUserType; @@ -44,7 +46,9 @@ public final class TypeFactory implements Serializable { } private static class TypeScopeImpl implements TypeFactory.TypeScope { - private SessionFactoryImplementor factory; + private transient SessionFactoryImplementor factory; + private String sessionFactoryName; + private String sessionFactoryUuid; public void injectSessionFactory(SessionFactoryImplementor factory) { if ( this.factory != null ) { @@ -52,13 +56,31 @@ public final class TypeFactory implements Serializable { } else { LOG.tracev( "Scoping types to session factory {0}", factory ); + sessionFactoryUuid = factory.getUuid(); + String sfName = factory.getSettings().getSessionFactoryName(); + if ( sfName == null ) { + final CfgXmlAccessService cfgXmlAccessService = factory.getServiceRegistry() + .getService( CfgXmlAccessService.class ); + if ( cfgXmlAccessService.getAggregatedConfig() != null ) { + sfName = cfgXmlAccessService.getAggregatedConfig().getSessionFactoryName(); + } + } + sessionFactoryName = sfName; } this.factory = factory; } public SessionFactoryImplementor resolveFactory() { if ( factory == null ) { - throw new HibernateException( "SessionFactory for type scoping not yet known" ); + factory = (SessionFactoryImplementor) SessionFactoryRegistry.INSTANCE.findSessionFactory( + sessionFactoryUuid, + sessionFactoryName + ); + if ( factory == null ) { + throw new HibernateException( + "Could not find a SessionFactory [uuid=" + sessionFactoryUuid + ",name=" + sessionFactoryName + "]" + ); + } } return factory; } diff --git a/hibernate-core/src/test/java/org/hibernate/test/serialization/TypeFactorySerializationTest.java b/hibernate-core/src/test/java/org/hibernate/test/serialization/TypeFactorySerializationTest.java new file mode 100644 index 0000000000..567036f5cd --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/serialization/TypeFactorySerializationTest.java @@ -0,0 +1,189 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.serialization; + +import org.junit.Test; + +import org.hibernate.HibernateException; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cfg.Configuration; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.internal.SessionFactoryRegistry; +import org.hibernate.internal.util.SerializationHelper; +import org.hibernate.testing.junit4.BaseUnitTestCase; +import org.hibernate.type.TypeFactory; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.fail; + +/** + * @author Gail Badner + */ +public class TypeFactorySerializationTest extends BaseUnitTestCase { + private static String NAME = "test name"; + + @Test + public void testWithSameRegisteredSessionFactory() throws Exception { + Configuration cfg = new Configuration() + .setProperty( AvailableSettings.SESSION_FACTORY_NAME, NAME ) + .setProperty( AvailableSettings.SESSION_FACTORY_NAME_IS_JNDI, "false" ); // default is true + SessionFactoryImplementor factory = (SessionFactoryImplementor) cfg.buildSessionFactory(); + + // Session factory is registered. + assertSame( factory, SessionFactoryRegistry.INSTANCE.getNamedSessionFactory( NAME ) ); + + TypeFactory typeFactory = factory.getTypeResolver().getTypeFactory(); + byte[] typeFactoryBytes = SerializationHelper.serialize( typeFactory ); + typeFactory = (TypeFactory) SerializationHelper.deserialize( typeFactoryBytes ); + + assertSame( factory, typeFactory.resolveSessionFactory() ); + factory.close(); + } + + @Test + public void testUnregisterSerializeRegisterSameSessionFactory() throws Exception { + Configuration cfg = new Configuration() + .setProperty( AvailableSettings.SESSION_FACTORY_NAME, NAME ) + .setProperty( AvailableSettings.SESSION_FACTORY_NAME_IS_JNDI, "false" ); // default is true + SessionFactoryImplementor factory = (SessionFactoryImplementor) cfg.buildSessionFactory(); + assertSame( factory, SessionFactoryRegistry.INSTANCE.getNamedSessionFactory( NAME ) ); + + // Remove the session factory from the registry + SessionFactoryRegistry.INSTANCE.removeSessionFactory( factory.getUuid(), NAME, false, null ); + assertNull( SessionFactoryRegistry.INSTANCE.findSessionFactory( factory.getUuid(), NAME ) ); + + TypeFactory typeFactory = factory.getTypeResolver().getTypeFactory(); + byte[] typeFactoryBytes = SerializationHelper.serialize( typeFactory ); + typeFactory = (TypeFactory) SerializationHelper.deserialize( typeFactoryBytes ); + + try { + typeFactory.resolveSessionFactory(); + fail( "should have failed with HibernateException because session factory is not registered." ); + } + catch ( HibernateException ex ) { + // expected because the session factory is not registered. + } + + // Re-register the same session factory. + SessionFactoryRegistry.INSTANCE.addSessionFactory( factory.getUuid(), NAME, false, factory, null ); + + // Session factory resolved from typeFactory should be the new session factory + // (because it is resolved from SessionFactoryRegistry.INSTANCE) + assertSame( factory, typeFactory.resolveSessionFactory() ); + factory.close(); + } + + @Test + public void testUnregisterSerializeRegisterSameSessionFactoryNoName() throws Exception { + Configuration cfg = new Configuration(); + SessionFactoryImplementor factory = (SessionFactoryImplementor) cfg.buildSessionFactory(); + assertSame( factory, SessionFactoryRegistry.INSTANCE.findSessionFactory( factory.getUuid(), null ) ); + + // Remove the session factory from the registry + SessionFactoryRegistry.INSTANCE.removeSessionFactory( factory.getUuid(), null, false, null ); + assertNull( SessionFactoryRegistry.INSTANCE.findSessionFactory( factory.getUuid(), null ) ); + + TypeFactory typeFactory = factory.getTypeResolver().getTypeFactory(); + byte[] typeFactoryBytes = SerializationHelper.serialize( typeFactory ); + typeFactory = (TypeFactory) SerializationHelper.deserialize( typeFactoryBytes ); + + try { + typeFactory.resolveSessionFactory(); + fail( "should have failed with HibernateException because session factory is not registered." ); + } + catch ( HibernateException ex ) { + // expected because the session factory is not registered. + } + + // Re-register the same session factory. + SessionFactoryRegistry.INSTANCE.addSessionFactory( factory.getUuid(), null, false, factory, null ); + + // Session factory resolved from typeFactory should be the new session factory + // (because it is resolved from SessionFactoryRegistry.INSTANCE) + assertSame( factory, typeFactory.resolveSessionFactory() ); + factory.close(); + } + + @Test + public void testUnregisterSerializeRegisterDiffSessionFactory() throws Exception { + Configuration cfg = new Configuration() + .setProperty( AvailableSettings.SESSION_FACTORY_NAME, NAME ) + .setProperty( AvailableSettings.SESSION_FACTORY_NAME_IS_JNDI, "false" ); // default is true + SessionFactoryImplementor factory = (SessionFactoryImplementor) cfg.buildSessionFactory(); + assertSame( factory, SessionFactoryRegistry.INSTANCE.getNamedSessionFactory( NAME ) ); + + // Remove the session factory from the registry + SessionFactoryRegistry.INSTANCE.removeSessionFactory( factory.getUuid(), NAME, false, null ); + assertNull( SessionFactoryRegistry.INSTANCE.findSessionFactory( factory.getUuid(), NAME ) ); + + TypeFactory typeFactory = factory.getTypeResolver().getTypeFactory(); + byte[] typeFactoryBytes = SerializationHelper.serialize( typeFactory ); + typeFactory = (TypeFactory) SerializationHelper.deserialize( typeFactoryBytes ); + + try { + typeFactory.resolveSessionFactory(); + fail( "should have failed with HibernateException because session factory is not registered." ); + } + catch ( HibernateException ex ) { + // expected because the session factory is not registered. + } + + // Now create a new session factory with the same name; it will have a different UUID. + SessionFactoryImplementor factoryWithSameName = (SessionFactoryImplementor) cfg.buildSessionFactory(); + assertSame( factoryWithSameName, SessionFactoryRegistry.INSTANCE.getNamedSessionFactory( NAME ) ); + assertFalse( factory.getUuid().equals( factoryWithSameName.getUuid() ) ); + + // Session factory resolved from typeFactory should be the new session factory + // (because it is resolved from SessionFactoryRegistry.INSTANCE) + assertSame( factoryWithSameName, typeFactory.resolveSessionFactory() ); + + factory.close(); + factoryWithSameName.close(); + } + + @Test + public void testUnregisterSerializeRegisterDiffSessionFactoryNoName() throws Exception { + Configuration cfg = new Configuration(); + SessionFactoryImplementor factory = (SessionFactoryImplementor) cfg.buildSessionFactory(); + assertSame( factory, SessionFactoryRegistry.INSTANCE.getSessionFactory( factory.getUuid() ) ); + + // Remove the session factory from the registry + SessionFactoryRegistry.INSTANCE.removeSessionFactory( factory.getUuid(), null, false, null ); + assertNull( SessionFactoryRegistry.INSTANCE.getSessionFactory( factory.getUuid() ) ); + + TypeFactory typeFactory = factory.getTypeResolver().getTypeFactory(); + byte[] typeFactoryBytes = SerializationHelper.serialize( typeFactory ); + typeFactory = (TypeFactory) SerializationHelper.deserialize( typeFactoryBytes ); + + try { + typeFactory.resolveSessionFactory(); + fail( "should have failed with HibernateException because session factory is not registered." ); + } + catch ( HibernateException ex ) { + // expected because the session factory is not registered. + } + + // Now create a new session factory with the same name; it will have a different UUID. + SessionFactoryImplementor factoryWithDiffUuid = (SessionFactoryImplementor) cfg.buildSessionFactory(); + assertSame( factoryWithDiffUuid, SessionFactoryRegistry.INSTANCE.getSessionFactory( factoryWithDiffUuid.getUuid() ) ); + assertFalse( factory.getUuid().equals( factoryWithDiffUuid.getUuid() ) ); + + // It should not be possible to resolve the session factory with no name configured. + try { + typeFactory.resolveSessionFactory(); + fail( "should have failed with HibernateException because session factories were not registered with the same non-null name." ); + } + catch ( HibernateException ex ) { + // expected + } + + factory.close(); + factoryWithDiffUuid.close(); + } +}