package org.mockejb;
import java.lang.reflect.*;
import javax.ejb.*;
/**
* Supports invocations of the home methods specific for entity beans, such as
* finders and ejbHome.
*
* @author Alexander Ananiev
*/
class EntityBeanHome extends BasicEjbHome {
// bean and method that will be used as the target for methods that MockEJB does not implement itself
private DummyCMPBean dummyCmpBean = new DummyCMPBean();
private EntityDatabase entityDatabase;
EntityBeanHome( BasicEjbDescriptor descriptor, final EntityDatabase entityDatabase ){
super( descriptor );
this.entityDatabase = entityDatabase;
}
/**
* Creates entity bean. It involves instantiating it, setting the context and
* calling "create".
*/
public Object create( BasicEjbDescriptor basicDescriptor, MockEjbObject ejbObject,
Method createMethod, Object[] paramVals ) throws Exception {
EntityBeanDescriptor descriptor = (EntityBeanDescriptor)basicDescriptor;
MockEjbContext ejbContext = new MockEjbContext( getHomeProxy() );
Object bean = createBeanInstance(descriptor, createMethod, ejbContext );
Object pk = null;
if ( ! createMethod.getDeclaringClass().equals( GenericHome.class )) {
pk = invokeBeanCreateMethod( bean, createMethod, paramVals );
ejbContext.setPrimaryKey( pk );
// ejbPostCreate
invokeBeanMethodWithPrefix( "ejbPost", bean, createMethod, paramVals );
}
Object ejbObjectProxy = ejbObject.createProxy( bean, ejbContext );
// TODO: refactor - FindByPKHandler should handle create as well
if (pk != null ) {
entityDatabase.add( descriptor.getHomeClass(), pk, ejbObjectProxy);
}
return ejbObjectProxy;
}
/**
* Creates the bean without calling its create method and creating proxy.
* @param basicDescriptor
* @return new bean instance
*/
private Object createBeanInstance( EntityBeanDescriptor descriptor,
Method method, MockEjbContext ejbContext ) throws Exception {
// if the bean class is an abstract class - use the helper class to create the subclass
Class beanClass = descriptor.getBeanClass();
Object bean;
if (beanClass != null && descriptor.isCMP() ) {
EntityBeanSubclass subclassFactory = EntityBeanSubclass.newInstance(beanClass);
bean = subclassFactory.create();
}
else {
bean = createBean( descriptor );
}
if ( bean instanceof EntityBean ) {
Class paramTypes[]={ EntityContext.class };
Object args[]={ ejbContext };
invokeBeanMethod(bean, null,
"setEntityContext", paramTypes, args );
}
return bean;
}
public Object invokeHomeMethod( BasicEjbDescriptor basicDescriptor,
Method homeMethod, Object[] paramVals ) throws Exception{
Object returnObj = null;
EntityBeanDescriptor descriptor = (EntityBeanDescriptor)basicDescriptor;
if ( homeMethod.getName().startsWith("find") )
returnObj = invokeFinder(descriptor, homeMethod, paramVals);
else {
// consider everything else a home method
// create a bean that we can use to call a home method on
Object bean = createBeanInstance( descriptor, homeMethod,
getMockEjbContext( ) );
// try to find this method on the target bean
returnObj = invokeBeanMethodWithPrefix( "ejbHome", bean, homeMethod, paramVals );
}
return returnObj;
}
protected Object invokeFinder(EntityBeanDescriptor descriptor, Method finderMethod,
Object[] paramVals ) throws Exception{
Object returnObj = null;
if ( descriptor.isCMP() ) {
// this is to make sure that there is a context
getMockEjbContext();
try {
returnObj = interceptorInvoker.invoke( getHomeProxy(), finderMethod,
dummyCmpBean, dummyCmpBean.getTargetMethod(), paramVals );
}
catch ( MustBeInterceptedException mbie ){
// translate it into more meaningful error message
throw new MustBeInterceptedException( finderMethod );
}
}
else {
// create a bean that we can use to call a finder method on
Object bean = createBeanInstance( descriptor, finderMethod,
getMockEjbContext() );
returnObj = invokeBeanMethodWithPrefix("ejb", bean, finderMethod,
paramVals );
}
return returnObj;
}
private MockEjbContext getMockEjbContext( ) {
MockEjbContext context = new MockEjbContext( getHomeProxy() );
interceptorInvoker.setContext( MockEjbContext.class.getName(), context );
return context;
}
}
|