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