Adding XA test
Project: http://git-wip-us.apache.org/repos/asf/tomee/repo Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/bbc61e0b Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/bbc61e0b Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/bbc61e0b Branch: refs/heads/tomee-1.7.x Commit: bbc61e0b4e1427067377cf4b555dc4a39f220d7f Parents: 6345d7a Author: Jonathan Gallimore <j...@jrg.me.uk> Authored: Tue Jul 26 18:52:11 2016 +0200 Committer: Jonathan Gallimore <j...@jrg.me.uk> Committed: Tue Jul 26 18:56:09 2016 +0200 ---------------------------------------------------------------------- .../java/org/superbiz/injection/jpa/Movies.java | 5 + .../org/superbiz/injection/jpa/MoviesXA.java | 172 +++++++++++++ .../superbiz/injection/jpa/MoviesXATest.java | 242 +++++++++++++++++++ 3 files changed, 419 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tomee/blob/bbc61e0b/examples/xa-datasource/src/main/java/org/superbiz/injection/jpa/Movies.java ---------------------------------------------------------------------- diff --git a/examples/xa-datasource/src/main/java/org/superbiz/injection/jpa/Movies.java b/examples/xa-datasource/src/main/java/org/superbiz/injection/jpa/Movies.java index a03baa0..4e136aa 100644 --- a/examples/xa-datasource/src/main/java/org/superbiz/injection/jpa/Movies.java +++ b/examples/xa-datasource/src/main/java/org/superbiz/injection/jpa/Movies.java @@ -45,5 +45,10 @@ public class Movies { return query.getResultList(); } + public void deleteAll() throws Exception { + Query query = entityManager.createQuery("DELETE from Movie"); + query.executeUpdate(); + } + } //END SNIPPET: code http://git-wip-us.apache.org/repos/asf/tomee/blob/bbc61e0b/examples/xa-datasource/src/main/java/org/superbiz/injection/jpa/MoviesXA.java ---------------------------------------------------------------------- diff --git a/examples/xa-datasource/src/main/java/org/superbiz/injection/jpa/MoviesXA.java b/examples/xa-datasource/src/main/java/org/superbiz/injection/jpa/MoviesXA.java new file mode 100644 index 0000000..d506285 --- /dev/null +++ b/examples/xa-datasource/src/main/java/org/superbiz/injection/jpa/MoviesXA.java @@ -0,0 +1,172 @@ +package org.superbiz.injection.jpa; + +import javax.annotation.Resource; +import javax.ejb.Singleton; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.transaction.RollbackException; +import javax.transaction.SystemException; +import javax.transaction.TransactionManager; +import javax.transaction.xa.XAException; +import javax.transaction.xa.XAResource; +import javax.transaction.xa.Xid; + +@Singleton +public class MoviesXA { + private static int XA_STATE_INITIAL = 0; + private static int XA_STATE_STARTED = 1; + private static int XA_STATE_ENDED = 2; + private static int XA_STATE_PREPARED = 3; + private static int XA_STATE_DISPOSED = 4; + + @PersistenceContext + private EntityManager em; + + @Resource + private TransactionManager transactionManager; + + private volatile boolean fail = false; + private volatile boolean before = false; + + public void run(Movie movie) { + if (before) { + addXaResource(); + } + + em.persist(movie); + + if (!before) { + addXaResource(); + } + } + + private void addXaResource() { + try { + transactionManager.getTransaction().enlistResource(new XAResource() { + private int state = XA_STATE_INITIAL; + private Xid xid = null; + + private void validateXid(final Xid xid) throws XAException { + if (xid == null) { + throw new XAException("Null Xid"); + } + if (this.xid == null) { + throw new XAException("There is no live transaction for this XAResource"); + } + if (!xid.equals(this.xid)) { + throw new XAException("Given Xid is not that associated with this XAResource object"); + } + } + + @Override public void commit(final Xid xid, final boolean onePhase) throws XAException { + if (onePhase && state == XA_STATE_PREPARED) { + throw new XAException("Transaction is in a 2-phase state when 1-phase is requested"); + } + + if ((!onePhase) && state != XA_STATE_PREPARED) { + throw new XAException("Attempt to do a 2-phase commit when " + "transaction is not prepared"); + } + + dispose(); + } + + private void dispose() throws XAException { + state = XA_STATE_DISPOSED; + xid = null; + } + + @Override public void end(final Xid xid, final int flags) throws XAException { + + validateXid(xid); + + if (state != XA_STATE_STARTED) { + throw new XAException("Invalid XAResource state"); + } + + state = XA_STATE_ENDED; + } + + @Override public void forget(Xid xid) throws XAException { + validateXid(xid); + + if (state != XA_STATE_PREPARED) { + throw new XAException("Attempted to forget a XAResource that " + "is not in a heuristically completed state"); + } + + dispose(); + + state = XA_STATE_INITIAL; + } + + @Override public int getTransactionTimeout() throws XAException { + throw new XAException("Transaction timeouts not implemented yet"); + } + + @Override public boolean isSameRM(final XAResource xares) throws XAException { + return xares == this; + } + + @Override public int prepare(final Xid xid) throws XAException { + if (state != XA_STATE_ENDED) { + throw new XAException("Invalid XAResource state"); + } + + state = XA_STATE_PREPARED; + + if (fail) { + throw new XAException("oops"); + } + + return XA_OK; + } + + @Override public Xid[] recover(final int flag) throws XAException { + return new Xid[0]; + } + + @Override public void rollback(Xid xid) throws XAException { + if (state != XA_STATE_PREPARED && state != XA_STATE_ENDED) { + throw new XAException("Invalid XAResource state"); + } + dispose(); + } + + @Override public boolean setTransactionTimeout(final int seconds) throws XAException { + return false; + } + + @Override public void start(final Xid xid, final int flags) throws XAException { + if (state != XA_STATE_INITIAL && state != XA_STATE_DISPOSED) { + throw new XAException("Invalid XAResource state"); + } + + if (xid == null) { + throw new XAException("Null Xid"); + } + + this.xid = xid; + state = XA_STATE_STARTED; + } + }); + } catch (final RollbackException | SystemException e) { + throw new IllegalStateException(e); + } + } + + public Movie find() { + return em.createQuery("select e from Movie e", Movie.class).getResultList().iterator().next(); + } + + public void fail() { + fail = true; + } + + public void reset() { + fail = false; + before = false; + } + + public void before() { + before = true; + } +} http://git-wip-us.apache.org/repos/asf/tomee/blob/bbc61e0b/examples/xa-datasource/src/test/java/org/superbiz/injection/jpa/MoviesXATest.java ---------------------------------------------------------------------- diff --git a/examples/xa-datasource/src/test/java/org/superbiz/injection/jpa/MoviesXATest.java b/examples/xa-datasource/src/test/java/org/superbiz/injection/jpa/MoviesXATest.java new file mode 100644 index 0000000..f396c82 --- /dev/null +++ b/examples/xa-datasource/src/test/java/org/superbiz/injection/jpa/MoviesXATest.java @@ -0,0 +1,242 @@ +package org.superbiz.injection.jpa; + +import org.apache.openejb.jee.EjbJar; +import org.apache.openejb.jee.jpa.unit.PersistenceUnit; +import org.apache.openejb.junit.ApplicationComposer; +import org.apache.openejb.loader.Files; +import org.apache.openejb.testing.Classes; +import org.apache.openejb.testing.Configuration; +import org.apache.openejb.testing.Module; +import org.junit.Test; +import org.junit.runner.RunWith; + +import javax.ejb.EJB; +import javax.ejb.EJBException; +import java.io.File; +import java.util.Properties; + +import static java.lang.Math.abs; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +@RunWith(ApplicationComposer.class) +public class MoviesXATest { + @Module + @Classes(value = { MoviesXA.class, Movies.class, MoviesDirect.class }) + public EjbJar app() { + return new EjbJar(); + } + + @Module + public PersistenceUnit jpa() { + final PersistenceUnit unit = new PersistenceUnit("movie-unit"); + unit.setJtaDataSource("movieDatabase"); + unit.setNonJtaDataSource("movieDatabaseUnmanaged"); + unit.setProperty("openjpa.jdbc.SynchronizeMappings", "buildSchema"); + unit.addClass(Movie.class); + return unit; + } + + @Configuration + public Properties config() { + final String db = "target/test + " + abs(System.nanoTime()); + Files.deleteOnExit(new File(db)); + + final Properties p = new Properties(); + + p.put("movieDatabaseXA", "new://Resource?type=javax.sql.XADataSource&class-name=org.apache.derby.jdbc.EmbeddedXADataSource"); + p.put("movieDatabaseXA.DatabaseName", db); + p.put("movieDatabaseXA.CreateDatabase", "create"); + + p.put("movieDatabase", "new://Resource?type=DataSource"); + p.put("movieDatabase.XaDataSource", "movieDatabaseXA"); + p.put("movieDatabase.JtaManaged", "true"); + p.put("movieDatabase.UserName", "admin"); + p.put("movieDatabase.Password", "admin"); + p.put("movieDatabase.MaxActive", "128"); + p.put("movieDatabase.MaxIdle", "25"); + p.put("movieDatabase.MinIdle", "10"); + p.put("movieDatabase.AccessToUnderlyingConnectionAllowed", "true"); + p.put("movieDatabase.TestOnBorrow", "false"); + p.put("movieDatabase.TestWhileIdle", "true"); + p.put("movieDatabase.TimeBetweenEvictionRuns", "1 minute"); + p.put("movieDatabase.MaxWaitTime", "0 seconds"); + p.put("movieDatabase.PoolPreparedStatements", "true"); + p.put("movieDatabase.MaxOpenPreparedStatements", "1024"); + p.put("movieDatabase.ValidationQuery", "values 1"); + + p.put("movieDatabaseUnmanaged", "new://Resource?type=DataSource"); + p.put("movieDatabaseUnmanaged.LogSql", "true"); + p.put("movieDatabaseUnmanaged.JdbcDriver", "org.apache.derby.jdbc.EmbeddedDriver"); + p.put("movieDatabaseUnmanaged.JdbcUrl", "jdbc:derby:" + db + ";create=true"); + p.put("movieDatabaseUnmanaged.UserName", "admin"); + p.put("movieDatabaseUnmanaged.Password", "admin"); + p.put("movieDatabaseUnmanaged.JtaManaged", "false"); + p.put("movieDatabaseUnmanaged.MaxActive", "128"); + p.put("movieDatabaseUnmanaged.MaxIdle", "25"); + p.put("movieDatabaseUnmanaged.MinIdle", "10"); + p.put("movieDatabaseUnmanaged.AccessToUnderlyingConnectionAllowed", "true"); + p.put("movieDatabaseUnmanaged.TestOnBorrow", "false"); + p.put("movieDatabaseUnmanaged.TestWhileIdle", "true"); + p.put("movieDatabaseUnmanaged.TimeBetweenEvictionRuns", "1 minute"); + p.put("movieDatabaseUnmanaged.MaxWaitTime", "0 seconds"); + p.put("movieDatabaseUnmanaged.PoolPreparedStatements", "true"); + p.put("movieDatabaseUnmanaged.MaxOpenPreparedStatements", "1024"); + p.put("movieDatabaseUnmanaged.ValidationQuery", "values 1"); + + /* + + Configuration for MS SQL Server + + p.put("movieDatabaseXA", "new://Resource?type=javax.sql.XADataSource&class-name=com.microsoft.sqlserver.jdbc.SQLServerXADataSource"); + p.put("movieDatabaseXA.DatabaseName", "moviefun"); + p.put("movieDatabaseXA.URL", "jdbc:sqlserver://localhost:1433;databaseName=moviefun;SelectMethod=cursor;sendStringParametersAsUnicode=false"); + + p.put("movieDatabase", "new://Resource?type=DataSource"); + p.put("movieDatabase.XaDataSource", "movieDatabaseXA"); + p.put("movieDatabase.UserName", "sa"); + p.put("movieDatabase.Password", "XXX"); + p.put("movieDatabase.JtaManaged", "true"); + p.put("movieDatabase.MaxActive", "128"); + p.put("movieDatabase.MaxIdle", "25"); + p.put("movieDatabase.MinIdle", "10"); + p.put("movieDatabase.AccessToUnderlyingConnectionAllowed", "true"); + p.put("movieDatabase.TestOnBorrow", "false"); + p.put("movieDatabase.TestWhileIdle", "true"); + p.put("movieDatabase.TimeBetweenEvictionRuns", "1 minute"); + p.put("movieDatabase.MaxWaitTime", "0 seconds"); + p.put("movieDatabase.PoolPreparedStatements", "true"); + p.put("movieDatabase.MaxOpenPreparedStatements", "1024"); + p.put("movieDatabase.ValidationQuery", "select 1"); + + p.put("movieDatabaseUnmanaged", "new://Resource?type=DataSource"); + p.put("movieDatabaseUnmanaged.LogSql", "true"); + p.put("movieDatabaseUnmanaged.JdbcDriver", "com.microsoft.sqlserver.jdbc.SQLServerDriver"); + p.put("movieDatabaseUnmanaged.JdbcUrl", "jdbc:sqlserver://localhost:1433;databaseName=moviefun;SelectMethod=cursor;sendStringParametersAsUnicode=false"); + p.put("movieDatabaseUnmanaged.UserName", "sa"); + p.put("movieDatabaseUnmanaged.Password", "XXX"); + p.put("movieDatabaseUnmanaged.JtaManaged", "false"); + p.put("movieDatabaseUnmanaged.MaxActive", "128"); + p.put("movieDatabaseUnmanaged.MaxIdle", "25"); + p.put("movieDatabaseUnmanaged.MinIdle", "10"); + p.put("movieDatabaseUnmanaged.AccessToUnderlyingConnectionAllowed", "true"); + p.put("movieDatabaseUnmanaged.TestOnBorrow", "false"); + p.put("movieDatabaseUnmanaged.TestWhileIdle", "true"); + p.put("movieDatabaseUnmanaged.TimeBetweenEvictionRuns", "1 minute"); + p.put("movieDatabaseUnmanaged.MaxWaitTime", "0 seconds"); + p.put("movieDatabaseUnmanaged.PoolPreparedStatements", "true"); + p.put("movieDatabaseUnmanaged.MaxOpenPreparedStatements", "1024"); + p.put("movieDatabaseUnmanaged.ValidationQuery", "select 1"); + + p.put("movieDatabaseXA", "new://Resource?type=javax.sql.XADataSource&class-name=oracle.jdbc.xa.client.OracleXADataSource"); + p.put("movieDatabaseXA.url", "jdbc:oracle:thin:@//localhost:1521/orcl"); + + */ + + /* + + Configuration for Oracle + + p.put("movieDatabase", "new://Resource?type=DataSource"); + p.put("movieDatabase.XaDataSource", "movieDatabaseXA"); + p.put("movieDatabase.JtaManaged", "true"); + p.put("movieDatabase.UserName", "system"); + p.put("movieDatabase.Password", "oracle"); + p.put("movieDatabase.MaxActive", "128"); + p.put("movieDatabase.MaxIdle", "25"); + p.put("movieDatabase.MinIdle", "10"); + p.put("movieDatabase.AccessToUnderlyingConnectionAllowed", "true"); + p.put("movieDatabase.TestOnBorrow", "false"); + p.put("movieDatabase.TestWhileIdle", "true"); + p.put("movieDatabase.TimeBetweenEvictionRuns", "1 minute"); + p.put("movieDatabase.MaxWaitTime", "0 seconds"); + p.put("movieDatabase.PoolPreparedStatements", "true"); + p.put("movieDatabase.MaxOpenPreparedStatements", "1024"); + p.put("movieDatabase.ValidationQuery", "select 1 from dual"); + + p.put("movieDatabaseUnmanaged", "new://Resource?type=DataSource"); + p.put("movieDatabaseUnmanaged.LogSql", "true"); + p.put("movieDatabaseUnmanaged.JdbcDriver", "oracle.jdbc.driver.OracleDriver"); + p.put("movieDatabaseUnmanaged.JdbcUrl", "jdbc:oracle:thin:@//localhost:1521/orcl"); + p.put("movieDatabaseUnmanaged.UserName", "system"); + p.put("movieDatabaseUnmanaged.Password", "oracle"); + p.put("movieDatabaseUnmanaged.JtaManaged", "false"); + p.put("movieDatabaseUnmanaged.MaxActive", "128"); + p.put("movieDatabaseUnmanaged.MaxIdle", "25"); + p.put("movieDatabaseUnmanaged.MinIdle", "10"); + p.put("movieDatabaseUnmanaged.AccessToUnderlyingConnectionAllowed", "true"); + p.put("movieDatabaseUnmanaged.TestOnBorrow", "false"); + p.put("movieDatabaseUnmanaged.TestWhileIdle", "true"); + p.put("movieDatabaseUnmanaged.TimeBetweenEvictionRuns", "1 minute"); + p.put("movieDatabaseUnmanaged.MaxWaitTime", "0 seconds"); + p.put("movieDatabaseUnmanaged.PoolPreparedStatements", "true"); + p.put("movieDatabaseUnmanaged.MaxOpenPreparedStatements", "1024"); + p.put("movieDatabaseUnmanaged.ValidationQuery", "select 1 from dual"); + + */ + + System.out.println("Using db: " + db); + + return p; + } + + @EJB + private Movies movies; + + @EJB + private MoviesDirect moviesDirect; + + @EJB + private MoviesXA runner; + + @Test + public void run() throws Exception { + movies.deleteAll(); + + runner.reset(); + + final Movie movie = new Movie(); + movie.setTitle("Bad Boys"); + movie.setDirector("Michael Bay"); + movie.setYear(1995); + + runner.run(movie); + assertEquals(1, moviesDirect.count()); + + final Movie storedMovie = runner.find(); + assertNotNull(storedMovie); + } + + @Test + public void failBefore() { + runner.before(); + doFail(); + } + + @Test + public void failAfter() { + doFail(); + } + + private void doFail() { + runner.fail(); + try { + final Movie movie = new Movie(); + movie.setTitle("Bad Boys"); + movie.setDirector("Michael Bay"); + movie.setYear(1995); + + runner.run(movie); + } catch (final EJBException ee) { + System.out.flush(); + System.err.flush(); + System.out.println("Exception ->"); + ee.printStackTrace(); + System.out.println(); + System.out.flush(); + System.err.flush(); + } + + assertEquals(0, moviesDirect.count()); + } +}