Author: galder.zamarreno(a)jboss.com
Date: 2010-02-22 11:37:22 -0500 (Mon, 22 Feb 2010)
New Revision: 18848
Added:
core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/JBossStandaloneJtaExampleTest.java
Modified:
core/trunk/cache-infinispan/pom.xml
Log:
[HHH-4640] (Add test with JNDI bound JBoss Transactions Transaction Manager) Done.
Modified: core/trunk/cache-infinispan/pom.xml
===================================================================
--- core/trunk/cache-infinispan/pom.xml 2010-02-21 17:36:27 UTC (rev 18847)
+++ core/trunk/cache-infinispan/pom.xml 2010-02-22 16:37:22 UTC (rev 18848)
@@ -22,6 +22,8 @@
<version.hsqldb>1.8.0.2</version.hsqldb>
<version.cglib>2.2</version.cglib>
<version.javassist>3.4.GA</version.javassist>
+ <version.org.jboss.naming>5.0.3.GA</version.org.jboss.naming>
+ <version.xapool>1.5.0</version.xapool>
<skipUnitTests>true</skipUnitTests>
<!--
Following is the default jgroups mcast address. If you find the testsuite runs
very slowly, there
@@ -77,6 +79,34 @@
<version>${version.javassist}</version>
<scope>test</scope>
</dependency>
+
+ <dependency>
+ <groupId>org.jboss.naming</groupId>
+ <artifactId>jnp-client</artifactId>
+ <scope>test</scope>
+ <version>${version.org.jboss.naming}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.jboss.naming</groupId>
+ <artifactId>jnpserver</artifactId>
+ <scope>test</scope>
+ <version>${version.org.jboss.naming}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.experlog</groupId>
+ <artifactId>xapool</artifactId>
+ <scope>test</scope>
+ <version>${version.xapool}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>jboss.jbossts</groupId>
+ <artifactId>jbossjta</artifactId>
+ <version>4.9.0.GA</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
Added:
core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/JBossStandaloneJtaExampleTest.java
===================================================================
---
core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/JBossStandaloneJtaExampleTest.java
(rev 0)
+++
core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/JBossStandaloneJtaExampleTest.java 2010-02-22
16:37:22 UTC (rev 18848)
@@ -0,0 +1,269 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2010, Red Hat Middleware LLC 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 Middleware LLC.
+ *
+ * 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.tm;
+
+import junit.framework.TestCase;
+import org.enhydra.jdbc.standard.StandardXADataSource;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.mapping.Collection;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.stat.Statistics;
+import org.hibernate.test.cache.infinispan.functional.Item;
+import org.infinispan.transaction.lookup.JBossStandaloneJTAManagerLookup;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
+import org.jboss.util.naming.NonSerializableFactory;
+import org.jnp.interfaces.NamingContext;
+import org.jnp.server.Main;
+import org.jnp.server.NamingServer;
+
+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 javax.transaction.Status;
+import javax.transaction.TransactionManager;
+import javax.transaction.UserTransaction;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Iterator;
+import java.util.Properties;
+
+/**
+ * This is an example test based on
http://community.jboss.org/docs/DOC-14617 that shows
how to interact with
+ * Hibernate configured with Infinispan second level cache provider using JTA
transactions.
+ *
+ * In this test, an XADataSource wrapper is in use where we have associated our
transaction manager to it so that
+ * commits/rollbacks are propagated to the database as well.
+ *
+ * @author Galder Zamarreño
+ * @since 3.5
+ */
+public class JBossStandaloneJtaExampleTest extends TestCase {
+ private static final Log log =
LogFactory.getLog(JBossStandaloneJtaExampleTest.class);
+ private static final JBossStandaloneJTAManagerLookup lookup = new
JBossStandaloneJTAManagerLookup();
+ Context ctx;
+ Main jndiServer;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ jndiServer = startJndiServer();
+ ctx = createJndiContext();
+ bindTransactionManager();
+ bindUserTransaction();
+ bindDataSource();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ ctx.close();
+ jndiServer.stop();
+ }
+
+ public void testPersistAndLoadUnderJta() throws Exception {
+ Item item;
+ SessionFactory sessionFactory = buildSessionFactory();
+ UserTransaction ut = (UserTransaction) ctx.lookup("UserTransaction");
+ ut.begin();
+ try {
+ Session session = sessionFactory.openSession();
+ session.getTransaction().begin();
+ item = new Item("anItem", "An item owned by someone");
+ session.persist(item);
+ session.getTransaction().commit();
+ session.close();
+ } catch(Exception e) {
+ ut.setRollbackOnly();
+ throw e;
+ } finally {
+ if (ut.getStatus() == Status.STATUS_ACTIVE)
+ ut.commit();
+ else
+ ut.rollback();
+ }
+
+ ut = (UserTransaction) ctx.lookup("UserTransaction");
+ ut.begin();
+ try {
+ Session session = sessionFactory.openSession();
+ session.getTransaction().begin();
+ Item found = (Item) session.load(Item.class, item.getId());
+ Statistics stats = session.getSessionFactory().getStatistics();
+ log.info(stats.toString());
+ assertEquals(item.getDescription(), found.getDescription());
+ assertEquals(0, stats.getSecondLevelCacheMissCount());
+ assertEquals(1, stats.getSecondLevelCacheHitCount());
+ session.delete(found);
+ session.getTransaction().commit();
+ session.close();
+ } catch(Exception e) {
+ ut.setRollbackOnly();
+ throw e;
+ } finally {
+ if (ut.getStatus() == Status.STATUS_ACTIVE)
+ ut.commit();
+ else
+ ut.rollback();
+ }
+ }
+
+ public static class ExtendedXADataSource extends StandardXADataSource { // XAPOOL
+ @Override
+ public Connection getConnection() throws SQLException {
+
+ if (getTransactionManager() == null) { // although already set before, it
results null again after retrieving the datasource by jndi
+ TransactionManager tm; // this is because the TransactionManager information
is not serialized.
+ try {
+ tm = lookup.getTransactionManager();
+ } catch (Exception e) {
+ throw new SQLException(e);
+ }
+ setTransactionManager(tm); // resets the TransactionManager on the
datasource retrieved by jndi,
+ // this makes the datasource JTA-aware
+ }
+
+ // According to Enhydra documentation, here we must return the connection of our
XAConnection
+ // see
http://cvs.forge.objectweb.org/cgi-bin/viewcvs.cgi/xapool/xapool/examples...
+ return super.getXAConnection().getConnection();
+ }
+
+ @Override
+ public <T> T unwrap(Class<T> iface) throws SQLException {
+ return null; // JDK6 stuff
+ }
+
+ @Override
+ public boolean isWrapperFor(Class<?> iface) throws SQLException {
+ return false; // JDK6 stuff
+ }
+ }
+
+ private Main startJndiServer() throws Exception {
+ // Create an in-memory jndi
+ NamingServer namingServer = new NamingServer();
+ NamingContext.setLocal(namingServer);
+ Main namingMain = new Main();
+ namingMain.setInstallGlobalService(true);
+ namingMain.setPort(-1);
+ namingMain.start();
+ return namingMain;
+ }
+
+ private Context createJndiContext() throws Exception {
+ Properties props = new Properties();
+ props.put(Context.INITIAL_CONTEXT_FACTORY,
"org.jnp.interfaces.NamingContextFactory");
+ props.put("java.naming.factory.url.pkgs",
"org.jboss.naming:org.jnp.interfaces");
+ return new InitialContext(props);
+ }
+
+ private void bindTransactionManager() throws Exception {
+ // as JBossTransactionManagerLookup extends JNDITransactionManagerLookup we must
also register the TransactionManager
+ bind("java:/TransactionManager", lookup.getTransactionManager(),
lookup.getTransactionManager().getClass(), ctx);
+ }
+
+ private void bindUserTransaction() throws Exception {
+ // also the UserTransaction must be registered on jndi:
org.hibernate.transaction.JTATransactionFactory#getUserTransaction() requires this
+ bind("UserTransaction", lookup.getUserTransaction(),
lookup.getUserTransaction().getClass(), ctx);
+ }
+
+ private void bindDataSource() throws Exception {
+ ExtendedXADataSource xads = new ExtendedXADataSource();
+ xads.setDriverName("org.hsqldb.jdbcDriver");
+ xads.setUrl("jdbc:hsqldb:mem:/example");
+ ctx.bind("java:/MyDatasource", xads);
+ }
+
+ /**
+ * 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) {
+ System.out.println("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);
+ }
+
+ private SessionFactory buildSessionFactory() {
+ Configuration cfg = new Configuration();
+ cfg.setProperty(Environment.DIALECT,
"org.hibernate.dialect.HSQLDialect");
+ cfg.setProperty(Environment.HBM2DDL_AUTO, "create-drop");
+ cfg.setProperty(Environment.DATASOURCE, "java:/MyDatasource");
+ cfg.setProperty(Environment.JNDI_CLASS,
"org.jnp.interfaces.NamingContextFactory");
+ cfg.setProperty(Environment.TRANSACTION_MANAGER_STRATEGY,
"org.hibernate.transaction.JBossTransactionManagerLookup");
+ cfg.setProperty(Environment.TRANSACTION_STRATEGY,
"org.hibernate.transaction.JTATransactionFactory");
+ cfg.setProperty(Environment.CURRENT_SESSION_CONTEXT_CLASS, "jta");
+ cfg.setProperty(Environment.RELEASE_CONNECTIONS, "auto");
+ cfg.setProperty(Environment.USE_SECOND_LEVEL_CACHE, "true");
+ cfg.setProperty(Environment.USE_QUERY_CACHE, "true");
+ cfg.setProperty(Environment.CACHE_REGION_FACTORY,
"org.hibernate.cache.infinispan.InfinispanRegionFactory");
+ String[] mappings = new
String[]{"org/hibernate/test/cache/infinispan/functional/Item.hbm.xml"};
+ for (String mapping : mappings) {
+ cfg.addResource(mapping, Thread.currentThread().getContextClassLoader());
+ }
+ Iterator iter = cfg.getClassMappings();
+ while (iter.hasNext()) {
+ PersistentClass clazz = (PersistentClass) iter.next();
+ cfg.setCacheConcurrencyStrategy(clazz.getEntityName(),
"transactional");
+ }
+ iter = cfg.getCollectionMappings();
+ while (iter.hasNext()) {
+ Collection coll = (Collection) iter.next();
+ cfg.setCollectionCacheConcurrencyStrategy(coll.getRole(),
"transactional");
+ }
+ return cfg.buildSessionFactory();
+ }
+}