/*
* 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.test.cache.infinispan.functional;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.Name;
import javax.naming.NameNotFoundException;
import javax.naming.Reference;
import javax.naming.StringRefAddr;
import java.util.Properties;
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.hibernate.Session;
import org.hibernate.cache.spi.RegionFactory;
import org.hibernate.cache.infinispan.InfinispanRegionFactory;
import org.hibernate.cache.infinispan.JndiInfinispanRegionFactory;
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 org.junit.Test;
import static org.junit.Assert.assertEquals;
/**
* // TODO: Document this
*
* @author Galder ZamarreƱo
* @since // TODO
*/
public class JndiRegionFactoryTestCase extends SingleNodeTestCase {
private static final Log log = LogFactory.getLog( JndiRegionFactoryTestCase.class );
private static final String JNDI_NAME = "java:CacheManager";
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();
try {
Session s = sessionFactory.openSession();
s.getTransaction().begin();
s.persist( item );
s.getTransaction().commit();
s.close();
}
catch (Exception e) {
setRollbackOnlyTx( 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 );
Name n = ctx.getNameParser( "" ).parse( jndiName );
while ( n.size() > 1 ) {
String ctxName = n.get( 0 );
try {
ctx = (Context) ctx.lookup( ctxName );
}
catch (NameNotFoundException e) {
log.debug( "creating Subcontext " + ctxName );
ctx = ctx.createSubcontext( ctxName );
}
n = n.getSuffix( 1 );
}
// The helper class NonSerializableFactory uses address type nns, we go on to
// use the helper class to bind the service object in JNDI
StringRefAddr addr = new StringRefAddr( "nns", jndiName );
Reference ref = new Reference( classType.getName(), addr, NonSerializableFactory.class.getName(), null );
ctx.rebind( n.get( 0 ), ref );
}
private void unbind(String jndiName, Context ctx) throws Exception {
NonSerializableFactory.unbind( jndiName );
// ctx.unbind(jndiName);
}
}