001    package com.mockrunner.mock.jdbc;
002    
003    import java.sql.Driver;
004    import java.sql.DriverManager;
005    import java.sql.SQLException;
006    import java.util.Enumeration;
007    import java.util.HashSet;
008    import java.util.Iterator;
009    import java.util.Set;
010    
011    import com.mockrunner.base.NestedApplicationException;
012    
013    /**
014     * Used to create all types of JDBC mock objects. 
015     * Maintains the necessary dependencies between the mock objects.
016     * If you use the mock objects returned by this
017     * factory in your tests you can be sure that they are all
018     * up to date.
019     * Please note, that this class removes all drivers
020     * from the JDBC <code>DriverManager</code> and registers
021     * the {@link MockDriver}. All drivers are preserved and
022     * can be restored with {@link #restoreDrivers}.
023     */
024    public class JDBCMockObjectFactory
025    {
026        private MockDataSource dataSource;
027        private MockDriver driver;
028        private MockConnection connection;
029        private Set preservedDrivers;
030        
031        /**
032         * Creates a new set of mock objects.
033         */
034        public JDBCMockObjectFactory()
035        {
036            dataSource = createMockDataSource();
037            driver = createMockDriver();
038            connection = createMockConnection();
039            preservedDrivers = new HashSet();
040            setUpDependencies();
041        }
042    
043        private void setUpDependencies()
044        {
045            dataSource.setupConnection(connection);
046            driver.setupConnection(connection);
047            registerMockDriver();
048        }
049    
050        private void deregisterDrivers()
051        {
052            try
053            {
054                Enumeration drivers = DriverManager.getDrivers();
055                while(drivers.hasMoreElements())
056                {
057                    DriverManager.deregisterDriver((Driver)drivers.nextElement());
058                }
059            }
060            catch(SQLException exc)
061            {
062                throw new NestedApplicationException(exc);
063            }
064        }
065        
066        private void deregisterMockDrivers()
067        {
068            try
069            {
070                Enumeration drivers = DriverManager.getDrivers();
071                while(drivers.hasMoreElements())
072                {
073                    Driver currentDriver = (Driver)drivers.nextElement();
074                    if(currentDriver instanceof MockDriver)
075                    {
076                        DriverManager.deregisterDriver(currentDriver);
077                    }
078                }
079            }
080            catch(SQLException exc)
081            {
082                throw new NestedApplicationException(exc);
083            }
084        }
085        
086        private void preserveDrivers()
087        {
088            Enumeration drivers = DriverManager.getDrivers();
089            while(drivers.hasMoreElements())
090            {
091                Driver currentDriver = (Driver)drivers.nextElement();
092                if(!(currentDriver instanceof MockDriver))
093                {
094                    preservedDrivers.add(currentDriver);
095                }
096            }
097        }
098        
099        /**
100         * Removes all JDBC drivers from the <code>DriveManager</code> and
101         * registers the mock driver. The removed drivers are preserved and
102         * can be restored with {@link #restoreDrivers}.
103         */
104        public void registerMockDriver()
105        {
106            try
107            {
108                preserveDrivers();
109                deregisterDrivers();
110                DriverManager.registerDriver(driver);
111            }
112            catch(SQLException exc)
113            {
114                throw new NestedApplicationException(exc);
115            }
116        }
117        
118        /**
119         * Since <code>JDBCMockObjectFactory</code> removes all the
120         * drivers from the <code>DriveManager</code> (so the
121         * {@link MockDriver} is guaranteed to be the only one)
122         * you can use this method to restore the original drivers.
123         * Automatically called by {@link com.mockrunner.base.BaseTestCase#tearDown}.
124         */
125        public void restoreDrivers()
126        {
127            deregisterMockDrivers();
128            try
129            {
130                Iterator drivers = preservedDrivers.iterator();
131                while(drivers.hasNext())
132                {
133                    DriverManager.registerDriver((Driver)drivers.next());
134                }
135            }
136            catch(SQLException exc)
137            {
138                throw new NestedApplicationException(exc);
139            }
140            preservedDrivers.clear();
141        }
142        
143        /**
144         * Creates the {@link com.mockrunner.mock.jdbc.MockConnection} using <code>new</code>.
145         * This method can be overridden to return a subclass of {@link com.mockrunner.mock.jdbc.MockConnection}.
146         * @return the {@link com.mockrunner.mock.jdbc.MockConnection}
147         */
148        public MockConnection createMockConnection()
149        {
150            return new MockConnection();
151        }
152    
153        /**
154         * Creates the {@link com.mockrunner.mock.jdbc.MockDriver} using <code>new</code>.
155         * This method can be overridden to return a subclass of {@link com.mockrunner.mock.jdbc.MockDriver}.
156         * @return the {@link com.mockrunner.mock.jdbc.MockDriver}
157         */
158        public MockDriver createMockDriver()
159        {
160            return new MockDriver();
161        }
162    
163        /**
164         * Creates the {@link com.mockrunner.mock.jdbc.MockDataSource} using <code>new</code>.
165         * This method can be overridden to return a subclass of {@link com.mockrunner.mock.jdbc.MockDataSource}.
166         * @return the {@link com.mockrunner.mock.jdbc.MockDataSource}
167         */
168        public MockDataSource createMockDataSource()
169        {
170            return new MockDataSource();
171        }
172    
173        /**
174         * Returns the {@link com.mockrunner.mock.jdbc.MockDataSource}.
175         * @return the {@link com.mockrunner.mock.jdbc.MockDataSource}
176         */
177        public MockDataSource getMockDataSource()
178        {
179            return dataSource;
180        }
181        
182        /**
183         * Returns the {@link com.mockrunner.mock.jdbc.MockDriver}.
184         * @return the {@link com.mockrunner.mock.jdbc.MockDriver}
185         */
186        public MockDriver getMockDriver()
187        {
188            return driver;
189        }
190    
191        /**
192         * Returns the {@link com.mockrunner.mock.jdbc.MockConnection}.
193         * @return the {@link com.mockrunner.mock.jdbc.MockConnection}
194         */
195        public MockConnection getMockConnection()
196        {
197            return connection;
198        }
199    }