001: package com.quadcap.jdbc;
002:
003: /* Copyright 1999 - 2003 Quadcap Software. All rights reserved.
004: *
005: * This software is distributed under the Quadcap Free Software License.
006: * This software may be used or modified for any purpose, personal or
007: * commercial. Open Source redistributions are permitted. Commercial
008: * redistribution of larger works derived from, or works which bundle
009: * this software requires a "Commercial Redistribution License"; see
010: * http://www.quadcap.com/purchase.
011: *
012: * Redistributions qualify as "Open Source" under one of the following terms:
013: *
014: * Redistributions are made at no charge beyond the reasonable cost of
015: * materials and delivery.
016: *
017: * Redistributions are accompanied by a copy of the Source Code or by an
018: * irrevocable offer to provide a copy of the Source Code for up to three
019: * years at the cost of materials and delivery. Such redistributions
020: * must allow further use, modification, and redistribution of the Source
021: * Code under substantially the same terms as this license.
022: *
023: * Redistributions of source code must retain the copyright notices as they
024: * appear in each source code file, these license terms, and the
025: * disclaimer/limitation of liability set forth as paragraph 6 below.
026: *
027: * Redistributions in binary form must reproduce this Copyright Notice,
028: * these license terms, and the disclaimer/limitation of liability set
029: * forth as paragraph 6 below, in the documentation and/or other materials
030: * provided with the distribution.
031: *
032: * The Software is provided on an "AS IS" basis. No warranty is
033: * provided that the Software is free of defects, or fit for a
034: * particular purpose.
035: *
036: * Limitation of Liability. Quadcap Software shall not be liable
037: * for any damages suffered by the Licensee or any third party resulting
038: * from use of the Software.
039: */
040:
041: import java.io.File;
042: import java.io.IOException;
043:
044: import java.util.Enumeration;
045: import java.util.Hashtable;
046: import java.util.Properties;
047: import java.util.Vector;
048:
049: import java.sql.Driver;
050: import java.sql.DriverManager;
051: import java.sql.DriverPropertyInfo;
052: import java.sql.SQLException;
053:
054: import com.quadcap.sql.Cursor;
055: import com.quadcap.sql.Database;
056: import com.quadcap.sql.QedResultSet;
057: import com.quadcap.sql.QDriver;
058: import com.quadcap.sql.Session;
059: import com.quadcap.sql.Version;
060:
061: import com.quadcap.util.Config;
062: import com.quadcap.util.ConfigNumber;
063: import com.quadcap.util.Debug;
064: import com.quadcap.util.Util;
065:
066: /**
067: * This class implements the <code>java.sql.Driver</code> interface,
068: * which provides a basic mechanism for establishing connections to
069: * a QED database. A driver can support multiple simultaneously open
070: * databases -- the database URL specifies a file name which is the
071: * root directory of the database, and which is used to select the
072: * correct database.
073: *
074: * @author Stan Bailes
075: */
076: public class JdbcDriver implements QDriver {
077: /*{com.quadcap.qed.Trace-vars.xml-0}
078: *
079: * <config>
080: */
081:
082: /*{com.quadcap.qed.Trace-vars.xml-999999}
083: *
084: * </config>
085: */
086:
087: /*{com.quadcap.qed.Trace-vars.xml-1050}
088: * <config-var>
089: * <config-name>qed.trace.JdbcDriver</config-name>
090: * <config-dflt>0</config-dflt>
091: * <config-desc>
092: * <pre>
093: * bit 0: API execution
094: * bit 1: Database open/close
095: * </pre>
096: * </config-desc>
097: * </config-var>
098: */
099: //#ifdef DEBUG
100: static final ConfigNumber trace = ConfigNumber.find(
101: "qed.trace.JdbcDriver", "0");
102: //#endif
103:
104: static Hashtable dbs = new Hashtable();
105:
106: public static JdbcDriver jdbcDriver = null;
107:
108: static {
109: try {
110: DriverManager.registerDriver(jdbcDriver = new JdbcDriver());
111: } catch (SQLException e) {
112: Debug.print(e);
113: }
114: }
115:
116: /**
117: * No-argument constructor
118: */
119: public JdbcDriver() {
120: }
121:
122: /**
123: * Make a new <code>Connection</code> for the specified database
124: * and user.
125: * @deprecated <i>Pay no attention to that man behind the curtains.</i>
126: *
127: * @param db the database
128: * @param auth the userid
129: */
130: public java.sql.Connection makeConnection(Database db, String auth,
131: String passwd) throws SQLException {
132: //#ifdef DEBUG
133: if (trace.bit(0)) {
134: Debug.println("JdbcDriver.makeConnection()");
135: }
136: //#endif
137: return new Connection(db, auth, passwd);
138: }
139:
140: /**
141: * Make a <code>QedResultSet</code> to wrap the internal database
142: * cursor.
143: * @deprecated <i>Pay no attention to that man behind the curtains.</i>
144: *
145: * @param c the cursor
146: * @return the resultset
147: */
148: public QedResultSet makeResultSet(Cursor c) {
149: return new ResultSet(c);
150: }
151:
152: /**
153: * Return true if this is a QED JDBC URL. QED URLS are of the
154: * form <code>jdbc:qed:<i>database</i></code>.
155: *
156: * @param url a URL
157: * @return true if <code>url</code> is a QED JDBC URL.
158: */
159: public boolean acceptsURL(String url) {
160: if (url.startsWith("jdbc:")) {
161: url = url.substring(5);
162: int idx = url.indexOf(':');
163: if (idx > 0) {
164: String protocol = url.substring(0, idx);
165: if (protocol.equals("quadcap"))
166: return true;
167: if (protocol.equals("qed"))
168: return true;
169: }
170: }
171: return false;
172: }
173:
174: /**
175: * Assuming that <code>url</code> is a QED URL, return a new
176: * <code>Connection</code> object that can be used to access the
177: * database specified by that url.
178: *
179: * @param url a JDBC URL. If the URL string contains a semicolon,
180: * then the URL proper is interpreted as the portion of the
181: * string preceeding the semicolon, and the remaining string
182: * is treated as a semi-colon separated list of 'name=value'
183: * connection properties. E.g., <code>jdbc:qed:db1;create=true</code>
184: *
185: * @param props a set of connection properties.
186: * @return a new Connection
187: * @exception SQLException may be thrown
188: */
189: public java.sql.Connection connect(String url, Properties props)
190: throws SQLException {
191: //#ifdef DEBUG
192: if (trace.bit(0)) {
193: Debug.println("JdbcDriver.connect(" + url + ", " + props
194: + ")");
195: }
196: //#endif
197: if (!acceptsURL(url))
198: return null;
199: String origUrl = url;
200: url = url.substring(5);
201: int idx = url.indexOf(';');
202: if (idx >= 0) {
203: String extraProps = url.substring(idx + 1);
204: url = url.substring(0, idx);
205: Properties props2 = new Properties(Config
206: .getPropSubset("qed.*"));
207: props2.putAll(props);
208: props2.putAll(Util.parsePropsString(extraProps));
209: props = props2;
210: }
211:
212: idx = url.indexOf(':');
213: String param = url.substring(idx + 1);
214:
215: Database db = null;
216: try {
217: param = new File(param).getCanonicalPath();
218: synchronized (dbs) {
219: db = (Database) dbs.get(param);
220: if (db == null) {
221: //#ifdef DEBUG
222: if (trace.bit(1)) {
223: Debug.println("Open database " + dbs.size()
224: + ": " + param);
225: }
226: //#endif
227: db = new Database();
228: db.init(this , origUrl, param, props);
229: db.driverLock = dbs;
230: dbs.put(param, db);
231: }
232: db.addConnection();
233: }
234: } catch (IOException e) {
235: Debug.print(e);
236: throw new SQLException(e.toString(), "Q000Z");
237: }
238:
239: String auth = props.getProperty("user");
240: String pass = props.getProperty("passwd");
241: Connection conn = null;
242: try {
243: conn = new Connection(db, auth, pass);
244: } finally {
245: // in case an (auth?) exception is thrown, we need to avoid
246: // leaking the connection.
247: if (conn == null) {
248: synchronized (dbs) {
249: db.removeConnection();
250: }
251: }
252: }
253: return conn;
254: }
255:
256: /**
257: * Return the driver major version number.
258: *
259: * @return the driver's major version number
260: */
261: public int getMajorVersion() {
262: return Version.majorVersion;
263: }
264:
265: /**
266: * Return the driver minor version number.
267: *
268: * @return the driver's minor version number
269: */
270: public int getMinorVersion() {
271: return Version.minorVersion;
272: }
273:
274: /**
275: * Return an array of <code>DriverPropertyInfo</code> objects
276: * that describe the properties required to connect to a
277: * QED database. Currently no properties are required except
278: * <code>user</code>
279: *
280: * @param url the database url
281: * @param info the properties the client has so far.
282: * @return the required connect properties
283: */
284: public DriverPropertyInfo[] getPropertyInfo(String url,
285: Properties info) throws SQLException {
286: int cnt = 0;
287: if (info == null || info.get("user") == null)
288: cnt++;
289: DriverPropertyInfo[] ret = new DriverPropertyInfo[cnt];
290: if (cnt != 0) {
291: ret[0] = new DriverPropertyInfo("user", null);
292: ret[0].required = true;
293: }
294: return ret;
295: }
296:
297: /**
298: * QED is a JDBC compliant driver
299: *
300: * @return true
301: */
302: public boolean jdbcCompliant() {
303: return true; // since 3.1, we're declaring success...
304: }
305:
306: /**
307: * Close the specified database.
308: * @deprecated <i>Pay no attention to that man behind the curtains.</i>
309: *
310: * @param name the name of the database.
311: */
312: public void closeDatabase(final String name) {
313: //#ifdef DEBUG
314: if (trace.bit(1)) {
315: Debug.println("closeDatabase(" + name + ")");
316: }
317: //#endif
318: synchronized (dbs) {
319: Database db = (Database) dbs.get(name);
320: if (db != null) {
321: try {
322: db.close();
323: } finally {
324: dbs.remove(name);
325: }
326: }
327: }
328: //#ifdef DEBUG
329: if (trace.bit(1)) {
330: Debug.println("closeDatabase(" + name + ") complete");
331: }
332: //#endif
333: }
334:
335: /**
336: * Enumerate the currently open databases
337: * @deprecated <i>Pay no attention to that man behind the curtains.</i>.
338: *
339: * @return an enumeration of the names of the currently open databases
340: */
341: public Enumeration getDatabaseNames() {
342: return dbs.keys();
343: }
344:
345: /**
346: * Locate a specific database by name
347: * @deprecated <i>Pay no attention to that man behind the curtains.</i>.
348: *
349: * @param name the name of the database
350: * @return the database.
351: */
352: public Database getDatabase(String name) {
353: synchronized (dbs) {
354: return (Database) dbs.get(name);
355: }
356: }
357:
358: /**
359: * Close all databases (presumably at program exit)
360: */
361: public static void closeAll() {
362: synchronized (dbs) {
363: Enumeration e = JdbcDriver.dbs.elements();
364: while (e.hasMoreElements()) {
365: Database db = (Database) e.nextElement();
366: try {
367: db.close();
368: } catch (Throwable t) {
369: }
370: }
371: dbs.clear();
372: }
373: }
374:
375: /**
376: * Return the session for this connection
377: */
378: public Session getSession(java.sql.Connection conn) {
379: try {
380: QDriver d = (QDriver) DriverManager.getDriver("jdbc:qed");
381: return d.getSession(conn);
382: } catch (SQLException ex) {
383: return null;
384: }
385: }
386: }
|