This is an automated email from the ASF dual-hosted git repository. jgallimore pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/tomee.git
commit e3c3fc95dfa6aefc956eb4308596958c80a92877 Author: Jonathan Gallimore <[email protected]> AuthorDate: Fri Jun 14 15:10:47 2019 +0100 Reinstating example --- examples/xa-datasource/README.md | 217 +++++++++++++++++++++ examples/xa-datasource/pom.xml | 113 +++++++++++ .../java/org/superbiz/injection/jpa/Movie.java | 76 ++++++++ .../java/org/superbiz/injection/jpa/Movies.java | 54 +++++ .../org/superbiz/injection/jpa/MoviesDirect.java | 47 +++++ .../java/org/superbiz/injection/jpa/MoviesXA.java | 189 ++++++++++++++++++ .../src/main/resources/META-INF/persistence.xml | 32 +++ .../org/superbiz/injection/jpa/MoviesTest.java | 98 ++++++++++ .../org/superbiz/injection/jpa/MoviesXATest.java | 169 ++++++++++++++++ 9 files changed, 995 insertions(+) diff --git a/examples/xa-datasource/README.md b/examples/xa-datasource/README.md new file mode 100644 index 0000000..5128f0c --- /dev/null +++ b/examples/xa-datasource/README.md @@ -0,0 +1,217 @@ +Title: Injection Of Entitymanager + +This example shows use of `@PersistenceContext` to have an `EntityManager` with an +`EXTENDED` persistence context injected into a `@Stateful bean`. A JPA +`@Entity` bean is used with the `EntityManager` to create, persist and merge +data to a database. + +## Creating the JPA Entity + +The entity itself is simply a pojo annotated with `@Entity`. We create one called `Movie` which we can use to hold movie records. + + package org.superbiz.injection.jpa; + + import javax.persistence.Entity; + + @Entity + public class Movie { + + @Id @GeneratedValue + private long id; + + private String director; + private String title; + private int year; + + public Movie() { + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public Movie(String director, String title, int year) { + this.director = director; + this.title = title; + this.year = year; + } + + public String getDirector() { + return director; + } + + public void setDirector(String director) { + this.director = director; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public int getYear() { + return year; + } + + public void setYear(int year) { + this.year = year; + } + } + +## Configure the EntityManager via a persistence.xml file + +The above `Movie` entity can be created, removed, updated or deleted via an `EntityManager` object. The `EntityManager` itself is +configured via a `META-INF/persistence.xml` file that is placed in the same jar as the `Movie` entity. + + <persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0"> + + <persistence-unit name="movie-unit"> + <jta-data-source>movieDatabase</jta-data-source> + <non-jta-data-source>movieDatabaseUnmanaged</non-jta-data-source> + <class>org.superbiz.injection.jpa.Movie</class> + + <properties> + <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/> + </properties> + </persistence-unit> + </persistence> + +Notice that the `Movie` entity is listed via a `<class>` element. This is not required, but can help when testing or when the +`Movie` class is located in a different jar than the jar containing the `persistence.xml` file. + +## Injection via @PersistenceContext + +The `EntityManager` itself is created by the container using the information in the `persistence.xml`, so to use it at +runtime, we simply need to request it be injected into one of our components. We do this via `@PersistenceContext` + +The `@PersistenceContext` annotation can be used on any CDI bean, EJB, Servlet, Servlet Listener, Servlet Filter, or JSF ManagedBean. If you don't use an EJB you will need to use a `UserTransaction` begin and commit transactions manually. A transaction is required for any of the create, update or delete methods of the EntityManager to work. + + package org.superbiz.injection.jpa; + + import javax.ejb.Stateful; + import javax.persistence.EntityManager; + import javax.persistence.PersistenceContext; + import javax.persistence.PersistenceContextType; + import javax.persistence.Query; + import java.util.List; + + @Stateful + public class Movies { + + @PersistenceContext(unitName = "movie-unit", type = PersistenceContextType.EXTENDED) + private EntityManager entityManager; + + public void addMovie(Movie movie) throws Exception { + entityManager.persist(movie); + } + + public void deleteMovie(Movie movie) throws Exception { + entityManager.remove(movie); + } + + public List<Movie> getMovies() throws Exception { + Query query = entityManager.createQuery("SELECT m from Movie as m"); + return query.getResultList(); + } + } + +This particular `EntityManager` is injected as an `EXTENDED` persistence context, which simply means that the `EntityManager` +is created when the `@Stateful` bean is created and destroyed when the `@Stateful` bean is destroyed. Simply put, the +data in the `EntityManager` is cached for the lifetime of the `@Stateful` bean. + +The use of `EXTENDED` persistence contexts is **only** available to `@Stateful` beans. See the [JPA Concepts](../../jpa-concepts.html) page for an high level explanation of what a "persistence context" really is and how it is significant to JPA. + +## MoviesTest + +Testing JPA is quite easy, we can simply use the `EJBContainer` API to create a container in our test case. + + package org.superbiz.injection.jpa; + + import junit.framework.TestCase; + + import javax.ejb.embeddable.EJBContainer; + import javax.naming.Context; + import java.util.List; + import java.util.Properties; + + //START SNIPPET: code + public class MoviesTest extends TestCase { + + public void test() throws Exception { + + final Properties p = new Properties(); + p.put("movieDatabase", "new://Resource?type=DataSource"); + p.put("movieDatabase.JdbcDriver", "org.hsqldb.jdbcDriver"); + p.put("movieDatabase.JdbcUrl", "jdbc:hsqldb:mem:moviedb"); + + final Context context = EJBContainer.createEJBContainer(p).getContext(); + + Movies movies = (Movies) context.lookup("java:global/injection-of-entitymanager/Movies"); + + movies.addMovie(new Movie("Quentin Tarantino", "Reservoir Dogs", 1992)); + movies.addMovie(new Movie("Joel Coen", "Fargo", 1996)); + movies.addMovie(new Movie("Joel Coen", "The Big Lebowski", 1998)); + + List<Movie> list = movies.getMovies(); + assertEquals("List.size()", 3, list.size()); + + for (Movie movie : list) { + movies.deleteMovie(movie); + } + + assertEquals("Movies.getMovies()", 0, movies.getMovies().size()); + } + } + +# Running + +When we run our test case we should see output similar to the following. + + ------------------------------------------------------- + T E S T S + ------------------------------------------------------- + Running org.superbiz.injection.jpa.MoviesTest + Apache OpenEJB 4.0.0-beta-1 build: 20111002-04:06 + http://tomee.apache.org/ + INFO - openejb.home = /Users/dblevins/examples/injection-of-entitymanager + INFO - openejb.base = /Users/dblevins/examples/injection-of-entitymanager + INFO - Using 'javax.ejb.embeddable.EJBContainer=true' + INFO - Configuring Service(id=Default Security Service, type=SecurityService, provider-id=Default Security Service) + INFO - Configuring Service(id=Default Transaction Manager, type=TransactionManager, provider-id=Default Transaction Manager) + INFO - Configuring Service(id=movieDatabase, type=Resource, provider-id=Default JDBC Database) + INFO - Found EjbModule in classpath: /Users/dblevins/examples/injection-of-entitymanager/target/classes + INFO - Beginning load: /Users/dblevins/examples/injection-of-entitymanager/target/classes + INFO - Configuring enterprise application: /Users/dblevins/examples/injection-of-entitymanager + INFO - Configuring Service(id=Default Stateful Container, type=Container, provider-id=Default Stateful Container) + INFO - Auto-creating a container for bean Movies: Container(type=STATEFUL, id=Default Stateful Container) + INFO - Configuring Service(id=Default Managed Container, type=Container, provider-id=Default Managed Container) + INFO - Auto-creating a container for bean org.superbiz.injection.jpa.MoviesTest: Container(type=MANAGED, id=Default Managed Container) + INFO - Configuring PersistenceUnit(name=movie-unit) + INFO - Auto-creating a Resource with id 'movieDatabaseNonJta' of type 'DataSource for 'movie-unit'. + INFO - Configuring Service(id=movieDatabaseNonJta, type=Resource, provider-id=movieDatabase) + INFO - Adjusting PersistenceUnit movie-unit <non-jta-data-source> to Resource ID 'movieDatabaseNonJta' from 'movieDatabaseUnmanaged' + INFO - Enterprise application "/Users/dblevins/examples/injection-of-entitymanager" loaded. + INFO - Assembling app: /Users/dblevins/examples/injection-of-entitymanager + INFO - PersistenceUnit(name=movie-unit, provider=org.apache.openjpa.persistence.PersistenceProviderImpl) - provider time 462ms + INFO - Jndi(name="java:global/injection-of-entitymanager/Movies!org.superbiz.injection.jpa.Movies") + INFO - Jndi(name="java:global/injection-of-entitymanager/Movies") + INFO - Jndi(name="java:global/EjbModule1461341140/org.superbiz.injection.jpa.MoviesTest!org.superbiz.injection.jpa.MoviesTest") + INFO - Jndi(name="java:global/EjbModule1461341140/org.superbiz.injection.jpa.MoviesTest") + INFO - Created Ejb(deployment-id=Movies, ejb-name=Movies, container=Default Stateful Container) + INFO - Created Ejb(deployment-id=org.superbiz.injection.jpa.MoviesTest, ejb-name=org.superbiz.injection.jpa.MoviesTest, container=Default Managed Container) + INFO - Started Ejb(deployment-id=Movies, ejb-name=Movies, container=Default Stateful Container) + INFO - Started Ejb(deployment-id=org.superbiz.injection.jpa.MoviesTest, ejb-name=org.superbiz.injection.jpa.MoviesTest, container=Default Managed Container) + INFO - Deployed Application(path=/Users/dblevins/examples/injection-of-entitymanager) + Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.301 sec + + Results : + + Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 + diff --git a/examples/xa-datasource/pom.xml b/examples/xa-datasource/pom.xml new file mode 100644 index 0000000..efe0e54 --- /dev/null +++ b/examples/xa-datasource/pom.xml @@ -0,0 +1,113 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- $Rev$ $Date$ --> + +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>org.superbiz</groupId> + <artifactId>xa-datasource</artifactId> + <packaging>jar</packaging> + <version>8.0.0-SNAPSHOT</version> + <name>OpenEJB :: Examples :: XA Datasource configuration and usage</name> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <derby.version>10.12.1.1</derby.version> + </properties> + <build> + <defaultGoal>install</defaultGoal> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.5.1</version> + <configuration> + <source>1.8</source> + <target>1.8</target> + </configuration> + </plugin> + </plugins> + </build> + <repositories> + <repository> + <id>apache-m2-snapshot</id> + <name>Apache Snapshot Repository</name> + <url>https://repository.apache.org/content/groups/snapshots</url> + </repository> + </repositories> + <dependencies> + <dependency> + <groupId>org.apache.tomee</groupId> + <artifactId>javaee-api</artifactId> + <version>8.0</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.12</version> + <scope>test</scope> + </dependency> + <!-- + The <scope>test</scope> guarantees that non of your runtime + code is dependent on any OpenEJB classes. + --> + <dependency> + <groupId>org.apache.tomee</groupId> + <artifactId>openejb-core</artifactId> + <version>8.0.0-SNAPSHOT</version> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.apache.derby</groupId> + <artifactId>derby</artifactId> + <version>${derby.version}</version> + </dependency> + + <dependency> + <groupId>org.apache.derby</groupId> + <artifactId>derbynet</artifactId> + <version>${derby.version}</version> + </dependency> + + <dependency> + <groupId>org.apache.derby</groupId> + <artifactId>derbyclient</artifactId> + <version>${derby.version}</version> + </dependency> + + </dependencies> + <!-- + This section allows you to configure where to publish libraries for sharing. + It is not required and may be deleted. For more information see: + http://maven.apache.org/plugins/maven-deploy-plugin/ + --> + <distributionManagement> + <repository> + <id>localhost</id> + <url>file://${basedir}/target/repo/</url> + </repository> + <snapshotRepository> + <id>localhost</id> + <url>file://${basedir}/target/snapshot-repo/</url> + </snapshotRepository> + </distributionManagement> +</project> diff --git a/examples/xa-datasource/src/main/java/org/superbiz/injection/jpa/Movie.java b/examples/xa-datasource/src/main/java/org/superbiz/injection/jpa/Movie.java new file mode 100644 index 0000000..1bc65eb --- /dev/null +++ b/examples/xa-datasource/src/main/java/org/superbiz/injection/jpa/Movie.java @@ -0,0 +1,76 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.superbiz.injection.jpa; +//START SNIPPET: code + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity +public class Movie { + + @Id + @GeneratedValue + private long id; + + private String director; + private String title; + private int year; + + public Movie() { + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public Movie(String director, String title, int year) { + this.director = director; + this.title = title; + this.year = year; + } + + public String getDirector() { + return director; + } + + public void setDirector(String director) { + this.director = director; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public int getYear() { + return year; + } + + public void setYear(int year) { + this.year = year; + } +} +//END SNIPPET: code 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 new file mode 100644 index 0000000..4e136aa --- /dev/null +++ b/examples/xa-datasource/src/main/java/org/superbiz/injection/jpa/Movies.java @@ -0,0 +1,54 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.superbiz.injection.jpa; + +//START SNIPPET: code + +import javax.ejb.Singleton; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.persistence.PersistenceContextType; +import javax.persistence.Query; +import java.util.List; + +@Singleton +public class Movies { + + @PersistenceContext(unitName = "movie-unit", type = PersistenceContextType.TRANSACTION) + private EntityManager entityManager; + + public void addMovie(Movie movie) throws Exception { + entityManager.persist(movie); + } + + public void deleteMovie(Movie movie) throws Exception { + final Movie storedMovie = entityManager.find(Movie.class, movie.getId()); + entityManager.remove(storedMovie); + } + + public List<Movie> getMovies() throws Exception { + Query query = entityManager.createQuery("SELECT m from Movie as m"); + return query.getResultList(); + } + + public void deleteAll() throws Exception { + Query query = entityManager.createQuery("DELETE from Movie"); + query.executeUpdate(); + } + +} +//END SNIPPET: code diff --git a/examples/xa-datasource/src/main/java/org/superbiz/injection/jpa/MoviesDirect.java b/examples/xa-datasource/src/main/java/org/superbiz/injection/jpa/MoviesDirect.java new file mode 100644 index 0000000..22646b0 --- /dev/null +++ b/examples/xa-datasource/src/main/java/org/superbiz/injection/jpa/MoviesDirect.java @@ -0,0 +1,47 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.superbiz.injection.jpa; + +import javax.annotation.Resource; +import javax.ejb.Singleton; +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; + +@Singleton +public class MoviesDirect { + + @Resource(name="moviesDatabaseUnmanaged") + private DataSource ds; + + public int count() { + try (final Connection connection = ds.getConnection()) { + try (final PreparedStatement ps = connection.prepareStatement("select count(1) from movie")) { + try (final ResultSet rs = ps.executeQuery()) { + if (rs != null && rs.next()) { + return rs.getInt(1); + } else { + return 0; + } + } + } + } catch (final Exception e) { + throw new RuntimeException("Unable to execute query against the database"); + } + } +} 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..05a384d --- /dev/null +++ b/examples/xa-datasource/src/main/java/org/superbiz/injection/jpa/MoviesXA.java @@ -0,0 +1,189 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +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; + } +} diff --git a/examples/xa-datasource/src/main/resources/META-INF/persistence.xml b/examples/xa-datasource/src/main/resources/META-INF/persistence.xml new file mode 100644 index 0000000..798f6a9 --- /dev/null +++ b/examples/xa-datasource/src/main/resources/META-INF/persistence.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<!-- START SNIPPET: code --> +<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0"> + + <persistence-unit name="movie-unit"> + <jta-data-source>movieDatabase</jta-data-source> + <non-jta-data-source>movieDatabaseUnmanaged</non-jta-data-source> + <class>org.superbiz.injection.jpa.Movie</class> + + <properties> + <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/> + </properties> + </persistence-unit> +</persistence> + <!-- END SNIPPET: code --> diff --git a/examples/xa-datasource/src/test/java/org/superbiz/injection/jpa/MoviesTest.java b/examples/xa-datasource/src/test/java/org/superbiz/injection/jpa/MoviesTest.java new file mode 100644 index 0000000..48771ce --- /dev/null +++ b/examples/xa-datasource/src/test/java/org/superbiz/injection/jpa/MoviesTest.java @@ -0,0 +1,98 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.superbiz.injection.jpa; + +import junit.framework.TestCase; + +import javax.ejb.embeddable.EJBContainer; +import javax.naming.Context; +import java.util.List; +import java.util.Properties; + +//START SNIPPET: code +public class MoviesTest extends TestCase { + + public void test() throws Exception { + + 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", "test"); + p.put("movieDatabaseXA.CreateDatabase", "create"); + + p.put("movieDatabase", "new://Resource?type=DataSource"); + p.put("movieDatabase.DataSourceCreator", "dbcp"); + 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.DataSourceCreator", "dbcp"); + p.put("movieDatabaseUnmanaged.JdbcDriver", "org.apache.derby.jdbc.EmbeddedDriver"); + p.put("movieDatabaseUnmanaged.JdbcUrl", "jdbc:derby:test;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"); + + EJBContainer container = EJBContainer.createEJBContainer(p); + final Context context = container.getContext(); + + Movies movies = (Movies) context.lookup("java:global/xa-datasource/Movies"); + MoviesDirect moviesDirect = (MoviesDirect) context.lookup("java:global/xa-datasource/MoviesDirect"); + + movies.addMovie(new Movie("Quentin Tarantino", "Reservoir Dogs", 1992)); + movies.addMovie(new Movie("Joel Coen", "Fargo", 1996)); + movies.addMovie(new Movie("Joel Coen", "The Big Lebowski", 1998)); + + List<Movie> list = movies.getMovies(); + assertEquals("List.size()", 3, list.size()); + assertEquals(3, moviesDirect.count()); + + + for (Movie movie : list) { + movies.deleteMovie(movie); + } + + assertEquals("Movies.getMovies()", 0, movies.getMovies().size()); + assertEquals(0, moviesDirect.count()); + + container.close(); + } +} +//END SNIPPET: code 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..56ee0c6 --- /dev/null +++ b/examples/xa-datasource/src/test/java/org/superbiz/injection/jpa/MoviesXATest.java @@ -0,0 +1,169 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +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(foreignKeys=true,schemaAction='dropDB,add')"); + 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.InitialSize", "2"); + 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.InitialSize", "2"); + 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"); + + 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()); + } +}
