本来今天已经完成了框架的大部分功能,写的一些测试用例都可以成功执行,但是自动发布是放在BaseTestCase里面的,感觉不好,就重构了一下,扩展了InitialContext类,覆盖了lookup方法(参数为字符串的那个,我们的代码中都是使用的这个),这样代码看起来更好一些的。另外我们的系统里面使用到了一些类似的机制,我为了产品可以进行单元测试还对一些Factory类进行了简单的修改,让他们返回我为了单元测试而写的实现类。如果使用这个扩展的InitialContext类,应该不需要做那些修改了,试了下,发现不行,因为产品的代码好像和Jboss的某些特性进行绑定了,先做简单的重构,以后再研究产品到底使用了JBoss的哪些特性,能否搞定。
代码如下:
package test.base;

import java.lang.reflect.Method;
import java.util.Iterator;

import javax.jms.MessageListener;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.mockejb.EntityBeanDescriptor;
import org.mockejb.MDBDescriptor;
import org.mockejb.MockContainer;
import org.mockejb.SessionBeanDescriptor;
import org.mockejb.interceptor.Aspect;
import org.mockejb.interceptor.AspectSystem;
import org.mockejb.interceptor.ClassPointcut;
import org.mockejb.interceptor.InvocationRecorder;

import test.util.ClassUtil;
import test.util.CommandUtil;
import test.util.DataUtil;
import test.util.DummyDataUtil;
import test.util.EJBUtil;

public class ARInitialContext extends InitialContext
{
    private static Logger log = LogManager.getLogger(ARInitialContext.class);

    private MockContainer mockContainer;

    private AspectSystem aspectSystem;

    public ARInitialContext() throws NamingException
    {

    }

    /**
     * @return the mockContainer
     */
    public MockContainer getMockContainer()
    {
        return mockContainer;
    }

    /**
     * @param mockContainer the mockContainer to set
     */
    public void setMockContainer(MockContainer mockContainer)
    {
        this.mockContainer = mockContainer;
    }

    /**
     * @return the aspectSystem
     */
    public AspectSystem getAspectSystem()
    {
        return aspectSystem;
    }

    /**
     * @param aspectSystem the aspectSystem to set
     */
    public void setAspectSystem(AspectSystem aspectSystem)
    {
        this.aspectSystem = aspectSystem;
    }

    /**
     * Lookup responding object, if not existed, try to init it.
     * First try to init from custom init method(init+jndiName’s final part),
     * if failed, try to get BeanInfo from config file and init it.
     * @param jndiName
     * @return
     * @throws Exception
     */
    public Object lookup(String jndiName) throws NamingException
    {
        return lookup(jndiName, true);
    }

    public Object lookup(String jndiName, boolean tryInit) throws NamingException
    {
        Object objRef = null;
        try
        {
            objRef = super.lookup(jndiName);
            if (objRef != null)
            {
                return objRef;
            }
        }
        catch (NamingException e)
        {

        }
        if (tryInit)
        {
            return tryToInitBean(jndiName);
        }
        else
        {
            return objRef;
        }
    }

    /**
     * Init bean according to BeanInfo, can init entity bean, session bean and message driven bean.
     * @param jndi
     * @param beanInfo
     * @throws Exception
     */
    private void initBean(String jndi, BeanInfo beanInfo) throws Exception
    {
        log.debug("Init bean:" + beanInfo.getShortName() + ", JNDI:" + jndi);
        if (beanInfo.getType() == BeanInfo.ENTITY_BEAN)
        {
            initEntityBean(jndi, beanInfo);
        }
        else if (beanInfo.getType() == BeanInfo.SESSION_BEAN)
        {
            initSessionBean(jndi, beanInfo);
        }
        else if (beanInfo.getType() == BeanInfo.MESSAGE_BEAN)
        {
            initMessageBean(beanInfo);
        }
        else
        {
            log.error("Unsupported bean type: " + beanInfo.getType());
        }
    }

    /**
     * Init message bean, if the jndi name is start with "topic/", then it is topic type, otherwise, it is queue type.
     * The factory also is depending on its jndi name.
     * @param beanInfo
     * @throws Exception
     */
    private void initMessageBean(BeanInfo beanInfo) throws Exception
    {
        Class bean = ClassUtil.getClassForName(beanInfo.getBean());
        String jndi = beanInfo.getJndi();
        String factoryJndi = null;
        if (jndi.startsWith(Constant.TOPIC))
        {
            factoryJndi = Constant.TOPIC_CONNECTION_FACTORY;
        }
        else
        {
            factoryJndi = Constant.QUEUE_CONNECTION_FACTORY;
        }
        MDBDescriptor descriptor = new MDBDescriptor(factoryJndi, jndi, bean.newInstance());
        if (jndi.startsWith(Constant.TOPIC))
        {
            descriptor.setIsTopic(true);
        }
        mockContainer.deploy(descriptor);
        InvocationRecorder recorder = new InvocationRecorder();
        aspectSystem.add(new ClassPointcut(MessageListener.class, false), recorder);
    }

    public void initQueueConnectionFactory(String factoryJndi) throws Exception
    {
        MDBDescriptor descriptor = new MDBDescriptor(factoryJndi, Constant.MOCK_QUEUE, new BaseMessageBean());
        descriptor.setIsTopic(false);
        mockContainer.deploy(descriptor);
    }

    public void initTopicConnectionFactory(String factoryJndi) throws Exception
    {
        MDBDescriptor descriptor = new MDBDescriptor(factoryJndi, Constant.MOCK_TOPIC, new BaseMessageBean());
        descriptor.setIsTopic(true);
        mockContainer.deploy(descriptor);
    }

    private Object tryToInitBean(String jndiName)
    {
        try
        {
            BeanInfo beanInfo = EJBUtil.getBeanInfoByJndi(jndiName);
            if (beanInfo == null)
            {
                log.error("Can not find BeanInfo for " + jndiName);
                return null;
            }
            else
            {
                initBean(jndiName, beanInfo);
            }
            return super.lookup(jndiName);
        }
        catch (Exception e)
        {
            log.error("Can not init bean:" + jndiName);
            return null;
        }
    }

    /**
     * Inint entity bean and create all dummy record from dummy xml database.
     * @param jndi
     * @param beanInfo
     * @throws Exception
     */
    private void initEntityBean(String jndi, BeanInfo beanInfo) throws Exception
    {
        Class home = ClassUtil.getClassForName(beanInfo.getHome());
        Class remote = ClassUtil.getClassForName(beanInfo.getRemote());
        Class bean = ClassUtil.getClassForName(beanInfo.getBean());
        Class create = ClassUtil.getClassForName(Constant.ASPECT_PACKAGE + beanInfo.getShortName() + "CreateAspect");
        Class find = ClassUtil.getClassForName(Constant.ASPECT_PACKAGE + beanInfo.getShortName() + "FindAspect");
        Class setter = ClassUtil.getClassForName(Constant.ASPECT_PACKAGE + beanInfo.getShortName() + "SetterAspect");
        Aspect createAspect = null;
        Aspect findAspect = null;
        Aspect setterAspect = null;
        if (create != null)
        {
            createAspect = (Aspect) create.getConstructor(new Class[]
            { BeanInfo.class }).newInstance(new Object[]
            { beanInfo });
        }
        else
        {
            createAspect = new BaseCreateAspect(beanInfo);
        }
        if (find != null)
        {
            findAspect = (Aspect) find.getConstructor(new Class[]
            { BeanInfo.class }).newInstance(new Object[]
            { beanInfo });
        }
        else
        {
            findAspect = new BaseFindAspect(beanInfo);
        }
        if (setter != null)
        {
            setterAspect = (Aspect) setter.getConstructor(new Class[]
            { BeanInfo.class }).newInstance(new Object[]
            { beanInfo });
        }
        else
        {
            setterAspect = new BaseSetterAspect(beanInfo);
        }
        aspectSystem.add(createAspect);
        aspectSystem.add(findAspect);
        aspectSystem.add(setterAspect);
        EntityBeanDescriptor descriptor = new EntityBeanDescriptor(jndi, home, remote, bean);
        mockContainer.deploy(descriptor);
        Object homeObject = lookup(jndi);
        try
        {
            Method createMethod = ClassUtil.getMostSimpleCreateMethod(homeObject);
            Class[] parameterTypes = createMethod.getParameterTypes();
            Object[] values = new Object[parameterTypes.length];
            Iterator pks = DummyDataUtil.getPkValues(EJBUtil.getBeanInfoByJndi(jndi).getShortName()).iterator();
            while (pks.hasNext())
            {
                Long pk = (Long) pks.next();
                DataUtil.setPk(beanInfo.getShortName(), pk);
                createMethod.invoke(homeObject, values);
            }
            CommandUtil.executeCommands();
        }
        catch (Exception e)
        {
            log.warn("Can not init dummy data for " + jndi, e);
            try
            {
                DummyDataUtil.initDatabaseInfo(beanInfo);
            }
            catch (Exception e1)
            {
                log.warn("Can not init database info for " + jndi, e);
            }
        }
    }

    /**
     * Init session bean, maybe local type, depending on the jndi name
     * @param jndi
     * @param beanInfo
     * @throws Exception
     */
    private void initSessionBean(String jndi, BeanInfo beanInfo) throws Exception
    {
        Class home = null;
        Class remote = null;
        Class bean = ClassUtil.getClassForName(beanInfo.getBean());
        if (jndi.equals(beanInfo.getJndi()))
        {
            home = ClassUtil.getClassForName(beanInfo.getHome());
            remote = ClassUtil.getClassForName(beanInfo.getRemote());
        }
        else
        {
            home = ClassUtil.getClassForName(beanInfo.getLocalHome());
            remote = ClassUtil.getClassForName(beanInfo.getLocal());
        }
        Class aspectClass = ClassUtil.getClassForName(Constant.ASPECT_PACKAGE + beanInfo.getShortName() + "Aspect");
        Aspect aspect = null;
        if (aspectClass != null)
        {
            aspect = (Aspect) aspectClass.getConstructor(new Class[]
            { BeanInfo.class }).newInstance(new Object[]
            { beanInfo });
            aspectSystem.add(aspect);
        }
        SessionBeanDescriptor descriptor = new SessionBeanDescriptor(jndi, home, remote, bean);
        mockContainer.deploy(descriptor);
    }

    public void deploySessionBean(String jndi, Class home, Class remote, Object bean) throws Exception
    {
        SessionBeanDescriptor descriptor = new SessionBeanDescriptor(jndi, home, remote, bean);
        mockContainer.deploy(descriptor);
    }

}

(Visited 21 times, 1 visits today)