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;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
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.jndi.JndiHelper;
import org.hibernate.service.spi.ServiceRegistryAwareService;
import org.hibernate.service.spi.ServiceRegistryImplementor;
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
@ -41,9 +39,7 @@ import org.infinispan.util.logging.LogFactory;
* @author Galder Zamarreño
* @since 3.5
*/
public class JndiInfinispanRegionFactory extends InfinispanRegionFactory {
private static final Log log = LogFactory.getLog( JndiInfinispanRegionFactory.class );
public class JndiInfinispanRegionFactory extends InfinispanRegionFactory implements ServiceRegistryAwareService {
/**
* 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";
private JndiService jndiService;
@Override
public void injectServices(ServiceRegistryImplementor serviceRegistry) {
this.jndiService = serviceRegistry.getService( JndiService.class );
}
/**
* Constructs a JndiInfinispanRegionFactory
*/
@ -75,34 +78,18 @@ public class JndiInfinispanRegionFactory extends InfinispanRegionFactory {
if ( name == null ) {
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 {
ctx = new InitialContext( jndiProperties );
return (EmbeddedCacheManager) ctx.lookup( jndiNamespace );
return (EmbeddedCacheManager) jndiService.locate( name );
}
catch (NamingException ne) {
final String msg = "Unable to retrieve CacheManager from JNDI [" + jndiNamespace + "]";
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 );
}
}
catch (JndiException e) {
throw new CacheException( "Unable to retrieve CacheManager from JNDI [" + name + "]", e );
}
}
@Override
public void stop() {
// 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;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
@ -31,28 +33,41 @@ import javax.naming.NameNotFoundException;
import javax.naming.Reference;
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.lifecycle.ComponentStatus;
import org.infinispan.manager.DefaultCacheManager;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.util.logging.Log;
import org.infinispan.util.logging.LogFactory;
import org.jboss.util.naming.NonSerializableFactory;
import org.jnp.server.Main;
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;
/**
@ -61,121 +76,40 @@ import static org.junit.Assert.assertEquals;
* @author Galder Zamarreño
* @since // TODO
*/
public class JndiRegionFactoryTestCase extends SingleNodeTestCase {
public class JndiRegionFactoryTestCase extends BaseUnitTestCase {
private static final Log log = LogFactory.getLog( JndiRegionFactoryTestCase.class );
private static final String JNDI_NAME = "java:CacheManager";
// Naming
private Main namingMain;
private SingletonNamingServer namingServer;
private Properties props;
private boolean bindToJndi = true;
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
protected Class<? extends RegionFactory> getCacheRegionFactory() {
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();
@Before
public void setUp() {
try {
Session s = sessionFactory.openSession();
s.getTransaction().begin();
s.persist( item );
s.getTransaction().commit();
s.close();
// Create an in-memory jndi
namingServer = new SingletonNamingServer();
namingMain = new Main();
namingMain.setInstallGlobalService( true );
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) {
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 {
// Ah ! This service isn't serializable, so we use a helper class
NonSerializableFactory.bind( jndiName, who );
@ -199,9 +133,98 @@ public class JndiRegionFactoryTestCase extends SingleNodeTestCase {
ctx.rebind( n.get( 0 ), ref );
}
private void unbind(String jndiName, Context ctx) throws Exception {
NonSerializableFactory.unbind( jndiName );
// ctx.unbind(jndiName);
@After
public void tearDown() {
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;
import static org.junit.Assert.fail;
import java.io.InputStream;
import java.sql.Blob;
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.AttributeBinding;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.type.Type;
import org.hibernate.testing.AfterClassOnce;
import org.hibernate.testing.BeforeClassOnce;
import org.hibernate.testing.OnExpectedFailure;
import org.hibernate.testing.OnFailure;
import org.hibernate.testing.SkipLog;
import org.hibernate.testing.cache.CachingRegionFactory;
import org.hibernate.type.Type;
import org.junit.After;
import org.junit.Before;
import static org.junit.Assert.fail;
/**
* Applies functional testing logic for core Hibernate testing on top of {@link BaseUnitTestCase}
*
@ -212,15 +213,19 @@ public abstract class BaseCoreFunctionalTestCase extends BaseUnitTestCase {
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 ) {
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;
for ( AttributeBinding attributeBinding : entityBinding.getAttributeBindingClosure() ) {
if ( attributeBinding.getAttribute().isSingular() ) {
@ -240,15 +245,11 @@ public abstract class BaseCoreFunctionalTestCase extends BaseUnitTestCase {
entityBinding.getHierarchyDetails().getCaching().setRequested( TruthValue.TRUE );
entityBinding.getHierarchyDetails().getCaching().setRegion( entityBinding.getEntityName() );
entityBinding.getHierarchyDetails().getCaching().setCacheLazyProperties( true );
entityBinding.getHierarchyDetails().getCaching().setAccessType(
AccessType.fromExternalName(
getCacheConcurrencyStrategy()
)
);
entityBinding.getHierarchyDetails().getCaching().setAccessType( AccessType.fromExternalName( accessType ) );
}
}
private void overrideCollectionCachesForEntity(EntityBinding entityBinding) {
private static void overrideCollectionCachesForEntity(EntityBinding entityBinding, String accessType) {
for ( AttributeBinding attributeBinding : entityBinding.getAttributeBindingClosure() ) {
if ( !attributeBinding.getAttribute().isSingular() ) {
AbstractPluralAttributeBinding binding = AbstractPluralAttributeBinding.class.cast( attributeBinding );
@ -261,7 +262,7 @@ public abstract class BaseCoreFunctionalTestCase extends BaseUnitTestCase {
)
);
binding.getCaching().setCacheLazyProperties( true );
binding.getCaching().setAccessType( AccessType.fromExternalName( getCacheConcurrencyStrategy() ) );
binding.getCaching().setAccessType( AccessType.fromExternalName( accessType ) );
}
}
}