/** * * 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. */ package org.apache.openejb.core.stateful; import junit.framework.TestCase; import org.apache.openejb.OpenEJB; import org.apache.openejb.assembler.classic.Assembler; import org.apache.openejb.assembler.classic.ProxyFactoryInfo; import org.apache.openejb.assembler.classic.SecurityServiceInfo; import org.apache.openejb.assembler.classic.StatefulSessionContainerInfo; import org.apache.openejb.assembler.classic.TransactionServiceInfo; import org.apache.openejb.config.ConfigurationFactory; import org.apache.openejb.core.LocalInitialContextFactory; import org.apache.openejb.jee.EjbJar; import org.apache.openejb.jee.StatefulBean; import org.apache.openejb.loader.SystemInstance; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.annotation.Resource; import javax.ejb.Local; import javax.ejb.LocalBean; import javax.ejb.PostActivate; import javax.ejb.PrePassivate; import javax.ejb.Remote; import javax.ejb.Remove; import javax.ejb.SessionContext; import javax.naming.InitialContext; import javax.transaction.TransactionManager; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Stack; /** * @version $Revision$ $Date$ */ public class StatefulContainerTest extends TestCase { private List<Lifecycle> inTxExpectedLifecycle; private List expectedLifecycle; public void testBusinessLocalInterface() throws Exception { testBusinessLocalInterface(expectedLifecycle); } public void testBusinessLocalBeanInterface() throws Exception { final List localbeanExpectedLifecycle = new ArrayList(); localbeanExpectedLifecycle.addAll(expectedLifecycle); // WAS can't avoid the extra constructor call // NOW it was rewritten to avoid it // localbeanExpectedLifecycle.add(4, Lifecycle.CONSTRUCTOR); testBusinessLocalBeanInterface(localbeanExpectedLifecycle); } public void testBusinessRemoteInterfaceInTx() throws Exception { final TransactionManager transactionManager = SystemInstance.get().getComponent(TransactionManager.class); transactionManager.begin(); try { testBusinessRemoteInterface(inTxExpectedLifecycle); } finally { transactionManager.commit(); } } protected void testBusinessLocalInterface(final List expectedLifecycle) throws Exception { // Do a create... final InitialContext ctx = new InitialContext(); final Object object = ctx.lookup("WidgetBeanLocal"); assertTrue("instanceof widget", object instanceof Widget); final Widget widget = (Widget) object; // Do a business method... final Stack<Object> actual = widget.getLifecycle(); assertNotNull("lifecycle", actual); // test app exception try { widget.throwAppException(); fail("Expected application exception"); } catch (final SQLException e) { assertEquals("test", e.getMessage()); } // Do another business method... widget.afterAppException(); // Do a remove... widget.destroy(); // Check the lifecycle of the bean assertEquals(StatefulContainerTest.join("\n", expectedLifecycle), join("\n", WidgetBean.lifecycle)); } protected void testBusinessLocalBeanInterface(final List expectedLifecycle) throws Exception { // Do a create... final InitialContext ctx = new InitialContext(); final Object object = ctx.lookup("WidgetBeanLocalBean"); assertTrue("instanceof widget", object instanceof WidgetBean); final WidgetBean widget = (WidgetBean) object; // Do a business method... final Stack<Object> actual = widget.getLifecycle(); assertNotNull("lifecycle", actual); // test app exception try { widget.throwAppException(); fail("Expected application exception"); } catch (final SQLException e) { assertEquals("test", e.getMessage()); } // Do another business method... widget.afterAppException(); // Do a remove... widget.destroy(); // Check the lifecycle of the bean assertEquals(StatefulContainerTest.join("\n", expectedLifecycle), join("\n", WidgetBean.lifecycle)); } public void testBusinessRemoteInterface() throws Exception { testBusinessRemoteInterface(expectedLifecycle); } public void testBusinessLocalInterfaceInTx() throws Exception { final TransactionManager transactionManager = SystemInstance.get().getComponent(TransactionManager.class); transactionManager.begin(); try { testBusinessLocalInterface(inTxExpectedLifecycle); } finally { transactionManager.commit(); } } public void testBusinessLocalBeanInterfaceInTx() throws Exception { final List localbeanExpectedLifecycle = new ArrayList(); localbeanExpectedLifecycle.addAll(inTxExpectedLifecycle); // WAS can't avoid the extra constructor call // NOW it was rewritten to avoid it // localbeanExpectedLifecycle.add(3, Lifecycle.CONSTRUCTOR); final TransactionManager transactionManager = SystemInstance.get().getComponent(TransactionManager.class); transactionManager.begin(); try { testBusinessLocalBeanInterface(localbeanExpectedLifecycle); } finally { transactionManager.commit(); } } protected void testBusinessRemoteInterface(final List expectedLifecycle) throws Exception { WidgetBean.lifecycle.clear(); // Do a create... final InitialContext ctx = new InitialContext(); final Object object = ctx.lookup("WidgetBeanRemote"); assertTrue("instanceof widget", object instanceof RemoteWidget); final RemoteWidget widget = (RemoteWidget) object; // Do a business method... final Stack<Object> lifecycle = widget.getLifecycle(); assertNotNull("lifecycle", lifecycle); assertNotSame("is copy", lifecycle, WidgetBean.lifecycle); // test app exception try { widget.throwAppException(); fail("Expected application exception"); } catch (final SQLException e) { assertEquals("test", e.getMessage()); } // Do another business method... widget.afterAppException(); // Do a remove... widget.destroy(); try { widget.destroy(); fail("Calling a removed bean should not be possible"); } catch (final Exception e) { //Ignore } // Check the lifecycle of the bean assertEquals(StatefulContainerTest.join("\n", expectedLifecycle), join("\n", WidgetBean.lifecycle)); } protected void setUp() throws Exception { super.setUp(); System.setProperty(javax.naming.Context.INITIAL_CONTEXT_FACTORY, LocalInitialContextFactory.class.getName()); final ConfigurationFactory config = new ConfigurationFactory(); final Assembler assembler = new Assembler(); assembler.createProxyFactory(config.configureService(ProxyFactoryInfo.class)); assembler.createTransactionManager(config.configureService(TransactionServiceInfo.class)); assembler.createSecurityService(config.configureService(SecurityServiceInfo.class)); // containers final StatefulSessionContainerInfo statefulContainerInfo = config.configureService(StatefulSessionContainerInfo.class); statefulContainerInfo.properties.setProperty("PoolSize", "0"); statefulContainerInfo.properties.setProperty("BulkPassivate", "1"); statefulContainerInfo.properties.setProperty("Frequency", "0"); assembler.createContainer(statefulContainerInfo); // Setup the descriptor information final EjbJar ejbJar = new EjbJar(); ejbJar.addEnterpriseBean(new StatefulBean(WidgetBean.class)); assembler.createApplication(config.configureApplication(ejbJar)); WidgetBean.lifecycle.clear(); expectedLifecycle = Arrays.asList(Lifecycle.values()); inTxExpectedLifecycle = new ArrayList<Lifecycle>(); for (final Lifecycle lifecycle : Lifecycle.values()) { if (!lifecycle.name().startsWith("PRE_PASSIVATE") && !lifecycle.name().startsWith("POST_ACTIVATE")) { inTxExpectedLifecycle.add(lifecycle); } } } @Override protected void tearDown() throws Exception { OpenEJB.destroy(); } private static String join(final String delimeter, final List items) { final StringBuilder sb = new StringBuilder(); for (final Object item : items) { sb.append(item.toString()).append(delimeter); } return sb.toString(); } @Local public static interface Widget { Stack<Object> getLifecycle(); void throwAppException() throws SQLException; void afterAppException(); void destroy(); } @Remote public static interface RemoteWidget extends Widget { } public static enum Lifecycle { // construction CONSTRUCTOR, INJECTION, POST_CONSTRUCT, PRE_PASSIVATE1, // business method POST_ACTIVATE1, BUSINESS_METHOD, PRE_PASSIVATE2, // throw app exception POST_ACTIVATE2, PRE_PASSIVATE3, // business method after app exception POST_ACTIVATE3, PRE_PASSIVATE4, // remove POST_ACTIVATE4, REMOVE, PRE_DESTROY, } @LocalBean public static class WidgetBean implements Widget, RemoteWidget { private int activates = 0; private int passivates = 0; public static Stack<Object> lifecycle = new Stack<Object>(); public WidgetBean() { lifecycle.push(Lifecycle.CONSTRUCTOR); } public void throwAppException() throws SQLException { throw new SQLException("test"); } public void afterAppException() { } @Resource public void setContext(final SessionContext context) { lifecycle.push(Lifecycle.INJECTION); } public Stack<Object> getLifecycle() { lifecycle.push(Lifecycle.BUSINESS_METHOD); return lifecycle; } @PostActivate public void activate() { final String name = "POST_ACTIVATE" + (++activates); try { lifecycle.push(Enum.valueOf(Lifecycle.class, name)); } catch (final Exception e) { lifecycle.push(name); } } @PrePassivate public void passivate() { final String name = "PRE_PASSIVATE" + (++passivates); try { lifecycle.push(Enum.valueOf(Lifecycle.class, name)); } catch (final Exception e) { lifecycle.push(name); } } @PostConstruct public void init() { lifecycle.push(Lifecycle.POST_CONSTRUCT); } @PreDestroy public void predestroy() { lifecycle.push(Lifecycle.PRE_DESTROY); } @Remove public void destroy() { lifecycle.push(Lifecycle.REMOVE); } } }