HHH-9146 - hibernate-infinispan should be using JndiService to access CacheManager

This commit is contained in:
Steve Ebersole 2014-04-25 10:02:28 -05:00
parent 9514c56c6d
commit 9db6596a15
3 changed files with 172 additions and 161 deletions

View File

@ -22,17 +22,15 @@
package org.hibernate.cache.infinispan; package org.hibernate.cache.infinispan;
import java.util.Properties; import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.hibernate.cache.CacheException; import org.hibernate.cache.CacheException;
import org.hibernate.engine.jndi.JndiException;
import org.hibernate.engine.jndi.spi.JndiService;
import org.hibernate.internal.util.config.ConfigurationHelper; import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.internal.util.jndi.JndiHelper; import org.hibernate.service.spi.ServiceRegistryAwareService;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.infinispan.manager.EmbeddedCacheManager; import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.util.logging.Log;
import org.infinispan.util.logging.LogFactory;
/** /**
* A {@link org.hibernate.cache.spi.RegionFactory} for <a href="http://www.jboss.org/infinispan">Infinispan</a>-backed cache * A {@link org.hibernate.cache.spi.RegionFactory} for <a href="http://www.jboss.org/infinispan">Infinispan</a>-backed cache
@ -41,9 +39,7 @@ import org.infinispan.util.logging.LogFactory;
* @author Galder Zamarreño * @author Galder Zamarreño
* @since 3.5 * @since 3.5
*/ */
public class JndiInfinispanRegionFactory extends InfinispanRegionFactory { public class JndiInfinispanRegionFactory extends InfinispanRegionFactory implements ServiceRegistryAwareService {
private static final Log log = LogFactory.getLog( JndiInfinispanRegionFactory.class );
/** /**
* Specifies the JNDI name under which the {@link EmbeddedCacheManager} to use is bound. * Specifies the JNDI name under which the {@link EmbeddedCacheManager} to use is bound.
@ -51,6 +47,13 @@ public class JndiInfinispanRegionFactory extends InfinispanRegionFactory {
*/ */
public static final String CACHE_MANAGER_RESOURCE_PROP = "hibernate.cache.infinispan.cachemanager"; public static final String CACHE_MANAGER_RESOURCE_PROP = "hibernate.cache.infinispan.cachemanager";
private JndiService jndiService;
@Override
public void injectServices(ServiceRegistryImplementor serviceRegistry) {
this.jndiService = serviceRegistry.getService( JndiService.class );
}
/** /**
* Constructs a JndiInfinispanRegionFactory * Constructs a JndiInfinispanRegionFactory
*/ */
@ -75,34 +78,18 @@ public class JndiInfinispanRegionFactory extends InfinispanRegionFactory {
if ( name == null ) { if ( name == null ) {
throw new CacheException( "Configuration property " + CACHE_MANAGER_RESOURCE_PROP + " not set" ); throw new CacheException( "Configuration property " + CACHE_MANAGER_RESOURCE_PROP + " not set" );
} }
return locateCacheManager( name, JndiHelper.extractJndiProperties( properties ) );
}
private EmbeddedCacheManager locateCacheManager(String jndiNamespace, Properties jndiProperties) {
Context ctx = null;
try { try {
ctx = new InitialContext( jndiProperties ); return (EmbeddedCacheManager) jndiService.locate( name );
return (EmbeddedCacheManager) ctx.lookup( jndiNamespace );
} }
catch (NamingException ne) { catch (JndiException e) {
final String msg = "Unable to retrieve CacheManager from JNDI [" + jndiNamespace + "]"; throw new CacheException( "Unable to retrieve CacheManager from JNDI [" + name + "]", e );
log.info( msg, ne );
throw new CacheException( msg );
}
finally {
if ( ctx != null ) {
try {
ctx.close();
}
catch (NamingException ne) {
log.info( "Unable to release initial context", ne );
}
}
} }
} }
@Override @Override
public void stop() { public void stop() {
// Do not attempt to stop a cache manager because it wasn't created by this region factory. // Do not attempt to stop a cache manager because it wasn't created by this region factory.
jndiService = null;
} }
} }

View File

@ -23,6 +23,8 @@
*/ */
package org.hibernate.test.cache.infinispan.functional; package org.hibernate.test.cache.infinispan.functional;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties; import java.util.Properties;
import javax.naming.Context; import javax.naming.Context;
import javax.naming.InitialContext; import javax.naming.InitialContext;
@ -31,28 +33,41 @@ import javax.naming.NameNotFoundException;
import javax.naming.Reference; import javax.naming.Reference;
import javax.naming.StringRefAddr; import javax.naming.StringRefAddr;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.Session;
import org.hibernate.boot.registry.BootstrapServiceRegistry;
import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cache.infinispan.InfinispanRegionFactory;
import org.hibernate.cache.infinispan.JndiInfinispanRegionFactory;
import org.hibernate.cfg.Environment;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.transaction.internal.jta.CMTTransactionFactory;
import org.hibernate.metamodel.Metadata;
import org.hibernate.metamodel.MetadataSources;
import org.hibernate.metamodel.spi.MetadataImplementor;
import org.hibernate.stat.Statistics;
import org.hibernate.testing.jta.TestingJtaBootstrap;
import org.hibernate.testing.jta.TestingJtaPlatformImpl;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.hibernate.testing.junit4.BaseUnitTestCase;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.infinispan.Cache; import org.infinispan.Cache;
import org.infinispan.lifecycle.ComponentStatus; import org.infinispan.lifecycle.ComponentStatus;
import org.infinispan.manager.DefaultCacheManager; import org.infinispan.manager.DefaultCacheManager;
import org.infinispan.manager.EmbeddedCacheManager; import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.util.logging.Log; import org.infinispan.util.logging.Log;
import org.infinispan.util.logging.LogFactory; import org.infinispan.util.logging.LogFactory;
import org.jboss.util.naming.NonSerializableFactory; import org.jboss.util.naming.NonSerializableFactory;
import org.jnp.server.Main; import org.jnp.server.Main;
import org.jnp.server.SingletonNamingServer; import org.jnp.server.SingletonNamingServer;
import org.junit.Test;
import org.hibernate.Session;
import org.hibernate.cache.infinispan.InfinispanRegionFactory;
import org.hibernate.cache.infinispan.JndiInfinispanRegionFactory;
import org.hibernate.cache.spi.RegionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.cfg.Mappings;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.stat.Statistics;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
/** /**
@ -61,121 +76,40 @@ import static org.junit.Assert.assertEquals;
* @author Galder Zamarreño * @author Galder Zamarreño
* @since // TODO * @since // TODO
*/ */
public class JndiRegionFactoryTestCase extends SingleNodeTestCase { public class JndiRegionFactoryTestCase extends BaseUnitTestCase {
private static final Log log = LogFactory.getLog( JndiRegionFactoryTestCase.class ); private static final Log log = LogFactory.getLog( JndiRegionFactoryTestCase.class );
private static final String JNDI_NAME = "java:CacheManager"; private static final String JNDI_NAME = "java:CacheManager";
// Naming
private Main namingMain; private Main namingMain;
private SingletonNamingServer namingServer; private SingletonNamingServer namingServer;
private Properties props;
private boolean bindToJndi = true;
private EmbeddedCacheManager manager; private EmbeddedCacheManager manager;
@Override
protected void cleanupTest() throws Exception {
Context ctx = new InitialContext( props );
unbind( JNDI_NAME, ctx );
namingServer.destroy();
namingMain.stop();
manager.stop(); // Need to stop cos JNDI region factory does not stop it.
}
@Override @Before
protected Class<? extends RegionFactory> getCacheRegionFactory() { public void setUp() {
return JndiInfinispanRegionFactory.class;
}
@Override
public void afterConfigurationBuilt(Mappings mappings, Dialect dialect) {
if ( bindToJndi ) {
try {
// Create an in-memory jndi
namingServer = new SingletonNamingServer();
namingMain = new Main();
namingMain.setInstallGlobalService( true );
namingMain.setPort( -1 );
namingMain.start();
props = new Properties();
props.put( "java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory" );
props.put( "java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces" );
manager = new DefaultCacheManager( InfinispanRegionFactory.DEF_INFINISPAN_CONFIG_RESOURCE, false );
Context ctx = new InitialContext( props );
bind( JNDI_NAME, manager, EmbeddedCacheManager.class, ctx );
}
catch (Exception e) {
throw new RuntimeException( "Failure to set up JNDI", e );
}
}
}
@Override
public void configure(Configuration cfg) {
super.configure( cfg );
cfg.setProperty( JndiInfinispanRegionFactory.CACHE_MANAGER_RESOURCE_PROP, JNDI_NAME );
cfg.setProperty( Environment.JNDI_CLASS, "org.jnp.interfaces.NamingContextFactory" );
cfg.setProperty( "java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces" );
}
@Test
public void testRedeployment() throws Exception {
addEntityCheckCache( sessionFactory() );
sessionFactory().close();
bindToJndi = false;
SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor) configuration().buildSessionFactory( serviceRegistry() );
addEntityCheckCache( sessionFactory );
JndiInfinispanRegionFactory regionFactory = (JndiInfinispanRegionFactory) sessionFactory.getSettings().getRegionFactory();
Cache cache = regionFactory.getCacheManager().getCache( "org.hibernate.test.cache.infinispan.functional.Item" );
assertEquals( ComponentStatus.RUNNING, cache.getStatus() );
}
private void addEntityCheckCache(SessionFactoryImplementor sessionFactory) throws Exception {
Item item = new Item( "chris", "Chris's Item" );
beginTx();
try { try {
Session s = sessionFactory.openSession(); // Create an in-memory jndi
s.getTransaction().begin(); namingServer = new SingletonNamingServer();
s.persist( item ); namingMain = new Main();
s.getTransaction().commit(); namingMain.setInstallGlobalService( true );
s.close(); namingMain.setPort( -1 );
namingMain.start();
final Properties props = new Properties();
props.put( "java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory" );
props.put( "java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces" );
manager = new DefaultCacheManager( InfinispanRegionFactory.DEF_INFINISPAN_CONFIG_RESOURCE, false );
Context ctx = new InitialContext( props );
bind( JNDI_NAME, manager, EmbeddedCacheManager.class, ctx );
} }
catch (Exception e) { catch (Exception e) {
setRollbackOnlyTx( e ); throw new RuntimeException( "Failure to set up JNDI", e );
} }
finally {
commitOrRollbackTx();
}
beginTx();
try {
Session s = sessionFactory.openSession();
Item found = (Item) s.load( Item.class, item.getId() );
Statistics stats = sessionFactory.getStatistics();
log.info( stats.toString() );
assertEquals( item.getDescription(), found.getDescription() );
assertEquals( 0, stats.getSecondLevelCacheMissCount() );
assertEquals( 1, stats.getSecondLevelCacheHitCount() );
s.delete( found );
s.close();
}
catch (Exception e) {
setRollbackOnlyTx( e );
}
finally {
commitOrRollbackTx();
}
} }
/**
* Helper method that binds the a non serializable object to the JNDI tree.
*
* @param jndiName Name under which the object must be bound
* @param who Object to bind in JNDI
* @param classType Class type under which should appear the bound object
* @param ctx Naming context under which we bind the object
* @throws Exception Thrown if a naming exception occurs during binding
*/
private void bind(String jndiName, Object who, Class<?> classType, Context ctx) throws Exception { private void bind(String jndiName, Object who, Class<?> classType, Context ctx) throws Exception {
// Ah ! This service isn't serializable, so we use a helper class // Ah ! This service isn't serializable, so we use a helper class
NonSerializableFactory.bind( jndiName, who ); NonSerializableFactory.bind( jndiName, who );
@ -199,9 +133,98 @@ public class JndiRegionFactoryTestCase extends SingleNodeTestCase {
ctx.rebind( n.get( 0 ), ref ); ctx.rebind( n.get( 0 ), ref );
} }
private void unbind(String jndiName, Context ctx) throws Exception { @After
NonSerializableFactory.unbind( jndiName ); public void tearDown() {
// ctx.unbind(jndiName); try {
NonSerializableFactory.unbind( JNDI_NAME );
namingServer.destroy();
namingMain.stop();
manager.stop(); // Need to stop cos JNDI region factory does not stop it.
}
catch (Exception e) {
throw new RuntimeException( "Failure to clean up JNDI", e );
}
} }
@Test
public void testRedeployment() throws Exception {
SessionFactoryImplementor sf = (SessionFactoryImplementor) buildMetadata().buildSessionFactory();
addEntityCheckCache( sf );
sf.close();
sf = (SessionFactoryImplementor) buildMetadata().buildSessionFactory();
addEntityCheckCache( sf );
JndiInfinispanRegionFactory regionFactory = (JndiInfinispanRegionFactory) sf.getSettings().getRegionFactory();
Cache cache = regionFactory.getCacheManager().getCache( "org.hibernate.test.cache.infinispan.functional.Item" );
assertEquals( ComponentStatus.RUNNING, cache.getStatus() );
}
@SuppressWarnings("unchecked")
private Metadata buildMetadata() {
Map config = new HashMap();
config.put( Environment.HBM2DDL_AUTO, "create-drop" );
config.put( Environment.USE_SECOND_LEVEL_CACHE, "true" );
config.put( Environment.GENERATE_STATISTICS, "true" );
config.put( Environment.USE_QUERY_CACHE, "true" );
config.put( Environment.CACHE_REGION_FACTORY, JndiInfinispanRegionFactory.class.getName() );
config.put( JndiInfinispanRegionFactory.CACHE_MANAGER_RESOURCE_PROP, JNDI_NAME );
config.put( Environment.JNDI_CLASS, "org.jnp.interfaces.NamingContextFactory" );
config.put( "java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces" );
TestingJtaBootstrap.prepare( config );
config.put( Environment.TRANSACTION_STRATEGY, CMTTransactionFactory.class.getName() );
config.put( Environment.RELEASE_CONNECTIONS, ConnectionReleaseMode.AFTER_STATEMENT.toString() );
BootstrapServiceRegistry bsr = new BootstrapServiceRegistryBuilder().build();
StandardServiceRegistry ssr = new StandardServiceRegistryBuilder( bsr ).applySettings( config ).build();
MetadataSources sources = new MetadataSources( bsr );
sources.addResource( "org/hibernate/test/cache/infinispan/functional/Item.hbm.xml" );
sources.addResource( "org/hibernate/test/cache/infinispan/functional/Customer.hbm.xml" );
sources.addResource( "org/hibernate/test/cache/infinispan/functional/Contact.hbm.xml" );
MetadataImplementor metadata = (MetadataImplementor) sources.getMetadataBuilder( ssr ).build();
BaseCoreFunctionalTestCase.overrideCacheSettings( metadata, "transactional" );
return metadata;
}
private void addEntityCheckCache(SessionFactoryImplementor sessionFactory) throws Exception {
Item item = new Item( "chris", "Chris's Item" );
TestingJtaPlatformImpl.INSTANCE.getTransactionManager().begin();
try {
Session s = sessionFactory.openSession();
s.getTransaction().begin();
s.persist( item );
s.getTransaction().commit();
s.close();
}
catch (Exception e) {
log.error( "Error", e );
TestingJtaPlatformImpl.INSTANCE.getTransactionManager().setRollbackOnly();
}
finally {
TestingJtaPlatformImpl.INSTANCE.getTransactionManager().commit();
}
TestingJtaPlatformImpl.INSTANCE.getTransactionManager().begin();
try {
Session s = sessionFactory.openSession();
Item found = (Item) s.load( Item.class, item.getId() );
Statistics stats = sessionFactory.getStatistics();
log.info( stats.toString() );
assertEquals( item.getDescription(), found.getDescription() );
assertEquals( 0, stats.getSecondLevelCacheMissCount() );
assertEquals( 1, stats.getSecondLevelCacheHitCount() );
s.delete( found );
s.close();
}
catch (Exception e) {
log.error( "Error", e );
TestingJtaPlatformImpl.INSTANCE.getTransactionManager().setRollbackOnly();
}
finally {
TestingJtaPlatformImpl.INSTANCE.getTransactionManager().commit();
}
}
} }

View File

@ -23,8 +23,6 @@
*/ */
package org.hibernate.testing.junit4; package org.hibernate.testing.junit4;
import static org.junit.Assert.fail;
import java.io.InputStream; import java.io.InputStream;
import java.sql.Blob; import java.sql.Blob;
import java.sql.Clob; import java.sql.Clob;
@ -66,16 +64,19 @@ import org.hibernate.metamodel.spi.MetadataImplementor;
import org.hibernate.metamodel.spi.binding.AbstractPluralAttributeBinding; import org.hibernate.metamodel.spi.binding.AbstractPluralAttributeBinding;
import org.hibernate.metamodel.spi.binding.AttributeBinding; import org.hibernate.metamodel.spi.binding.AttributeBinding;
import org.hibernate.metamodel.spi.binding.EntityBinding; import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.type.Type;
import org.hibernate.testing.AfterClassOnce; import org.hibernate.testing.AfterClassOnce;
import org.hibernate.testing.BeforeClassOnce; import org.hibernate.testing.BeforeClassOnce;
import org.hibernate.testing.OnExpectedFailure; import org.hibernate.testing.OnExpectedFailure;
import org.hibernate.testing.OnFailure; import org.hibernate.testing.OnFailure;
import org.hibernate.testing.SkipLog; import org.hibernate.testing.SkipLog;
import org.hibernate.testing.cache.CachingRegionFactory; import org.hibernate.testing.cache.CachingRegionFactory;
import org.hibernate.type.Type;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import static org.junit.Assert.fail;
/** /**
* Applies functional testing logic for core Hibernate testing on top of {@link BaseUnitTestCase} * Applies functional testing logic for core Hibernate testing on top of {@link BaseUnitTestCase}
* *
@ -212,15 +213,19 @@ public abstract class BaseCoreFunctionalTestCase extends BaseUnitTestCase {
return; return;
} }
for ( EntityBinding entityBinding : metadataImplementor.getEntityBindings() ) { overrideCacheSettings( metadataImplementor, getCacheConcurrencyStrategy() );
}
public static void overrideCacheSettings(MetadataImplementor metadata, String accessType) {
for ( EntityBinding entityBinding : metadata.getEntityBindings() ) {
if ( entityBinding.getSuperEntityBinding() == null ) { if ( entityBinding.getSuperEntityBinding() == null ) {
overrideEntityCache( entityBinding ); overrideEntityCache( entityBinding, accessType );
} }
overrideCollectionCachesForEntity( entityBinding ); overrideCollectionCachesForEntity( entityBinding, accessType );
} }
} }
private void overrideEntityCache(EntityBinding entityBinding) { private static void overrideEntityCache(EntityBinding entityBinding, String accessType) {
boolean hasLob = false; boolean hasLob = false;
for ( AttributeBinding attributeBinding : entityBinding.getAttributeBindingClosure() ) { for ( AttributeBinding attributeBinding : entityBinding.getAttributeBindingClosure() ) {
if ( attributeBinding.getAttribute().isSingular() ) { if ( attributeBinding.getAttribute().isSingular() ) {
@ -240,15 +245,11 @@ public abstract class BaseCoreFunctionalTestCase extends BaseUnitTestCase {
entityBinding.getHierarchyDetails().getCaching().setRequested( TruthValue.TRUE ); entityBinding.getHierarchyDetails().getCaching().setRequested( TruthValue.TRUE );
entityBinding.getHierarchyDetails().getCaching().setRegion( entityBinding.getEntityName() ); entityBinding.getHierarchyDetails().getCaching().setRegion( entityBinding.getEntityName() );
entityBinding.getHierarchyDetails().getCaching().setCacheLazyProperties( true ); entityBinding.getHierarchyDetails().getCaching().setCacheLazyProperties( true );
entityBinding.getHierarchyDetails().getCaching().setAccessType( entityBinding.getHierarchyDetails().getCaching().setAccessType( AccessType.fromExternalName( accessType ) );
AccessType.fromExternalName(
getCacheConcurrencyStrategy()
)
);
} }
} }
private void overrideCollectionCachesForEntity(EntityBinding entityBinding) { private static void overrideCollectionCachesForEntity(EntityBinding entityBinding, String accessType) {
for ( AttributeBinding attributeBinding : entityBinding.getAttributeBindingClosure() ) { for ( AttributeBinding attributeBinding : entityBinding.getAttributeBindingClosure() ) {
if ( !attributeBinding.getAttribute().isSingular() ) { if ( !attributeBinding.getAttribute().isSingular() ) {
AbstractPluralAttributeBinding binding = AbstractPluralAttributeBinding.class.cast( attributeBinding ); AbstractPluralAttributeBinding binding = AbstractPluralAttributeBinding.class.cast( attributeBinding );
@ -261,7 +262,7 @@ public abstract class BaseCoreFunctionalTestCase extends BaseUnitTestCase {
) )
); );
binding.getCaching().setCacheLazyProperties( true ); binding.getCaching().setCacheLazyProperties( true );
binding.getCaching().setAccessType( AccessType.fromExternalName( getCacheConcurrencyStrategy() ) ); binding.getCaching().setAccessType( AccessType.fromExternalName( accessType ) );
} }
} }
} }