MockEJB提供了一个简单的CMP容器实现,但是功能实在是过于简单,只实现了一个findByPrimaryKey方法。它的CMP其它功能的实现需要依赖于Aspect,我的这个单元测试框架就是靠实现了一堆的Aspect来完成CMP的一些功能的。

  1. BaseCreateAspect:调用entity bean的create方法会进入这个Aspect,如果是系统初始化从数据库和文件读取初始数据的话,会直接根据那些数据填充entity bean,如果是程序代码创建的entity bean,就会调用entity bean的create和postCreate并且准备把创建的entity bean的内容同步到数据库。
  2. BasePostCreateAspect:调用entity bean的postCreate会调用这个,目前功能不多。(没有必要,删除)
  3. BaseFindAspect:调用entity bean的find方法会调用这个,前面的finder解析器解析的结果就是由它来使用的。
  4. BaseRemoveAspect:调用entity bean的remove方法会调用这个,会把记录从数据库删除。
  5. 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);
                }
            }
        }
    }
}

(Visited 99 times, 1 visits today)