MockEJB提供了一个简单的CMP容器实现,但是功能实在是过于简单,只实现了一个findByPrimaryKey方法。它的CMP其它功能的实现需要依赖于Aspect,我的这个单元测试框架就是靠实现了一堆的Aspect来完成CMP的一些功能的。
- BaseCreateAspect:调用entity bean的create方法会进入这个Aspect,如果是系统初始化从数据库和文件读取初始数据的话,会直接根据那些数据填充entity bean,如果是程序代码创建的entity bean,就会调用entity bean的create和postCreate并且准备把创建的entity bean的内容同步到数据库。
BasePostCreateAspect:调用entity bean的postCreate会调用这个,目前功能不多。(没有必要,删除)- BaseFindAspect:调用entity bean的find方法会调用这个,前面的finder解析器解析的结果就是由它来使用的。
- BaseRemoveAspect:调用entity bean的remove方法会调用这个,会把记录从数据库删除。
- BaseSetterAspect:调用entity bean的setter方法会调用这个,记录entity bean的内容有更新,可能会需要同步到数据库。
在完成这些Aspect的时候需要定义拦截点,可以使用表达式,可惜使用的是Apache的ORO的语法,和Java自己带的表达式语法不同。(修改为自己的Pointcut实现)
代码如下:
package com.activereasoning.test.base;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import javax.ejb.ObjectNotFoundException;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.mockejb.interceptor.Aspect;
import org.mockejb.interceptor.Pointcut;
import com.activereasoning.test.util.ClassUtil;
import com.activereasoning.test.util.SystemUtil;
public abstract class BaseAspect implements Aspect
{
protected Logger log = LogManager.getLogger(this.getClass());
private Class homeClass;
private BeanInfo beanInfo;
protected Pointcut pointcut;
public BeanInfo getBeanInfo()
{
return beanInfo;
}
public Pointcut getPointcut()
{
return pointcut;
}
public void setBeanInfo(BeanInfo bean)
{
this.beanInfo = bean;
homeClass = ClassUtil.getClassForName(bean.getHome());
}
public BaseAspect(BeanInfo bean)
{
this.beanInfo = bean;
homeClass = ClassUtil.getClassForName(bean.getHome());
}
protected Class getHomeClass()
{
return homeClass;
}
protected void setHomeClass(Class c)
{
homeClass = c;
}
public String getBeanName()
{
return beanInfo.getShortName();
}
public Collection distinct(Collection original)
{
return new ArrayList(new HashSet(original));
}
public Collection order(Collection original, List orders)
{
List sortedResult = new ArrayList(original);
Collections.sort(sortedResult, new FieldsComparator(orders));
return sortedResult;
}
public Collection or(Collection first, Collection second)
{
first.addAll(second);
return first;
}
public Collection or(Collection first, Option second)
{
return or(first, findByOption(second));
}
public Collection or(Option first, Option second)
{
return or(findByOption(first), findByOption(second));
}
public Collection and(Collection first, Collection second)
{
first.retainAll(second);
return first;
}
public Collection and(Collection first, Option second)
{
return and(first, findByOption(second));
}
public Collection and(Option first, Option second)
{
return and(findByOption(first), findByOption(second));
}
public Collection ands(List options)
{
Collection result = and((Option) options.get(0), (Option) options.get(1));
for (int i = 2; i < options.size(); i++)
{
result = and(result, (Option) options.get(i));
}
return result;
}
public Collection findByOption(Option option)
{
return SystemUtil.getAREntityDatabase().findByOption(getHomeClass(), option);
}
public Object findSingleByOption(Option option) throws Exception
{
return getSingleValue(findByOption(option));
}
protected Object getSingleValue(Collection collection) throws Exception
{
if (collection.size() == 0)
{
throw new ObjectNotFoundException();
}
else
{
if (collection.size() > 1)
{
log.warn("More than one record found, return first one.");
}
return collection.iterator().next();
}
}
public Collection findAll()
{
return SystemUtil.getAREntityDatabase().findAll(getHomeClass());
}
public boolean isExisted(Object pk)
{
return SystemUtil.getEntityDatabase().find(getHomeClass(), pk) != null;
}
}
package com.activereasoning.test.base;
import java.lang.reflect.Method;
import org.mockejb.interceptor.InvocationContext;
import org.mockejb.interceptor.Pointcut;
import com.activereasoning.session.SequenceUtil;
import com.activereasoning.test.util.CommandUtil;
import com.activereasoning.test.util.DataUtil;
import com.activereasoning.test.util.DummyDataUtil;
import com.activereasoning.test.util.ReflectUtil;
public class BaseCreateAspect extends BaseAspect
{
private boolean needInsertIntoDB = false;
private static Pointcut ejbCreatePointcut = new MethodNamePointcut("ejbCreate");
public BaseCreateAspect(BeanInfo bean)
{
super(bean);
pointcut = ejbCreatePointcut;
}
public void intercept(InvocationContext invocationContext) throws Exception
{
needInsertIntoDB = false;
Object[] paramVals = invocationContext.getParamVals();
Method method = invocationContext.getProxyMethod();
String methodName = method.getName();
if (methodName.equals(Constant.CREATE_METHOD))
{
invocationContext.proceed();
Object object = invocationContext.getTargetObject();
Long pk = DataUtil.getAndRemovePk(getBeanInfo().getShortName());
if (pk != null)//init entity bean
{
directlyCreate(invocationContext, object, pk);
}
else
//product code or test code invoke create
{
if (paramVals != null && paramVals.length >= 1 && paramVals[0] != null
&& paramVals[0].getClass().equals(Long.class))
{
createWithPrimaryKey(invocationContext, object, paramVals[0]);
}
else
{
createWithoutPrimaryKey(invocationContext, object);
}
}
}
if (needInsertIntoDB)
{
SaveRecordCommand command = new SaveRecordCommand(getBeanInfo(), invocationContext.getTargetObject(), true);
CommandUtil.addCommand(CommandUtil.DB, command);
}
}
private void directlyCreate(InvocationContext invocationContext, Object object, Object pk) throws Exception
{
DummyDataUtil.fillEntityBeanData(getBeanInfo(), object, pk);
invocationContext.setReturnObject(pk);
needInsertIntoDB = false;
}
private void createWithoutPrimaryKey(InvocationContext invocationContext, Object object) throws Exception
{
String pkSQLSequenceName = getBeanInfo().getPKSqlSequenceName();
if (pkSQLSequenceName == null)
{
log
.warn(getBeanInfo().getShortName()
+ " does not has a pk-sql sequence name but create without pk value!");
return;
}
Long pk = SequenceUtil.getNextId(pkSQLSequenceName);
ReflectUtil.invokeDirectSetter(object, Constant.PK_FIELD, Long.class, pk);
DataUtil.setEntityContextPk(object, pk);
invocationContext.setReturnObject(pk);
needInsertIntoDB = true;
}
private void createWithPrimaryKey(InvocationContext invocationContext, Object object, Object paramValue)
throws Exception
{
if (isExisted(paramValue))
{
throw new Exception("Can not create the record with the same primary key with existed record.");
//TODO change to the exception as a real container
}
invocationContext.setReturnObject(ReflectUtil.invokeGetter(object, Constant.PK_FIELD));
needInsertIntoDB = true;
}
}
package com.activereasoning.test.base;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import javax.ejb.ObjectNotFoundException;
import org.mockejb.interceptor.InvocationContext;
import org.mockejb.interceptor.Pointcut;
import com.activereasoning.test.util.EJBUtil;
public class BaseFindAspect extends BaseAspect
{
private static Pointcut findPointcut = new MethodNamePatternPointcut("(find|ejbSelect).*");
public BaseFindAspect(BeanInfo bean)
{
super(bean);
pointcut = findPointcut;
}
public void intercept(InvocationContext invocationContext) throws Exception
{
Method method = invocationContext.getProxyMethod();
String methodName = method.getName();
if (methodName.equals("findAll"))
{
invocationContext.setReturnObject(findAll());
}
else if (methodName.equals("findByPrimaryKey"))
{
log.debug("Can not find " + getBeanInfo().getShortName() + " by primary key"
+ invocationContext.getParamVals()[0]);
throw new ObjectNotFoundException();
}
boolean toInterceptResult = toIntercept(invocationContext);
if (!toInterceptResult)
{
BeanInfo beanInfo = EJBUtil.getBeanInfoByName(getBeanName());
Query query = beanInfo.getQuery(methodName);
if (query != null)
{
Object[] paramVals = invocationContext.getParamVals();
List options = query.getOptions();
Collection result = null;
if (options.size() == 0)
{
result = findAll();
}
else
{
//Collections.sort(options);
for (int i = 0; i < options.size(); i++)
{
Option option = (Option) options.get(i);
if (option.getIndex() < options.size() + 1)
{
option.setValue(paramVals[option.getIndex() – 1]);
}
if (i == 0)
{
result = findByOption(option);
}
else
{
if (option.isAnd())
{
result = and(result, option);
}
else
{
result = or(result, option);
}
}
}
}
List orders = query.getOrders();
List sortedResult = new ArrayList(result);
Collections.sort(sortedResult, new FieldsComparator(orders));
if (method.getReturnType().equals(Collection.class))
{
if (query.isDistinct())
{
invocationContext.setReturnObject(distinct(sortedResult));
}
else
{
invocationContext.setReturnObject(sortedResult);
}
}
else
{
invocationContext.setReturnObject(getSingleValue(sortedResult));
}
}
}
}
protected boolean toIntercept(InvocationContext invocationContext) throws Exception
{
return false;
}
}
package com.activereasoning.test.base;
import java.util.regex.Pattern;
import org.mockejb.interceptor.Aspect;
import org.mockejb.interceptor.InvocationContext;
import org.mockejb.interceptor.Pointcut;
import com.activereasoning.test.util.ClassUtil;
import com.activereasoning.test.util.DatabaseUtil;
import com.activereasoning.test.util.EJBUtil;
import com.activereasoning.test.util.ReflectUtil;
import com.activereasoning.test.util.StringUtil;
import com.activereasoning.test.util.SystemUtil;
public class BaseRemoveAspect implements Aspect
{
private static Pointcut pointcut = new MethodNamePointcut("remove");
private static Pattern pattern = Pattern
.compile("EJB object:\\s+BusinessIface:\\s+com\\.activereasoning(?:\\.(\\w+))+");
public void intercept(InvocationContext invocationContext) throws Exception
{
Object[] paramVals = invocationContext.getParamVals();
if (paramVals == null || paramVals.length == 0)
{
String target = invocationContext.getProxyObject().toString();
Class home = null;
String name = StringUtil.getFirstMatchGroup(pattern, target);
if (name != null)
{
name = StringUtil.getBeanName(name);
BeanInfo bean = EJBUtil.getBeanInfoByName(name);
if (bean.getType() == BeanInfo.ENTITY_BEAN)
{
home = ClassUtil.getClassForName(bean.getHome());
SystemUtil.getAREntityDatabase().remove(home, invocationContext.getProxyObject());
DatabaseUtil.deleteRecord(bean.getTable(), bean.getPK(), ReflectUtil.invokeDirectGetter(
invocationContext.getProxyObject(), Constant.PK_FIELD));
}
}
}
}
public Pointcut getPointcut()
{
return pointcut;
}
}
package com.activereasoning.test.base;
import java.lang.reflect.Method;
import org.mockejb.interceptor.InvocationContext;
import org.mockejb.interceptor.Pointcut;
import com.activereasoning.test.util.ClassUtil;
import com.activereasoning.test.util.CommandUtil;
public class BaseSetterAspect extends BaseAspect
{
private static Pointcut setterPointcut = new MethodNamePatternPointcut("set[A-Z]\\w+");
public BaseSetterAspect(BeanInfo bean)
{
super(bean);
pointcut = setterPointcut;
}
public void intercept(InvocationContext invocationContext) throws Exception
{
invocationContext.proceed();
Method method = invocationContext.getProxyMethod();
if (method != null)
{
Class[] types = method.getParameterTypes();
if (types != null && types.length == 1 && ClassUtil.isSupportedSetterType(types[0]))
{
String field = method.getName().substring(3);
if (!field.equalsIgnoreCase(Constant.PK_FIELD) && getBeanInfo().getFieldColumn(field) != null)
{
SaveRecordCommand command = new SaveRecordCommand(getBeanInfo(), invocationContext
.getTargetObject(), false);
CommandUtil.addCommand(CommandUtil.DB, command);
}
}
}
}
}
0 Comments
4 Pingbacks