001    package com.mockrunner.mock.ejb;
002    
003    import javax.naming.Context;
004    import javax.naming.NameNotFoundException;
005    import javax.naming.NamingException;
006    import javax.transaction.UserTransaction;
007    
008    import org.apache.commons.logging.Log;
009    import org.apache.commons.logging.LogFactory;
010    import org.mockejb.MockContainer;
011    
012    import com.mockrunner.ejb.Configuration;
013    import com.mockrunner.ejb.JNDIUtil;
014    
015    /**
016     * Used to create all types of EJB mock objects. 
017     * Maintains the necessary dependencies between the mock objects.
018     * If you use the mock objects returned by this factory in your tests 
019     * you can be sure that they are all up to date.
020     * This factory takes the <code>UserTransaction</code> from the JNDI context. 
021     * If there's no transaction bound to the  context, the factory will create a
022     * {@link com.mockrunner.mock.ejb.MockUserTransaction} and bind it to the context.
023     * If the bound transaction is no
024     * {@link com.mockrunner.mock.ejb.MockUserTransaction},
025     * the method {@link #getMockUserTransaction} returns <code>null</code>.
026     * Use {@link #getUserTransaction} instead in this case.
027     * You can configure the JNDI name of the <code>UserTransaction</code> and
028     * the JNDI <code>Context</code> with the class 
029     * {@link com.mockrunner.ejb.Configuration}.
030     */
031    public class EJBMockObjectFactory
032    {
033        private final static Log log = LogFactory.getLog(EJBMockObjectFactory.class);
034        private Configuration configuration;
035        private UserTransaction transaction;
036        private MockContainer container;
037        private Context context;
038        
039        /**
040         * Creates a new set of mock objects.
041         */
042        public EJBMockObjectFactory()
043        { 
044            this(new Configuration());
045        }
046        
047        /**
048         * Creates a new set of mock objects based on the specified configuration.
049         */
050        public EJBMockObjectFactory(Configuration configuration)
051        { 
052            this.configuration = configuration;
053            initializeContext();
054            initializeEJBContainer();
055            initializeUserTransaction();
056        }
057    
058        private void initializeContext()
059        {
060            context = JNDIUtil.getContext(configuration);
061        }
062        
063        private void initializeUserTransaction()
064        {
065            try
066            {
067                try
068                {
069                    transaction = (UserTransaction)context.lookup(configuration.getUserTransactionJNDIName());
070                }
071                catch(NameNotFoundException nameExc)
072                {
073                    transaction = createMockUserTransaction();
074                    JNDIUtil.bindUserTransaction(configuration, context, transaction);
075                }
076            }
077            catch(Exception exc)
078            {
079                log.error(exc.getMessage(), exc);
080                transaction = createMockUserTransaction();
081            }
082            if(transaction instanceof MockUserTransaction)
083            {
084                ((MockUserTransaction)transaction).reset();
085            }
086        }
087        
088        private void initializeEJBContainer()
089        {
090            container = new MockContainer(context); 
091        }
092    
093        /**
094         * Creates the {@link com.mockrunner.mock.ejb.MockUserTransaction} using <code>new</code>.
095         * This method can be overridden to return a subclass of {@link com.mockrunner.mock.ejb.MockUserTransaction}.
096         * @return the {@link com.mockrunner.mock.ejb.MockUserTransaction}
097         */
098        public MockUserTransaction createMockUserTransaction()
099        {
100            return new MockUserTransaction();
101        }
102        
103        /**
104         * Calls <code>MockContextFactory.setAsInitial()</code>, if 
105         * <code>MockContextFactory</code> is not already the current
106         * context factory.
107         */
108        public void initMockContextFactory() throws NamingException
109        {
110            JNDIUtil.initMockContextFactory();
111        }
112        
113        /**
114         * Calls <code>MockContextFactory.revertSetAsInitial()</code>, if 
115         * <code>MockContextFactory</code> is the current context factory.
116         */
117        public void resetMockContextFactory()
118        {
119            JNDIUtil.resetMockContextFactory();
120        }
121        
122        /**
123         * Returns the {@link com.mockrunner.mock.ejb.MockUserTransaction}.
124         * If the bound transaction is no {@link com.mockrunner.mock.ejb.MockUserTransaction},
125         * this method returns <code>null</code>.
126         * @return the {@link com.mockrunner.mock.ejb.MockUserTransaction}
127         */
128        public MockUserTransaction getMockUserTransaction()
129        {
130            if(!(transaction instanceof MockUserTransaction)) return null;
131            return (MockUserTransaction)transaction;
132        }
133    
134        /**
135         * Returns the <code>UserTransaction</code>.
136         * @return the <code>UserTransaction</code>
137         */
138        public UserTransaction getUserTransaction()
139        {
140            return transaction;
141        }
142        
143        /**
144         * Returns the MockEJB <code>MockContainer</code>.
145         * @return the <code>MockContainer</code>
146         */
147        public MockContainer getMockContainer()
148        {
149            return container;
150        }
151        
152        /**
153         * Returns the JNDI context that is used by this factory. If you do not set
154         * a <code>Context</code> using {@link com.mockrunner.ejb.Configuration#setContext}}, 
155         * the JNDI implementation of MockEJB is used.
156         * @return the JNDI context
157         */
158        public Context getContext()
159        {
160            return context;
161        }
162    }