/** * 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.txrollback; import junit.framework.TestCase; import javax.annotation.Resource; import javax.ejb.EJB; import javax.ejb.embeddable.EJBContainer; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.transaction.RollbackException; import javax.transaction.UserTransaction; import java.util.List; import java.util.Properties; //START SNIPPET: code public class MoviesTest extends TestCase { @EJB private Movies movies; @Resource private UserTransaction userTransaction; @PersistenceContext private EntityManager entityManager; private EJBContainer ejbContainer; public void setUp() throws Exception { 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" + System.currentTimeMillis()); ejbContainer = EJBContainer.createEJBContainer(p); ejbContainer.getContext().bind("inject", this); } @Override protected void tearDown() throws Exception { ejbContainer.close(); } /** * Standard successful transaction scenario. The data created inside * the transaction is visible after the transaction completes. * <p/> * Note that UserTransaction is only usable by Bean-Managed Transaction * beans, which can be specified with @TransactionManagement(BEAN) */ public void testCommit() throws Exception { userTransaction.begin(); try { entityManager.persist(new Movie("Quentin Tarantino", "Reservoir Dogs", 1992)); entityManager.persist(new Movie("Joel Coen", "Fargo", 1996)); entityManager.persist(new Movie("Joel Coen", "The Big Lebowski", 1998)); List<Movie> list = movies.getMovies(); assertEquals("List.size()", 3, list.size()); } finally { userTransaction.commit(); } // Transaction was committed List<Movie> list = movies.getMovies(); assertEquals("List.size()", 3, list.size()); } /** * Standard transaction rollback scenario. The data created inside * the transaction is not visible after the transaction completes. */ public void testUserTransactionRollback() throws Exception { userTransaction.begin(); try { entityManager.persist(new Movie("Quentin Tarantino", "Reservoir Dogs", 1992)); entityManager.persist(new Movie("Joel Coen", "Fargo", 1996)); entityManager.persist(new Movie("Joel Coen", "The Big Lebowski", 1998)); List<Movie> list = movies.getMovies(); assertEquals("List.size()", 3, list.size()); } finally { userTransaction.rollback(); } // Transaction was rolled back List<Movie> list = movies.getMovies(); assertEquals("List.size()", 0, list.size()); } /** * Transaction is marked for rollback inside the bean via * calling the javax.ejb.SessionContext.setRollbackOnly() method * <p/> * This is the cleanest way to make a transaction rollback. */ public void testMarkedRollback() throws Exception { userTransaction.begin(); try { entityManager.persist(new Movie("Quentin Tarantino", "Reservoir Dogs", 1992)); entityManager.persist(new Movie("Joel Coen", "Fargo", 1996)); entityManager.persist(new Movie("Joel Coen", "The Big Lebowski", 1998)); List<Movie> list = movies.getMovies(); assertEquals("List.size()", 3, list.size()); movies.callSetRollbackOnly(); } finally { try { userTransaction.commit(); fail("A RollbackException should have been thrown"); } catch (RollbackException e) { // Pass } } // Transaction was rolled back List<Movie> list = movies.getMovies(); assertEquals("List.size()", 0, list.size()); } /** * Throwing an unchecked exception from a bean will cause * the container to call setRollbackOnly() and discard the * bean instance from further use without calling any @PreDestroy * methods on the bean instance. */ public void testExceptionBasedRollback() throws Exception { userTransaction.begin(); try { entityManager.persist(new Movie("Quentin Tarantino", "Reservoir Dogs", 1992)); entityManager.persist(new Movie("Joel Coen", "Fargo", 1996)); entityManager.persist(new Movie("Joel Coen", "The Big Lebowski", 1998)); List<Movie> list = movies.getMovies(); assertEquals("List.size()", 3, list.size()); try { movies.throwUncheckedException(); } catch (RuntimeException e) { // Good, this will cause the tx to rollback } } finally { try { userTransaction.commit(); fail("A RollbackException should have been thrown"); } catch (RollbackException e) { // Pass } } // Transaction was rolled back List<Movie> list = movies.getMovies(); assertEquals("List.size()", 0, list.size()); } /** * It is still possible to throw unchecked (runtime) exceptions * without dooming the transaction by marking the exception * with the @ApplicationException annotation or in the ejb-jar.xml * deployment descriptor via the <application-exception> tag */ public void testCommit2() throws Exception { userTransaction.begin(); try { entityManager.persist(new Movie("Quentin Tarantino", "Reservoir Dogs", 1992)); entityManager.persist(new Movie("Joel Coen", "Fargo", 1996)); entityManager.persist(new Movie("Joel Coen", "The Big Lebowski", 1998)); List<Movie> list = movies.getMovies(); assertEquals("List.size()", 3, list.size()); try { movies.throwApplicationException(); } catch (RuntimeException e) { // This will *not* cause the tx to rollback // because it is marked as an @ApplicationException } } finally { userTransaction.commit(); } // Transaction was committed List<Movie> list = movies.getMovies(); assertEquals("List.size()", 3, list.size()); } } //END SNIPPET: code