/* Copyright 2017 Red Hat, Inc. Licensed 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. */ package org.jboss.as.test.integration.ejb.transaction.cmt.inheritance; import javax.annotation.Resource; import javax.ejb.EJB; import javax.ejb.EJBException; import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; import javax.transaction.Transaction; import javax.transaction.TransactionManager; import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.shrinkwrap.api.Archive; import org.jboss.shrinkwrap.api.ShrinkWrap; import org.jboss.shrinkwrap.api.asset.EmptyAsset; import org.jboss.shrinkwrap.api.spec.WebArchive; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; /** * <p> * Test checking behavior of {@link TransactionAttribute} when inherited * by child classes. * <p> * <b>8.3.7.1</b> Specification of Transaction Attributes with Metadata Annotations<br> * If the bean class has superclasses, the following additional rules apply. * <ul> * <li>A transaction attribute specified on a superclass S applies to the business methods defined by * S. If a class-level transaction attribute is not specified on S, it is equivalent to specification of * TransactionAttribute(REQUIRED) on S.</li> * <li>A transaction attribute may be specified on a business method M defined by class S to override * for method M the transaction attribute value explicitly or implicitly specified on the class S.</li> * <li>If a method M of class S overrides a business method defined by a superclass of S, the transaction * attribute of M is determined by the above rules as applied to class S.</li> * </ul> * * @author Ondrej Chaloupka <ochaloup@redhat.com> */ @RunWith(Arquillian.class) public class TransactionAttributeTestCase { @Resource(lookup = "java:/TransactionManager") private TransactionManager tm; @EJB private SuperSLSB superClass; @EJB private ChildSLSB childClass; @EJB private ChildWithClassAnnotationSLSB childWithClassAnnotation; @Deployment public static Archive<?> deploy() { WebArchive war = ShrinkWrap.create(WebArchive.class, "transaction-attribute-inheritance.war"); war.addPackage(TransactionAttributeTestCase.class.getPackage()); war.add(EmptyAsset.INSTANCE, "WEB-INF/beans.xml"); return war; } @Test public void superClassCheck() throws Exception { tm.begin(); try { // active transaction superClass.aMethod(); superClass.bMethod(); superClass.cMethod(); } finally { tm.rollback(); } tm.begin(); try { // active transaction superClass.neverMethod(); Assert.fail("TransactionAttribute.NEVER expects failure when running" + " within a transactional context of txn: '" + tm.getTransaction() + "'"); } catch (EJBException ignoreAsExpected) { } finally { tm.rollback(); } // no active transaction superClass.aMethod(); superClass.bMethod(); superClass.cMethod(); superClass.neverMethod(); } /** * Tests expects behavior of {@link TransactionAttributeType#REQUIRED} */ @Test public void defaultBeanAttributeOverridesParentClassDeclaration() throws Exception { tm.begin(); Transaction testTxn = tm.getTransaction(); try { // active transaction Transaction beanTxn = childClass.aMethod(); Assert.assertNotNull("There has to be started a transaction in the bean", beanTxn); Assert.assertEquals("Child method default REQUIRED TransactionAttribute" + " has to override the settings of SUPPORTS from super class", testTxn, beanTxn); } finally { tm.rollback(); } // no active transaction Transaction beanTxn = childClass.aMethod(); Assert.assertNotNull("There has to be started transaction in bean as TransactionAttribute" + " should be REQUIRED", beanTxn); } /** * Tests expects behavior of {@link TransactionAttributeType#SUPPORTS} */ @Test public void inheritsWhenMethodCalledFromParent() throws Exception { tm.begin(); try { // active transaction childClass.bMethod(); } finally { tm.rollback(); } // no active transaction Assert.assertNull("There can't be active transaction here", tm.getTransaction()); childClass.bMethod(); } /** * Tests expects behavior of {@link TransactionAttributeType#MANDATORY} */ @Test public void explicitMethodAttributeOverrides() throws Exception { tm.begin(); try { // active transaction childClass.cMethod(); } finally { tm.rollback(); } try { // no active transaction Assert.assertNull("There can't be active transaction here", tm.getTransaction()); childClass.cMethod(); Assert.fail("Method called with no active transaction but MANDATORY requires it"); } catch (EJBException ignoreAsExpected) { } } /** * Tests expects behavior of {@link TransactionAttributeType#REQUIRED} */ @Test public void defaultBeanAttributeOverridesParentMethodDeclaration() throws Exception { tm.begin(); Transaction testTxn = tm.getTransaction(); try { // active transaction Transaction beanTxn = childClass.neverMethod(); Assert.assertNotNull("There has to be started a transaction in the bean", beanTxn); Assert.assertEquals("Child method default REQUIRED TransactionAttribute" + " has to override the settings of SUPPORTS from super class", testTxn, beanTxn); } finally { tm.rollback(); } // no active transaction Assert.assertNull("There can't be active transaction here", tm.getTransaction()); Transaction beanTxn = childClass.neverMethod(); Assert.assertNotNull("There has to be started a transaction in the bean " + "as TransactionAttribute is REQUIRED", beanTxn); } /** * Tests expects behavior of {@link TransactionAttributeType#NEVER} */ @Test public void classAnnotationOverridesParentDeclaration() throws Exception { tm.begin(); try { // active transaction childWithClassAnnotation.aMethod(); Assert.fail("TransactionAttribute.NEVER expects failure when running" + " within a transactional context of txn: '" + tm.getTransaction() + "'"); } catch (EJBException ignoreAsExpected) { } finally { tm.rollback(); } // no active transaction Assert.assertNull("There can't be active transaction here", tm.getTransaction()); childWithClassAnnotation.aMethod(); } /** * Tests expects behavior of {@link TransactionAttributeType#SUPPORTS} */ @Test public void inheritsWhenMethodCalledFromParentWithChildClassLevelAnnotation() throws Exception { tm.begin(); try { // active transaction childClass.bMethod(); } finally { tm.rollback(); } // no active transaction Assert.assertNull("There can't be active transaction here", tm.getTransaction()); childClass.bMethod(); } }