KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > ziclix > python > sql > PyConnection


1 /*
2  * Jython Database Specification API 2.0
3  *
4  * $Id: PyConnection.java,v 1.14 2005/02/23 04:26:18 bzimmer Exp $
5  *
6  * Copyright (c) 2001 brian zimmer <bzimmer@ziclix.com>
7  *
8  */

9 package com.ziclix.python.sql;
10
11 import com.ziclix.python.sql.util.PyArgParser;
12 import org.python.core.ClassDictInit;
13 import org.python.core.Py;
14 import org.python.core.PyBuiltinFunctionSet;
15 import org.python.core.PyClass;
16 import org.python.core.PyInteger;
17 import org.python.core.PyList;
18 import org.python.core.PyObject;
19 import org.python.core.PyString;
20
21 import java.sql.Connection JavaDoc;
22 import java.sql.SQLException JavaDoc;
23 import java.util.Collections JavaDoc;
24 import java.util.HashSet JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.Set JavaDoc;
27
28 /**
29  * A connection to the database.
30  *
31  * @author brian zimmer
32  * @author last revised by $Author: bzimmer $
33  * @version $Revision: 1.14 $
34  */

35 public class PyConnection extends PyObject implements ClassDictInit {
36
37     /**
38      * Field closed
39      */

40     protected boolean closed;
41
42     /**
43      * Field connection
44      */

45     protected Connection JavaDoc connection;
46
47     /**
48      * Field supportsTransactions
49      */

50     protected boolean supportsTransactions;
51
52     /**
53      * Field cursors
54      */

55     private Set cursors;
56
57     /**
58      * Field statements
59      */

60     private Set statements;
61
62     /**
63      * Field __class__
64      */

65     public static PyClass __class__;
66
67     /**
68      * Method getPyClass
69      *
70      * @return PyClass
71      */

72     protected PyClass getPyClass() {
73         return __class__;
74     }
75
76     /**
77      * Field __members__
78      */

79     protected static PyList __members__;
80
81     /**
82      * Field __methods__
83      */

84     protected static PyList __methods__;
85
86     static {
87         PyObject[] m = new PyObject[5];
88
89         m[0] = new PyString("close");
90         m[1] = new PyString("commit");
91         m[2] = new PyString("cursor");
92         m[3] = new PyString("rollback");
93         m[4] = new PyString("nativesql");
94         __methods__ = new PyList(m);
95         m = new PyObject[10];
96         m[0] = new PyString("autocommit");
97         m[1] = new PyString("dbname");
98         m[2] = new PyString("dbversion");
99         m[3] = new PyString("drivername");
100         m[4] = new PyString("driverversion");
101         m[5] = new PyString("url");
102         m[6] = new PyString("__connection__");
103         m[7] = new PyString("__cursors__");
104         m[8] = new PyString("__statements__");
105         m[9] = new PyString("closed");
106         __members__ = new PyList(m);
107     }
108
109     /**
110      * Create a PyConnection with the open connection.
111      *
112      * @param connection
113      * @throws SQLException
114      */

115     public PyConnection(Connection JavaDoc connection) throws SQLException JavaDoc {
116
117         this.closed = false;
118         this.cursors = new HashSet JavaDoc();
119         this.connection = connection;
120         this.statements = new HashSet JavaDoc();
121         this.supportsTransactions = this.connection.getMetaData().supportsTransactions();
122
123         if (this.supportsTransactions) {
124             this.connection.setAutoCommit(false);
125         }
126     }
127
128     /**
129      * Produces a string representation of the object.
130      *
131      * @return string representation of the object.
132      */

133     public String JavaDoc toString() {
134
135         try {
136             return "<PyConnection user='" + this.connection.getMetaData().getUserName() + "', url='" + this.connection.getMetaData().getURL() + "'>";
137         } catch (SQLException JavaDoc e) {
138             return "<PyConnection at " + hashCode() + ">";
139         }
140     }
141
142     /**
143      * Method classDictInit
144      *
145      * @param dict
146      */

147     static public void classDictInit(PyObject dict) {
148
149         dict.__setitem__("autocommit", new PyInteger(0));
150         dict.__setitem__("__version__", Py.newString("$Revision: 1.14 $").__getslice__(Py.newInteger(11), Py.newInteger(-2), null));
151         dict.__setitem__("close", new ConnectionFunc("close", 0, 0, 0, zxJDBC.getString("close")));
152         dict.__setitem__("commit", new ConnectionFunc("commit", 1, 0, 0, zxJDBC.getString("commit")));
153         dict.__setitem__("cursor", new ConnectionFunc("cursor", 2, 0, 4, zxJDBC.getString("cursor")));
154         dict.__setitem__("rollback", new ConnectionFunc("rollback", 3, 0, 0, zxJDBC.getString("rollback")));
155         dict.__setitem__("nativesql", new ConnectionFunc("nativesql", 4, 1, 1, zxJDBC.getString("nativesql")));
156
157         // hide from python
158
dict.__setitem__("initModule", null);
159         dict.__setitem__("toString", null);
160         dict.__setitem__("setConnection", null);
161         dict.__setitem__("getPyClass", null);
162         dict.__setitem__("connection", null);
163         dict.__setitem__("classDictInit", null);
164         dict.__setitem__("cursors", null);
165     }
166
167     /**
168      * Sets the attribute.
169      *
170      * @param name
171      * @param value
172      */

173     public void __setattr__(String JavaDoc name, PyObject value) {
174
175         if ("autocommit".equals(name)) {
176             try {
177                 if (this.supportsTransactions) {
178                     this.connection.setAutoCommit(value.__nonzero__());
179                 }
180             } catch (SQLException JavaDoc e) {
181                 throw zxJDBC.makeException(zxJDBC.DatabaseError, e);
182             }
183
184             return;
185         }
186
187         super.__setattr__(name, value);
188     }
189
190     /**
191      * Finds the attribute.
192      *
193      * @param name the name of the attribute of interest
194      * @return the value for the attribute of the specified name
195      */

196     public PyObject __findattr__(String JavaDoc name) {
197
198         if ("autocommit".equals(name)) {
199             try {
200                 return connection.getAutoCommit() ? Py.One : Py.Zero;
201             } catch (SQLException JavaDoc e) {
202                 throw zxJDBC.makeException(zxJDBC.DatabaseError, e);
203             }
204         } else if ("dbname".equals(name)) {
205             try {
206                 return Py.newString(this.connection.getMetaData().getDatabaseProductName());
207             } catch (SQLException JavaDoc e) {
208                 throw zxJDBC.makeException(zxJDBC.DatabaseError, e);
209             }
210         } else if ("dbversion".equals(name)) {
211             try {
212                 return Py.newString(this.connection.getMetaData().getDatabaseProductVersion());
213             } catch (SQLException JavaDoc e) {
214                 throw zxJDBC.makeException(zxJDBC.DatabaseError, e);
215             }
216         } else if ("drivername".equals(name)) {
217             try {
218                 return Py.newString(this.connection.getMetaData().getDriverName());
219             } catch (SQLException JavaDoc e) {
220                 throw zxJDBC.makeException(zxJDBC.DatabaseError, e);
221             }
222         } else if ("driverversion".equals(name)) {
223             try {
224                 return Py.newString(this.connection.getMetaData().getDriverVersion());
225             } catch (SQLException JavaDoc e) {
226                 throw zxJDBC.makeException(zxJDBC.DatabaseError, e);
227             }
228         } else if ("url".equals(name)) {
229             try {
230                 return Py.newString(this.connection.getMetaData().getURL());
231             } catch (SQLException JavaDoc e) {
232                 throw zxJDBC.makeException(zxJDBC.DatabaseError, e);
233             }
234         } else if ("__connection__".equals(name)) {
235             return Py.java2py(this.connection);
236         } else if ("__cursors__".equals(name)) {
237             return Py.java2py(Collections.unmodifiableSet(this.cursors));
238         } else if ("__statements__".equals(name)) {
239             return Py.java2py(Collections.unmodifiableSet(this.statements));
240         } else if ("__methods__".equals(name)) {
241             return __methods__;
242         } else if ("__members__".equals(name)) {
243             return __members__;
244         } else if ("closed".equals(name)) {
245             return Py.newBoolean(closed);
246         }
247
248         return super.__findattr__(name);
249     }
250
251     /**
252      * Close the connection now (rather than whenever __del__ is called).
253      * The connection will be unusable from this point forward; an Error
254      * (or subclass) exception will be raised if any operation is attempted
255      * with the connection. The same applies to all cursor objects trying
256      * to use the connection.
257      */

258     public void close() {
259
260         if (closed) {
261             throw zxJDBC.makeException(zxJDBC.ProgrammingError, "connection is closed");
262         }
263
264         // mark ourselves closed now so that any callbacks we
265
// get from closing down cursors and statements to not
266
// try and modify our internal sets
267
this.closed = true;
268
269         synchronized (this.cursors) {
270
271             // close the cursors
272
for (Iterator JavaDoc i = this.cursors.iterator(); i.hasNext();) {
273                 ((PyCursor) i.next()).close();
274             }
275
276             this.cursors.clear();
277         }
278
279         synchronized (this.statements) {
280
281             // close the cursors
282
for (Iterator JavaDoc i = this.statements.iterator(); i.hasNext();) {
283                 ((PyStatement) i.next()).close();
284             }
285
286             this.statements.clear();
287         }
288
289         try {
290             this.connection.close();
291         } catch (SQLException JavaDoc e) {
292             throw zxJDBC.makeException(e);
293         }
294     }
295
296     /**
297      * Commit any pending transaction to the database. Note that if the
298      * database supports an auto-commit feature, this must be initially
299      * off. An interface method may be provided to turn it back on.
300      * <p/>
301      * Database modules that do not support transactions should implement
302      * this method with void functionality.
303      */

304     public void commit() {
305
306         if (closed) {
307             throw zxJDBC.makeException(zxJDBC.ProgrammingError, "connection is closed");
308         }
309
310         if (!this.supportsTransactions) {
311             return;
312         }
313
314         try {
315             this.connection.commit();
316         } catch (SQLException JavaDoc e) {
317             throw zxJDBC.makeException(e);
318         }
319     }
320
321     /**
322      * <i>This method is optional since not all databases provide transaction
323      * support.</i>
324      * <p/>
325      * In case a database does provide transactions this method causes the database
326      * to roll back to the start of any pending transaction. Closing a connection
327      * without committing the changes first will cause an implicit rollback to be
328      * performed.
329      */

330     public void rollback() {
331
332         if (closed) {
333             throw zxJDBC.makeException(zxJDBC.ProgrammingError, "connection is closed");
334         }
335
336         if (!this.supportsTransactions) {
337             return;
338         }
339
340         try {
341             this.connection.rollback();
342         } catch (SQLException JavaDoc e) {
343             throw zxJDBC.makeException(e);
344         }
345     }
346
347     /**
348      * Converts the given SQL statement into the system's native SQL grammar. A
349      * driver may convert the JDBC sql grammar into its system's native SQL grammar
350      * prior to sending it; this method returns the native form of the statement
351      * that the driver would have sent.
352      *
353      * @param nativeSQL
354      * @return the native form of this statement
355      */

356     public PyObject nativesql(PyObject nativeSQL) {
357
358         if (closed) {
359             throw zxJDBC.makeException(zxJDBC.ProgrammingError, "connection is closed");
360         }
361
362         if (nativeSQL == Py.None) {
363             return Py.None;
364         }
365
366         try {
367             return Py.newString(this.connection.nativeSQL(nativeSQL.__str__().toString()));
368         } catch (SQLException JavaDoc e) {
369             throw zxJDBC.makeException(e);
370         }
371     }
372
373     /**
374      * Return a new Cursor Object using the connection. If the database does not
375      * provide a direct cursor concept, the module will have to emulate cursors
376      * using other means to the extent needed by this specification.
377      *
378      * @return a new cursor using this connection
379      */

380     public PyCursor cursor() {
381         return cursor(false);
382     }
383
384     /**
385      * Return a new Cursor Object using the connection. If the database does not
386      * provide a direct cursor concept, the module will have to emulate cursors
387      * using other means to the extent needed by this specification.
388      *
389      * @param dynamicFetch if true, dynamically iterate the result
390      * @return a new cursor using this connection
391      */

392     public PyCursor cursor(boolean dynamicFetch) {
393         return this.cursor(dynamicFetch, Py.None, Py.None);
394     }
395
396     /**
397      * Return a new Cursor Object using the connection. If the database does not
398      * provide a direct cursor concept, the module will have to emulate cursors
399      * using other means to the extent needed by this specification.
400      *
401      * @param dynamicFetch if true, dynamically iterate the result
402      * @param rsType the type of the underlying ResultSet
403      * @param rsConcur the concurrency of the underlying ResultSet
404      * @return a new cursor using this connection
405      */

406     public PyCursor cursor(boolean dynamicFetch, PyObject rsType, PyObject rsConcur) {
407
408         if (closed) {
409             throw zxJDBC.makeException(zxJDBC.ProgrammingError, "connection is closed");
410         }
411
412         PyCursor cursor = new PyExtendedCursor(this, dynamicFetch, rsType, rsConcur);
413
414         this.cursors.add(cursor);
415
416         return cursor;
417     }
418
419     /**
420      * Remove an open PyCursor.
421      *
422      * @param cursor
423      */

424     void remove(PyCursor cursor) {
425
426         if (closed) {
427             return;
428         }
429
430         this.cursors.remove(cursor);
431     }
432
433     /**
434      * Method register
435      *
436      * @param statement statement
437      */

438     void add(PyStatement statement) {
439
440         if (closed) {
441             return;
442         }
443
444         this.statements.add(statement);
445     }
446
447     /**
448      * Method contains
449      *
450      * @param statement statement
451      * @return boolean
452      */

453     boolean contains(PyStatement statement) {
454
455         if (closed) {
456             return false;
457         }
458
459         return this.statements.contains(statement);
460     }
461 }
462
463 class ConnectionFunc extends PyBuiltinFunctionSet {
464     ConnectionFunc(String JavaDoc name, int index, int minargs, int maxargs, String JavaDoc doc) {
465         super(name, index, minargs, maxargs, true, doc);
466     }
467
468     public PyObject __call__() {
469         PyConnection c = (PyConnection) __self__;
470         switch (index) {
471             case 0:
472                 c.close();
473                 return Py.None;
474             case 1:
475                 c.commit();
476                 return Py.None;
477             case 2:
478                 return c.cursor();
479             case 3:
480                 c.rollback();
481                 return Py.None;
482             default :
483                 throw argCountError(0);
484         }
485     }
486
487     public PyObject __call__(PyObject arg) {
488         PyConnection c = (PyConnection) __self__;
489         switch (index) {
490             case 2:
491                 return c.cursor(arg.__nonzero__());
492             case 4:
493                 return c.nativesql(arg);
494             default :
495                 throw argCountError(1);
496         }
497     }
498
499     public PyObject __call__(PyObject arg1, PyObject arg2, PyObject arg3) {
500         PyConnection c = (PyConnection) __self__;
501         switch (index) {
502             case 2:
503                 return c.cursor(arg1.__nonzero__(), arg2, arg3);
504             default :
505                 throw argCountError(3);
506         }
507     }
508
509     public PyObject __call__(PyObject[] args, String JavaDoc[] keywords) {
510         PyConnection c = (PyConnection) __self__;
511         PyArgParser parser = new PyArgParser(args, keywords);
512         switch (index) {
513             case 2:
514                 PyObject dynamic = parser.kw("dynamic", Py.None);
515                 PyObject rstype = parser.kw("rstype", Py.None);
516                 PyObject rsconcur = parser.kw("rsconcur", Py.None);
517
518                 dynamic = (parser.numArg() >= 1) ? parser.arg(0) : dynamic;
519                 rstype = (parser.numArg() >= 2) ? parser.arg(1) : rstype;
520                 rsconcur = (parser.numArg() >= 3) ? parser.arg(2) : rsconcur;
521
522                 return c.cursor(dynamic.__nonzero__(), rstype, rsconcur);
523
524             default :
525                 throw argCountError(args.length);
526         }
527     }
528 }
529
Popular Tags