Quadcap Embeddable Database

com/quadcap/jdbc/JdbcDriver.java

Go to the documentation of this file.
00001 package com.quadcap.jdbc; 00002 00003 /* Copyright 1999 - 2003 Quadcap Software. All rights reserved. 00004 * 00005 * This software is distributed under the Quadcap Free Software License. 00006 * This software may be used or modified for any purpose, personal or 00007 * commercial. Open Source redistributions are permitted. Commercial 00008 * redistribution of larger works derived from, or works which bundle 00009 * this software requires a "Commercial Redistribution License"; see 00010 * http://www.quadcap.com/purchase. 00011 * 00012 * Redistributions qualify as "Open Source" under one of the following terms: 00013 * 00014 * Redistributions are made at no charge beyond the reasonable cost of 00015 * materials and delivery. 00016 * 00017 * Redistributions are accompanied by a copy of the Source Code or by an 00018 * irrevocable offer to provide a copy of the Source Code for up to three 00019 * years at the cost of materials and delivery. Such redistributions 00020 * must allow further use, modification, and redistribution of the Source 00021 * Code under substantially the same terms as this license. 00022 * 00023 * Redistributions of source code must retain the copyright notices as they 00024 * appear in each source code file, these license terms, and the 00025 * disclaimer/limitation of liability set forth as paragraph 6 below. 00026 * 00027 * Redistributions in binary form must reproduce this Copyright Notice, 00028 * these license terms, and the disclaimer/limitation of liability set 00029 * forth as paragraph 6 below, in the documentation and/or other materials 00030 * provided with the distribution. 00031 * 00032 * The Software is provided on an "AS IS" basis. No warranty is 00033 * provided that the Software is free of defects, or fit for a 00034 * particular purpose. 00035 * 00036 * Limitation of Liability. Quadcap Software shall not be liable 00037 * for any damages suffered by the Licensee or any third party resulting 00038 * from use of the Software. 00039 */ 00040 00041 import java.io.File; 00042 import java.io.IOException; 00043 00044 import java.util.Enumeration; 00045 import java.util.Hashtable; 00046 import java.util.Properties; 00047 import java.util.Vector; 00048 00049 import java.sql.Driver; 00050 import java.sql.DriverManager; 00051 import java.sql.DriverPropertyInfo; 00052 import java.sql.SQLException; 00053 00054 import com.quadcap.sql.Cursor; 00055 import com.quadcap.sql.Database; 00056 import com.quadcap.sql.QedResultSet; 00057 import com.quadcap.sql.QDriver; 00058 import com.quadcap.sql.Session; 00059 import com.quadcap.sql.Version; 00060 00061 import com.quadcap.util.Config; 00062 import com.quadcap.util.ConfigNumber; 00063 import com.quadcap.util.Debug; 00064 import com.quadcap.util.Util; 00065 00066 /** 00067 * This class implements the <code>java.sql.Driver</code> interface, 00068 * which provides a basic mechanism for establishing connections to 00069 * a QED database. A driver can support multiple simultaneously open 00070 * databases -- the database URL specifies a file name which is the 00071 * root directory of the database, and which is used to select the 00072 * correct database. 00073 * 00074 * @author Stan Bailes 00075 */ 00076 public class JdbcDriver implements QDriver { 00077 /*{com.quadcap.qed.Trace-vars.xml-0} 00078 * 00079 * <config> 00080 */ 00081 00082 /*{com.quadcap.qed.Trace-vars.xml-999999} 00083 * 00084 * </config> 00085 */ 00086 00087 /*{com.quadcap.qed.Trace-vars.xml-1050} 00088 * <config-var> 00089 * <config-name>qed.trace.JdbcDriver</config-name> 00090 * <config-dflt>0</config-dflt> 00091 * <config-desc> 00092 * <pre> 00093 * bit 0: API execution 00094 * bit 1: Database open/close 00095 * </pre> 00096 * </config-desc> 00097 * </config-var> 00098 */ 00099 //#ifdef DEBUG 00100 static final ConfigNumber trace = 00101 ConfigNumber.find("qed.trace.JdbcDriver", "0"); 00102 //#endif 00103 00104 static Hashtable dbs = new Hashtable(); 00105 00106 public static JdbcDriver jdbcDriver = null; 00107 00108 static { 00109 try { 00110 DriverManager.registerDriver(jdbcDriver = new JdbcDriver()); 00111 } catch (SQLException e) { 00112 Debug.print(e); 00113 } 00114 } 00115 00116 /** 00117 * No-argument constructor 00118 */ 00119 public JdbcDriver() { 00120 } 00121 00122 /** 00123 * Make a new <code>Connection</code> for the specified database 00124 * and user. 00125 * @deprecated <i>Pay no attention to that man behind the curtains.</i> 00126 * 00127 * @param db the database 00128 * @param auth the userid 00129 */ 00130 public java.sql.Connection makeConnection(Database db, String auth, 00131 String passwd) 00132 throws SQLException 00133 { 00134 //#ifdef DEBUG 00135 if (trace.bit(0)) { 00136 Debug.println("JdbcDriver.makeConnection()"); 00137 } 00138 //#endif 00139 return new Connection(db, auth, passwd); 00140 } 00141 00142 /** 00143 * Make a <code>QedResultSet</code> to wrap the internal database 00144 * cursor. 00145 * @deprecated <i>Pay no attention to that man behind the curtains.</i> 00146 * 00147 * @param c the cursor 00148 * @return the resultset 00149 */ 00150 public QedResultSet makeResultSet(Cursor c) { 00151 return new ResultSet(c); 00152 } 00153 00154 /** 00155 * Return true if this is a QED JDBC URL. QED URLS are of the 00156 * form <code>jdbc:qed:<i>database</i></code>. 00157 * 00158 * @param url a URL 00159 * @return true if <code>url</code> is a QED JDBC URL. 00160 */ 00161 public boolean acceptsURL(String url) { 00162 if (url.startsWith("jdbc:")) { 00163 url = url.substring(5); 00164 int idx = url.indexOf(':'); 00165 if (idx > 0) { 00166 String protocol = url.substring(0, idx); 00167 if (protocol.equals("quadcap")) return true; 00168 if (protocol.equals("qed")) return true; 00169 } 00170 } 00171 return false; 00172 } 00173 00174 /** 00175 * Assuming that <code>url</code> is a QED URL, return a new 00176 * <code>Connection</code> object that can be used to access the 00177 * database specified by that url. 00178 * 00179 * @param url a JDBC URL. If the URL string contains a semicolon, 00180 * then the URL proper is interpreted as the portion of the 00181 * string preceeding the semicolon, and the remaining string 00182 * is treated as a semi-colon separated list of 'name=value' 00183 * connection properties. E.g., <code>jdbc:qed:db1;create=true</code> 00184 * 00185 * @param props a set of connection properties. 00186 * @return a new Connection 00187 * @exception SQLException may be thrown 00188 */ 00189 public java.sql.Connection connect(String url, Properties props) 00190 throws SQLException 00191 { 00192 //#ifdef DEBUG 00193 if (trace.bit(0)) { 00194 Debug.println("JdbcDriver.connect(" + url + ", " + props + ")"); 00195 } 00196 //#endif 00197 if (!acceptsURL(url)) return null; 00198 String origUrl = url; 00199 url = url.substring(5); 00200 int idx = url.indexOf(';'); 00201 if (idx >= 0) { 00202 String extraProps = url.substring(idx+1); 00203 url = url.substring(0, idx); 00204 Properties props2 = new Properties(Config.getPropSubset("qed.*")); 00205 props2.putAll(props); 00206 props2.putAll(Util.parsePropsString(extraProps)); 00207 props = props2; 00208 } 00209 00210 idx = url.indexOf(':'); 00211 String param = url.substring(idx+1); 00212 00213 Database db = null; 00214 try { 00215 param = new File(param).getCanonicalPath(); 00216 synchronized (dbs) { 00217 db = (Database)dbs.get(param); 00218 if (db == null) { 00219 //#ifdef DEBUG 00220 if (trace.bit(1)) { 00221 Debug.println("Open database " + dbs.size() + ": " + param); 00222 } 00223 //#endif 00224 db = new Database(); 00225 db.init(this, origUrl, param, props); 00226 db.driverLock = dbs; 00227 dbs.put(param, db); 00228 } 00229 db.addConnection(); 00230 } 00231 } catch (IOException e) { 00232 Debug.print(e); 00233 throw new SQLException(e.toString(), "Q000Z"); 00234 } 00235 00236 String auth = props.getProperty("user"); 00237 String pass = props.getProperty("passwd"); 00238 Connection conn = null; 00239 try { 00240 conn = new Connection(db, auth, pass); 00241 } finally { 00242 // in case an (auth?) exception is thrown, we need to avoid 00243 // leaking the connection. 00244 if (conn == null) { 00245 synchronized (dbs) { 00246 db.removeConnection(); 00247 } 00248 } 00249 } 00250 return conn; 00251 } 00252 00253 /** 00254 * Return the driver major version number. 00255 * 00256 * @return the driver's major version number 00257 */ 00258 public int getMajorVersion() { return Version.majorVersion; } 00259 00260 /** 00261 * Return the driver minor version number. 00262 * 00263 * @return the driver's minor version number 00264 */ 00265 public int getMinorVersion() { return Version.minorVersion; } 00266 00267 /** 00268 * Return an array of <code>DriverPropertyInfo</code> objects 00269 * that describe the properties required to connect to a 00270 * QED database. Currently no properties are required except 00271 * <code>user</code> 00272 * 00273 * @param url the database url 00274 * @param info the properties the client has so far. 00275 * @return the required connect properties 00276 */ 00277 public DriverPropertyInfo[] getPropertyInfo(String url, 00278 Properties info) 00279 throws SQLException 00280 { 00281 int cnt = 0; 00282 if (info == null || info.get("user") == null) cnt++; 00283 DriverPropertyInfo[] ret = new DriverPropertyInfo[cnt]; 00284 if (cnt != 0) { 00285 ret[0] = new DriverPropertyInfo("user", null); 00286 ret[0].required = true; 00287 } 00288 return ret; 00289 } 00290 00291 /** 00292 * QED is a JDBC compliant driver 00293 * 00294 * @return true 00295 */ 00296 public boolean jdbcCompliant() { 00297 return true; // since 3.1, we're declaring success... 00298 } 00299 00300 /** 00301 * Close the specified database. 00302 * @deprecated <i>Pay no attention to that man behind the curtains.</i> 00303 * 00304 * @param name the name of the database. 00305 */ 00306 public void closeDatabase(final String name) { 00307 //#ifdef DEBUG 00308 if (trace.bit(1)) { 00309 Debug.println("closeDatabase(" + name + ")"); 00310 } 00311 //#endif 00312 synchronized (dbs) { 00313 Database db = (Database)dbs.get(name); 00314 if (db != null) { 00315 try { 00316 db.close(); 00317 } finally { 00318 dbs.remove(name); 00319 } 00320 } 00321 } 00322 //#ifdef DEBUG 00323 if (trace.bit(1)) { 00324 Debug.println("closeDatabase(" + name + ") complete"); 00325 } 00326 //#endif 00327 } 00328 00329 /** 00330 * Enumerate the currently open databases 00331 * @deprecated <i>Pay no attention to that man behind the curtains.</i>. 00332 * 00333 * @return an enumeration of the names of the currently open databases 00334 */ 00335 public Enumeration getDatabaseNames() { 00336 return dbs.keys(); 00337 } 00338 00339 /** 00340 * Locate a specific database by name 00341 * @deprecated <i>Pay no attention to that man behind the curtains.</i>. 00342 * 00343 * @param name the name of the database 00344 * @return the database. 00345 */ 00346 public Database getDatabase(String name) { 00347 synchronized (dbs) { 00348 return (Database)dbs.get(name); 00349 } 00350 } 00351 00352 /** 00353 * Close all databases (presumably at program exit) 00354 */ 00355 public static void closeAll() { 00356 synchronized (dbs) { 00357 Enumeration e = JdbcDriver.dbs.elements(); 00358 while (e.hasMoreElements()) { 00359 Database db = (Database)e.nextElement(); 00360 try { 00361 db.close(); 00362 } catch (Throwable t) { 00363 } 00364 } 00365 dbs.clear(); 00366 } 00367 } 00368 00369 /** 00370 * Return the session for this connection 00371 */ 00372 public Session getSession(java.sql.Connection conn) { 00373 try { 00374 QDriver d = (QDriver)DriverManager.getDriver("jdbc:qed"); 00375 return d.getSession(conn); 00376 } catch (SQLException ex) { 00377 return null; 00378 } 00379 } 00380 }