EntityBeanTest.java |
package org.mockejb.test.entity; import java.util.*; import javax.naming.*; import junit.framework.TestCase; import org.easymock.MockControl; import org.mockejb.*; import org.mockejb.interceptor.*; import org.mockejb.jndi.*; /** * Demonstrates CMP Entity bean support. * MockEJB uses CGLIB to dynamically generate implementation classes * for abstract entity bean classes. * MockEJB fully supports CMP field getters/setters. * The rest of the container's support (such as finders and CMR) has to be implemented using * Aspect/Interceptor framework as shown below. */ public class EntityBeanTest extends TestCase { // JNDI context and MockContainer instance used by all tests in this class private MockContainer mockContainer; private Context context; private AspectSystem aspectSystem; // We use PersonHome in all tests private PersonHome personHome; public EntityBeanTest(String testName) { super( testName ); } /** * Sets up mock container, JNDI context and deploy EJBs that we need. */ public void setUp() throws Exception { // we use aspects in most of the tests here aspectSystem = AspectSystemFactory.getAspectSystem(); // make MockContextFactory the primary JNDI provider MockContextFactory.setAsInitial(); context = new InitialContext(); // Creating MockContainer deletes all aspects from AspectSystem and clears EntityDatabase mockContainer = new MockContainer( context ); // Deploy the person bean EntityBeanDescriptor personDescriptor = new EntityBeanDescriptor( Person.JNDI_NAME, PersonHome.class, Person.class, PersonBean.class ); mockContainer.deploy( personDescriptor ); /* Create aspect that will handle automatic PK generation for the PersonBean. * PersonBean has auto-sequencing PK that would be handled by the container * (although it is not part of the spec, almost all EJB containers support it). */ aspectSystem.add( new PersonCreateAspect() ); // Deploy the address bean. In this simple example person has many addresses. EntityBeanDescriptor addressDescriptor = new EntityBeanDescriptor( Address.JNDI_NAME, AddressHome.class, Address.class, AddressBean.class ); mockContainer.deploy( addressDescriptor ); // Obtain personHome for use in the tests personHome = (PersonHome)context.lookup(Person.JNDI_NAME); } public void tearDown() { // cleanup JNDI settings MockContextFactory.revertSetAsInitial(); } /** * Demonstrates the create/ejbCreate support */ public void testCreate( ) throws Exception { // Create a Person instance Person person = personHome.create("John", "Doe"); // Make sure that CMP fields were set correctly assertEquals("John", person.getFirstName()); assertEquals("Doe", person.getLastName()); // Check that id (PK) was generated by the PersonCreateAspect assertTrue( person.getId()>0); // Check that PK was set correctly assertEquals( new Long(person.getId()), person.getPrimaryKey() ); } /** * Demonstrates the usage of a finder (other than findByPrimaryKey) */ public void testFinder() throws Exception { // Create aspect that returns mock data for the finder aspectSystem.add( new PersonFinderAspect() ); // call the finder Person person = personHome.findByName("John", "Doe" ); assertNotNull(person); assertEquals("Doe",person.getLastName()); } /** * Demonstrates the use of findByprimaryKey */ public void testFindByPrimaryKey() throws Exception { /* MockEJB provides a primitive in-memory database implementation (EntityDatabase class) * that automatically handles findByPrimaryKey calls. * It can be populated directly (see "testEasyMockWithFindByPrimaryKey") * or by simply calling "create". If ejbCreate is intercepted and returns * a PK (without interception it would return null because of the spec), * MockEJB automatically adds the newly created bean to the EntityDatabase. * Since our CreateAspect is active, it will make sure that the PK * is returned from the ejbCreate method. */ Person createdPerson = personHome.create("John", "Doe"); // find person -- EntityDatabase is used Person foundPerson = personHome.findByPrimaryKey( createdPerson.getId() ); // make sure that we got the same person assertEquals(createdPerson, foundPerson ); } /** * Demonstrates how mock entities can be setup using * EasyMock and EntityDatabase. */ public void testEasyMockWithFindByPrimaryKey() throws Exception { // Create mock entity. Note that since this object is created outside of // MockEJB, you won't be able to intercept calls to it or to use MockEJB-provided // exception translation and CMT transaction support. // Here we just need test data, we don't care about container's services MockControl personBeanControl = MockControl.createControl( Person.class); Person createdPerson = (Person) personBeanControl.getMock(); createdPerson.getId(); personBeanControl.setReturnValue(1L); createdPerson.getFirstName(); personBeanControl.setReturnValue("John"); createdPerson.getLastName(); personBeanControl.setReturnValue("Doe"); personBeanControl.replay(); // Add mock entity to the EntityDatabase so we can find it using findByPrimaryKey mockContainer.getEntityDatabase().add( PersonHome.class, new Long(1), createdPerson ); // now we can call findByPrimaryKey Person foundPerson = personHome.findByPrimaryKey( 1 ); assertNotNull( foundPerson); assertEquals( createdPerson, foundPerson); } /** * Demonstrates the use of CMR using standard EJB API. * First, we populate CMR collection using "create" and "set" * methods, after that we can begin using it. * For example, you can setup CMR this way in the "setUp" method of a test class and * then call Session facade that manipulates CMR collections in the test. * Alternatively, you can setup CMR using interceptors ( see "testCMRUsingInterceptor"). * */ public void testCMRUsingAdd() throws Exception { // Find the person we need // add aspect that handles finders aspectSystem.add( new PersonFinderAspect() ); Person person = personHome.findByName("John", "Doe" ); // now we can create Address for the person AddressHome addressHome = (AddressHome)context.lookup(Address.JNDI_NAME); // Get the current list of addresses for this person // Note that MockEJB returns an empty collection (not null) if the // collection is not initialized (as per the spec) // MockEJB also supports java.util.Set. Collection addresses = person.getAddresses(); Address address = addressHome.create("1001 Main St", "Washington", "DC", "22222","USA", person); /* We need to set the ID of the address. Real container would do it for us * if we define "id" field as auto-sequence in the deployment descriptor, * but with MockEJB it is the responsibility of the setup code. * In our case, setId is not even part of the business interface, so we * need to get to the implementation bean object. * In MockEJB any business interface can be cast to EjbBeanAccess which * provides access to the bean and its context. */ AddressBean addressBean = (AddressBean) ((EjbBeanAccess)address).getBean(); // now we can set the ID directly addressBean.setId(123); addresses.add( address); /* Since MockEJB does everything in memory, you don't need to call setter. * But it won't hurt either. */ person.setAddresses(addresses); // CMR is now setup, we can begin using it. In the real life, // the code above will probably be in the setUp method (unless you're // testing the CMR creation functionality) // make sure that the address was added assertEquals(1, person.getAddresses().size()); // make sure that M:1 is set address = (Address)person.getAddresses().iterator().next(); assertNotNull( address.getPerson() ); // check the PK of the address assertEquals( 123, address.getId()); } /** * Demonstrates how to set up CMR using interceptors/aspects. */ public void testCMRUsingInterceptor() throws Exception { // Add aspect that handles CMR methods on the Person bean aspectSystem.add( new PersonCMRAspect() ); // Aspect will do all the work for us, the setup code is now in the interceptor // add aspect that handles finders so we can find the person aspectSystem.add( new PersonFinderAspect() ); Person person = personHome.findByName("John", "Doe" ); // make sure that the address exists assertEquals(1, person.getAddresses().size()); // make sure that M:1 is set Address address = (Address)person.getAddresses().iterator().next(); assertNotNull( address.getPerson() ); // check the PK of the address assertEquals( 123, address.getId()); } /** * Demonstrates the support of ejbHome and ejbSelect methods */ public void testEjbHomeEjbSelect() throws Exception { // Create interceptor for the ejbSelectAll method of PersonBean SelectAllAspect selectAllAspect = new SelectAllAspect(); // Intercept calls to the "ejbSelectAll" method of the personBean aspectSystem.add( selectAllAspect ); // Call the home method which in turn calls ejbSelectAll method personHome.updateNames(); // make sure that the data has been updated List people = selectAllAspect.getPeople(); assertEquals( "Smith", ((Person)people.get(0)).getLastName() ); } // *** Interceptors used by this test case /** * Supports auto-sequenced PK for the Person bean */ class PersonCreateAspect implements Aspect { private long pkSequence =0; /** * Intercept all calls to the ejbCreate method of the PersonBean. * Notice how the pointcut can match interface methods as well as the methods * of the implementation class. */ public Pointcut getPointcut(){ /* Note that we have to use ".*" in the regexp since * the actual concrete class (subclass) is provided by CGLIB, so its name is different from * the is the PersonBean (the actual name is PersonBean$Enhanced...) */ return new MethodPatternPointcut( "PersonBean.*ejbCreate" ); } public void intercept( InvocationContext invocationContext ) throws Exception { // Proceed to call ejbCreate method of the PersonBean invocationContext.proceed( ); // generate the id for this bean. The real container can do it using Oracle sequence, for instance. long id = ++pkSequence; PersonBean personBean = (PersonBean)invocationContext.getTargetObject(); // Set the id personBean.setId(id); // return the PK value. Without this interceptor, this method would return null. invocationContext.setReturnObject( new Long( id ) ); } } /** * Handles findByName calls */ class PersonFinderAspect implements Aspect { /** * Intercept findByName method */ public Pointcut getPointcut(){ return new MethodPatternPointcut( "PersonHome\\.findByName" ); } public void intercept( InvocationContext invocationContext ) throws Exception { Object [] paramVals = invocationContext.getParamVals(); invocationContext.setReturnObject( create( (String)paramVals[0], (String)paramVals[1] ) ); // We don't need to proceed to the next interceptor since we're done with the finder } /** * Creates Person entity using its "create" method */ private Person create( String firstName, String lastName ) throws Exception { Context context = new InitialContext(); PersonHome personHome = (PersonHome)context.lookup(Person.JNDI_NAME); Person person = personHome.create(firstName, lastName); return person; } } /** * Intercepts calls to the CMR methods of the Person bean (getAddresses), * and populates and returns the collection of address objects. */ class PersonCMRAspect implements Aspect { public Pointcut getPointcut(){ return new MethodPatternPointcut( "Person\\.getAddresses()" ); } public void intercept( InvocationContext invocationContext ) throws Exception { // note that since this aspect only handles one method, we don't need to check // the method name that we intercepted // Create the addresses we want using AddressHome AddressHome addressHome = (AddressHome)context.lookup(Address.JNDI_NAME); // Create empty collection Collection addresses = new ArrayList(); /* * Create the address and add it to the collection. * We need to pass the parent object (person), this is the * Person interface that we intercepted. */ Address address = addressHome.create("1001 Main St", "Washington", "DC", "22222","USA", (Person)invocationContext.getProxyObject() ); // Set the PK of the address by getting the address bean and calling its setter AddressBean addressBean = (AddressBean) ((EjbBeanAccess)address).getBean(); addressBean.setId(123); addresses.add( address); invocationContext.setReturnObject( addresses); } } /** * Intercepts ejbSelectAll method and populates and returns * the data for this method. */ class SelectAllAspect implements Aspect { private List people; /** * Intercepts ejbSelectAll of the PersonBean * @see org.mockejb.interceptor.Aspect#getPointcut() */ public Pointcut getPointcut(){ // Note that the pointcut here is applied to the bean, not to the interface, since ejbSelect is only defined in the bean return new MethodPatternPointcut( "PersonBean\\.ejbSelectAll()" ); } public void intercept( InvocationContext invocationContext ) throws Exception { // we don't need to call "proceed" since the PersonBean does not know // how to handle it anyway. PersonHome personHome = (PersonHome)context.lookup(Person.JNDI_NAME); people = new ArrayList(); people.add( personHome.create("John", "Smit") ); // Return the created collection invocationContext.setReturnObject( people); } /** * Returns the collection of people that was returned to the client * so we can check against it in the test method. * @return collection of people */ List getPeople() { return people; } } }