| 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;
}
}
}