KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > db > explorer > DbDriverManager


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.db.explorer;
21
22 import java.sql.Connection JavaDoc;
23 import java.sql.Driver JavaDoc;
24 import java.sql.DriverManager JavaDoc;
25 import java.sql.SQLException JavaDoc;
26 import java.util.HashSet JavaDoc;
27 import java.util.Iterator JavaDoc;
28 import java.util.Map JavaDoc;
29 import java.util.Properties JavaDoc;
30 import java.util.Set JavaDoc;
31 import java.util.WeakHashMap JavaDoc;
32 import org.netbeans.api.db.explorer.JDBCDriver;
33 import org.openide.ErrorManager;
34
35 /**
36  * Class to load drivers and create connections. It can find drivers and connections from
37  * several sources: previously registered drivers, URLs from a JDBCDriver instance or
38  * drivers registered to java.sql.DriverManager, exactly this order. DriverManager
39  * has the lowest priority since we should always try to use the drivers defined by the
40  * user in the DB Explorer, even if the same driver class is on the IDE's classpath.
41  * (since the driver on the IDE's classpath could be a wrong/old version).
42  *
43  * <p>The advantage of this class over DriverManager is that it can work in a multi-class-loader
44  * environment. That is, registered drivers can retrieved regardless of the class loader of the
45  * caller of the getDriver() method.</p>
46  *
47  * <p>This class also caches and reuses the class loaders used to load the drivers' JAR files.
48  * It is not perfect, since when the JDBC driver properties are changed in the UI a new
49  * JDBCDriver instance is created, thus a new class loader is created for it. This
50  * has multiple implications, see issue 63957 and issue 76922.</p>
51  *
52  * @author Andrei Badea
53  */

54 public class DbDriverManager {
55     
56     private static final ErrorManager LOGGER = ErrorManager.getDefault().getInstance("org.netbeans.modules.db.explorer.DbDriverManager"); // NOI18N
57
private static final boolean LOG = LOGGER.isLoggable(ErrorManager.INFORMATIONAL);
58     
59     private static final DbDriverManager DEFAULT = new DbDriverManager();
60     
61     private Set JavaDoc registeredDrivers;
62     
63     /**
64      * Maps each connection to the driver used to create that connection.
65      */

66     private Map JavaDoc/*<Connection, Driver>*/ conn2Driver = new WeakHashMap JavaDoc();
67     
68     /**
69      * Maps each driver to the class loader for that driver.
70      */

71     private Map JavaDoc/*<JDBCDriver, ClassLoader>*/ driver2Loader = new WeakHashMap JavaDoc();
72     
73     private DbDriverManager() {
74     }
75     
76     /**
77      * Returns the singleton instance.
78      */

79     public static DbDriverManager getDefault() {
80         return DEFAULT;
81     }
82     
83     /**
84      * Gets a connection to databaseURL using jdbcDriver as a fallback.
85      *
86      * @param databaseURL
87      * @param props
88      * @param jdbcDriver the fallback JDBCDriver; can be null
89      */

90     public Connection JavaDoc getConnection(String JavaDoc databaseURL, Properties JavaDoc props, JDBCDriver jdbcDriver) throws SQLException JavaDoc {
91         if (LOG) {
92             LOGGER.log(ErrorManager.INFORMATIONAL, "Attempting to connect to '" + databaseURL + "'"); // NOI18N
93
}
94         
95         // try to find a registered driver or use the supplied jdbcDriver
96
// we'll look ourselves in DriverManager, don't look there
97
Driver JavaDoc driver = getDriverInternal(databaseURL, jdbcDriver, false);
98         if (driver != null) {
99             Connection JavaDoc conn = driver.connect(databaseURL, props);
100             if (conn == null) {
101                 if (LOG) {
102                     LOGGER.log(ErrorManager.INFORMATIONAL, driver.getClass().getName() + ".connect() returned null"); // NOI18N
103
}
104                 throw createDriverNotFoundException();
105             }
106             synchronized (conn2Driver) {
107                 conn2Driver.put(conn, driver);
108             }
109             return conn;
110         }
111         
112         // try to find a connection using DriverManager
113
try {
114             Connection JavaDoc conn = DriverManager.getConnection(databaseURL, props);
115             synchronized (conn2Driver) {
116                 conn2Driver.put(conn, driver);
117             }
118             return conn;
119         } catch (SQLException JavaDoc e) {
120             // ignore it, we throw our own exceptions
121
}
122         
123         throw createDriverNotFoundException();
124     }
125     
126     /**
127      * Returns a connection coming from the same driver as the conn parameter.
128      */

129     public Connection JavaDoc getSameDriverConnection(Connection JavaDoc existingConn, String JavaDoc databaseURL, Properties JavaDoc props) throws SQLException JavaDoc {
130         if (existingConn == null) {
131             throw new NullPointerException JavaDoc();
132         }
133         Driver JavaDoc driver = null;
134         synchronized (conn2Driver) {
135             if (!conn2Driver.containsKey(existingConn)) {
136                 throw new IllegalArgumentException JavaDoc("A connection not obtained through DbDriverManager was passed."); // NOI18N
137
}
138             driver = (Driver JavaDoc)conn2Driver.get(existingConn);
139         }
140         if (driver != null) {
141             Connection JavaDoc newConn = driver.connect(databaseURL, props);
142             if (newConn == null) {
143                 throw new SQLException JavaDoc("Unable to connect using existingConn's original driver", "08001"); // NOI18N
144
}
145             conn2Driver.put(newConn, driver);
146             return newConn;
147         } else {
148             return DriverManager.getConnection(databaseURL, props);
149         }
150     }
151     
152     /**
153      * Register a new driver.
154      */

155     public synchronized void registerDriver(Driver JavaDoc driver) {
156         if (registeredDrivers == null) {
157             registeredDrivers = new HashSet JavaDoc();
158         }
159         registeredDrivers.add(driver);
160     }
161     
162     /**
163      * Deregister a previously registered driver.
164      */

165     public synchronized void deregisterDriver(Driver JavaDoc driver) {
166         if (registeredDrivers == null) {
167             return;
168         }
169         registeredDrivers.remove(driver);
170     }
171     
172     /**
173      * Gets a driver which accepts databaseURL using jdbcDriver as a fallback.
174      *
175      * <p>No checks are made as if the driver loaded from jdbcDriver accepts
176      * databaseURL.</p>
177      */

178     public Driver JavaDoc getDriver(String JavaDoc databaseURL, JDBCDriver jdbcDriver) throws SQLException JavaDoc {
179         Driver JavaDoc d = getDriverInternal(databaseURL, jdbcDriver, true);
180         if (d == null) {
181             throw createDriverNotFoundException();
182         }
183         return d;
184     }
185     
186     /**
187      * Gets a driver, but can skip DriverManager and doesn't throw SQLException if a driver can't be found.
188      */

189     private Driver JavaDoc getDriverInternal(String JavaDoc databaseURL, JDBCDriver jdbcDriver, boolean lookInDriverManager) throws SQLException JavaDoc {
190         // try the registered drivers first
191
synchronized (this) {
192             if (registeredDrivers != null) {
193                 for (Iterator JavaDoc i = registeredDrivers.iterator(); i.hasNext();) {
194                     Driver JavaDoc d = (Driver JavaDoc)i.next();
195                     try {
196                         if (d.acceptsURL(databaseURL)) {
197                             return d;
198                         }
199                     } catch (SQLException JavaDoc e) {
200                         // ignore it, we don't want to exit prematurely
201
}
202                 }
203             }
204         }
205         
206         // didn't find it, try to load it from jdbcDriver, if any
207
if (jdbcDriver != null) {
208             ClassLoader JavaDoc l = getClassLoader(jdbcDriver);
209             try {
210                 return (Driver JavaDoc)Class.forName(jdbcDriver.getClassName(), true, l).newInstance();
211             } catch (Exception JavaDoc e) {
212                 SQLException JavaDoc sqlex = createDriverNotFoundException();
213                 sqlex.initCause(e);
214                 throw sqlex;
215             }
216         }
217         
218         // still nothing, try DriverManager
219
if (lookInDriverManager) {
220             try {
221                 return DriverManager.getDriver(databaseURL);
222             } catch (SQLException JavaDoc e) {
223                 // ignore it, we don't throw exceptions
224
}
225         }
226         
227         return null;
228     }
229     
230     private ClassLoader JavaDoc getClassLoader(JDBCDriver driver) {
231         ClassLoader JavaDoc loader = null;
232         synchronized (driver2Loader) {
233             loader = (ClassLoader JavaDoc)driver2Loader.get(driver);
234             if (loader == null) {
235                 loader = new DbURLClassLoader(driver.getURLs());
236                 if (LOG) {
237                     LOGGER.log(ErrorManager.INFORMATIONAL, "Creating " + loader); // NOI18N
238
}
239                 driver2Loader.put(driver, loader);
240             } else {
241                 if (LOG) {
242                     LOGGER.log(ErrorManager.INFORMATIONAL, "Reusing " + loader); // NOI18N
243
}
244             }
245         }
246         return loader;
247     }
248     
249     private SQLException JavaDoc createDriverNotFoundException() {
250         return new SQLException JavaDoc("Unable to find a suitable driver", "08001"); // NOI18N
251
}
252 }
253
Popular Tags