Source Code Cross Referenced for MConnection.java in  » Database-DBMS » mckoi » com » mckoi » database » jdbc » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database DBMS » mckoi » com.mckoi.database.jdbc 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /**
002:         * com.mckoi.database.jdbc.MConnection  20 Jul 2000
003:         *
004:         * Mckoi SQL Database ( http://www.mckoi.com/database )
005:         * Copyright (C) 2000, 2001, 2002  Diehl and Associates, Inc.
006:         *
007:         * This program is free software; you can redistribute it and/or
008:         * modify it under the terms of the GNU General Public License
009:         * Version 2 as published by the Free Software Foundation.
010:         *
011:         * This program is distributed in the hope that it will be useful,
012:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
013:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014:         * GNU General Public License Version 2 for more details.
015:         *
016:         * You should have received a copy of the GNU General Public License
017:         * Version 2 along with this program; if not, write to the Free Software
018:         * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
019:         *
020:         * Change Log:
021:         * 
022:         * 
023:         */package com.mckoi.database.jdbc;
024:
025:        import java.io.*;
026:        import java.sql.*;
027:        import java.util.Properties;
028:        import java.util.Vector;
029:        import java.util.StringTokenizer;
030:        import com.mckoi.database.global.ColumnDescription;
031:        import com.mckoi.database.global.ObjectTransfer;
032:        import com.mckoi.database.global.StreamableObject;
033:        import com.mckoi.util.ByteArrayUtil;
034:        import java.util.Hashtable; //#IFDEF(JDBC2.0)
035:        import java.util.Map;
036:
037:        //#ENDIF
038:
039:        /**
040:         * JDBC implementation of the connection object to a Mckoi database.  The
041:         * implementation specifics for how the connection talks with the database
042:         * is left up to the implementation of DatabaseInterface.
043:         * <p>
044:         * This object is thread safe.  It may be accessed safely from concurrent
045:         * threads.
046:         *
047:         * @author Tobias Downer
048:         */
049:
050:        public class MConnection implements  Connection, DatabaseCallBack {
051:
052:            /**
053:             * A cache of all rows retrieved from the server.  This cuts down the
054:             * number of requests to the server by caching rows that are accessed
055:             * frequently.  Note that cells are only cached within a ResultSet bounds.
056:             * Two different ResultSet's will not share cells in the cache.
057:             */
058:            private RowCache row_cache;
059:
060:            /**
061:             * The JDBC URL used to make this connection.
062:             */
063:            private String url;
064:
065:            /**
066:             * SQL warnings for this connection.
067:             */
068:            private SQLWarning head_warning;
069:
070:            /**
071:             * Set to true if the connection is closed.
072:             */
073:            private boolean is_closed;
074:
075:            /**
076:             * Set to true if the connection is in auto-commit mode.  (By default,
077:             * auto_commit is enabled).
078:             */
079:            private boolean auto_commit;
080:
081:            /**
082:             * The interface to the database.
083:             */
084:            private DatabaseInterface db_interface;
085:
086:            /**
087:             * The list of trigger listeners registered with the connection.
088:             */
089:            private Vector trigger_list;
090:
091:            /**
092:             * A Thread that handles all dispatching of trigger events to the JDBC
093:             * client.
094:             */
095:            private TriggerDispatchThread trigger_thread;
096:
097:            /**
098:             * If the ResultSet.getObject method should return the raw object type (eg.
099:             * BigDecimal for Integer, String for chars, etc) then this is set to false.
100:             * If this is true (the default) the 'getObject' methods return the
101:             * correct object types as specified by the JDBC specification.
102:             */
103:            private boolean strict_get_object;
104:
105:            /**
106:             * If the ResultSetMetaData.getColumnName method should return a succinct
107:             * form of the column name as most JDBC implementations do, this should
108:             * be set to false (the default).  If old style verbose column names should
109:             * be returned for compatibility with older Mckoi applications, this is
110:             * set to true.
111:             */
112:            private boolean verbose_column_names;
113:
114:            /**
115:             * This is set to true if the MResultSet column lookup methods are case
116:             * insensitive.  This should be set to true for any database that has
117:             * case insensitive identifiers.
118:             */
119:            private boolean case_insensitive_identifiers;
120:
121:            /**
122:             * A mapping from a streamable object id to InputStream used to represent
123:             * the object when being uploaded to the database engine.
124:             */
125:            private Hashtable s_object_hold;
126:
127:            /**
128:             * An unique id count given to streamable object being uploaded to the
129:             * server.
130:             */
131:            private long s_object_id;
132:
133:            // For synchronization in this object,
134:            private Object lock = new Object();
135:
136:            /**
137:             * Constructor.
138:             */
139:            public MConnection(String url, DatabaseInterface db_interface,
140:                    int cache_size, int max_size) {
141:                this .url = url;
142:                this .db_interface = db_interface;
143:                is_closed = true;
144:                auto_commit = true;
145:                trigger_list = new Vector();
146:                strict_get_object = true;
147:                verbose_column_names = false;
148:                case_insensitive_identifiers = false;
149:                row_cache = new RowCache(cache_size, max_size);
150:                s_object_hold = new Hashtable();
151:                s_object_id = 0;
152:            }
153:
154:            /**
155:             * Toggles strict get object.
156:             * <p>
157:             * If the 'getObject' method should return the raw object type (eg.
158:             * BigDecimal for Integer, String for chars, etc) then this is set to false.
159:             * If this is true (the default) the 'getObject' methods return the
160:             * correct object types as specified by the JDBC specification.
161:             * <p>
162:             * The default is true.
163:             */
164:            public void setStrictGetObject(boolean status) {
165:                strict_get_object = status;
166:            }
167:
168:            /**
169:             * Returns true if strict get object is enabled (default).
170:             */
171:            public boolean isStrictGetObject() {
172:                return strict_get_object;
173:            }
174:
175:            /**
176:             * Toggles verbose column names from ResultSetMetaData.
177:             * <p>
178:             * If this is set to true, getColumnName will return 'APP.Part.id' for a
179:             * column name.  If it is false getColumnName will return 'id'.  This
180:             * property is for compatibility with older Mckoi applications.
181:             */
182:            public void setVerboseColumnNames(boolean status) {
183:                verbose_column_names = status;
184:            }
185:
186:            /**
187:             * Returns true if ResultSetMetaData should return verbose column names.
188:             */
189:            public boolean verboseColumnNames() {
190:                return verbose_column_names;
191:            }
192:
193:            /**
194:             * Toggles whether this connection is handling identifiers as case
195:             * insensitive or not.  If this is true then 'getString("app.id")' will
196:             * match against 'APP.id', etc.
197:             */
198:            public void setCaseInsensitiveIdentifiers(boolean status) {
199:                case_insensitive_identifiers = status;
200:            }
201:
202:            /**
203:             * Returns true if the database has case insensitive identifiers.
204:             */
205:            public boolean isCaseInsensitiveIdentifiers() {
206:                return case_insensitive_identifiers;
207:            }
208:
209:            //  private static void printByteArray(byte[] array) {
210:            //    System.out.println("Length: " + array.length);
211:            //    for (int i = 0; i < array.length; ++i) {
212:            //      System.out.print(array[i]);
213:            //      System.out.print(", ");
214:            //    }
215:            //  }
216:
217:            /**
218:             * Returns the row Cache object for this connection.
219:             */
220:            protected final RowCache getRowCache() {
221:                return row_cache;
222:            }
223:
224:            /**
225:             * Adds a new SQLWarning to the chain.
226:             */
227:            protected final void addSQLWarning(SQLWarning warning) {
228:                synchronized (lock) {
229:                    if (head_warning == null) {
230:                        head_warning = warning;
231:                    } else {
232:                        head_warning.setNextWarning(warning);
233:                    }
234:                }
235:            }
236:
237:            /**
238:             * Closes this connection by calling the 'dispose' method in the database
239:             * interface.
240:             */
241:            public final void internalClose() throws SQLException {
242:                synchronized (lock) {
243:                    if (!isClosed()) {
244:                        try {
245:                            db_interface.dispose();
246:                        } finally {
247:                            is_closed = true;
248:                        }
249:                    }
250:                }
251:            }
252:
253:            /**
254:             * Returns this MConnection wrapped in a MckoiConnection object.
255:             */
256:            MckoiConnection getMckoiConnection() {
257:                return new MckoiConnection(this );
258:            }
259:
260:            /**
261:             * Attempts to login to the database interface with the given default schema,
262:             * username and password.  If the authentication fails an SQL exception is
263:             * generated.
264:             */
265:            public void login(String default_schema, String username,
266:                    String password) throws SQLException {
267:
268:                synchronized (lock) {
269:                    if (!is_closed) {
270:                        throw new SQLException(
271:                                "Unable to login to connection because it is open.");
272:                    }
273:                }
274:
275:                if (username == null || username.equals("") || password == null
276:                        || password.equals("")) {
277:                    throw new SQLException(
278:                            "username or password have not been set.");
279:                }
280:
281:                // Set the default schema to username if it's null
282:                if (default_schema == null) {
283:                    default_schema = username;
284:                }
285:
286:                // Login with the username/password
287:                boolean li = db_interface.login(default_schema, username,
288:                        password, this );
289:                synchronized (lock) {
290:                    is_closed = !li;
291:                }
292:                if (!li) {
293:                    throw new SQLException("User authentication failed for: "
294:                            + username);
295:                }
296:
297:                // Determine if this connection is case insensitive or not,
298:                setCaseInsensitiveIdentifiers(false);
299:                Statement stmt = createStatement();
300:                ResultSet rs = stmt.executeQuery("SHOW CONNECTION_INFO");
301:                while (rs.next()) {
302:                    String key = rs.getString(1);
303:                    if (key.equals("case_insensitive_identifiers")) {
304:                        String val = rs.getString(2);
305:                        setCaseInsensitiveIdentifiers(val.equals("true"));
306:                    } else if (key.equals("auto_commit")) {
307:                        String val = rs.getString(2);
308:                        auto_commit = val.equals("true");
309:                    }
310:                }
311:                rs.close();
312:                stmt.close();
313:
314:            }
315:
316:            // ---------- Package Protected ----------
317:
318:            /**
319:             * Returns the url string used to make this connection.
320:             */
321:            String getURL() {
322:                return url;
323:            }
324:
325:            /**
326:             * Logs into the JDBC server running on a remote machine.  Throws an
327:             * exception if user authentication fails.
328:             */
329:            void login(Properties info, String default_schema)
330:                    throws SQLException {
331:
332:                String username = info.getProperty("user", "");
333:                String password = info.getProperty("password", "");
334:
335:                login(default_schema, username, password);
336:            }
337:
338:            //  /**
339:            //   * Cancels a result set that is downloading.
340:            //   */
341:            //  void cancelResultSet(MResultSet result_set) throws SQLException {
342:            //    disposeResult(result_set.getResultID());
343:            //
344:            ////    connection_thread.disposeResult(result_set.getResultID());
345:            //  }
346:
347:            /**
348:             * Uploads any streamable objects found in an SQLQuery into the database.
349:             */
350:            private void uploadStreamableObjects(SQLQuery sql)
351:                    throws SQLException {
352:
353:                // Push any streamable objects that are present in the query onto the
354:                // server.
355:                Object[] vars = sql.getVars();
356:                try {
357:                    for (int i = 0; i < vars.length; ++i) {
358:                        // For each streamable object.
359:                        if (vars[i] != null
360:                                && vars[i] instanceof  StreamableObject) {
361:                            // Buffer size is fixed to 64 KB
362:                            final int BUF_SIZE = 64 * 1024;
363:
364:                            StreamableObject s_object = (StreamableObject) vars[i];
365:                            long offset = 0;
366:                            final byte type = s_object.getType();
367:                            final long total_len = s_object.getSize();
368:                            final long id = s_object.getIdentifier();
369:                            final byte[] buf = new byte[BUF_SIZE];
370:
371:                            // Get the InputStream from the StreamableObject hold
372:                            Object sob_id = new Long(id);
373:                            InputStream i_stream = (InputStream) s_object_hold
374:                                    .get(sob_id);
375:                            if (i_stream == null) {
376:                                throw new RuntimeException(
377:                                        "Assertion failed: Streamable object InputStream is not available.");
378:                            }
379:
380:                            while (offset < total_len) {
381:                                // Fill the buffer
382:                                int index = 0;
383:                                final int block_read = (int) Math.min(
384:                                        (long) BUF_SIZE, (total_len - offset));
385:                                int to_read = block_read;
386:                                while (to_read > 0) {
387:                                    int count = i_stream.read(buf, index,
388:                                            to_read);
389:                                    if (count == -1) {
390:                                        throw new IOException(
391:                                                "Premature end of stream.");
392:                                    }
393:                                    index += count;
394:                                    to_read -= count;
395:                                }
396:
397:                                // Send the part of the streamable object to the database.
398:                                db_interface.pushStreamableObjectPart(type, id,
399:                                        total_len, buf, offset, block_read);
400:                                // Increment the offset and upload the next part of the object.
401:                                offset += block_read;
402:                            }
403:
404:                            // Remove the streamable object once it has been written
405:                            s_object_hold.remove(sob_id);
406:
407:                            //        [ Don't close the input stream - we may only want to put a part of
408:                            //          the stream into the database and keep the file open. ]
409:                            //          // Close the input stream
410:                            //          i_stream.close();
411:
412:                        }
413:                    }
414:                } catch (IOException e) {
415:                    e.printStackTrace(System.err);
416:                    throw new SQLException(
417:                            "IO Error pushing large object to server: "
418:                                    + e.getMessage());
419:                }
420:            }
421:
422:            /**
423:             * Sends the batch of SQLQuery objects to the database to be executed.  The
424:             * given array of MResultSet will be the consumer objects for the query
425:             * results.  If a query succeeds then we are guarenteed to know that size of
426:             * the result set.
427:             * <p>
428:             * This method blocks until all of the queries have been processed by the
429:             * database.
430:             */
431:            void executeQueries(SQLQuery[] queries, MResultSet[] results)
432:                    throws SQLException {
433:                // For each query
434:                for (int i = 0; i < queries.length; ++i) {
435:                    executeQuery(queries[i], results[i]);
436:                }
437:            }
438:
439:            /**
440:             * Sends the SQL string to the database to be executed.  The given MResultSet
441:             * is the consumer for the results from the database.  We are guarenteed
442:             * that if the query succeeds that we know the size of the result set and
443:             * at least first first row of the set.
444:             * <p>
445:             * This method will block until we have received the result header
446:             * information.
447:             */
448:            void executeQuery(SQLQuery sql, MResultSet result_set)
449:                    throws SQLException {
450:
451:                uploadStreamableObjects(sql);
452:                // Execute the query,
453:                QueryResponse resp = db_interface.execQuery(sql);
454:
455:                // The format of the result
456:                ColumnDescription[] col_list = new ColumnDescription[resp
457:                        .getColumnCount()];
458:                for (int i = 0; i < col_list.length; ++i) {
459:                    col_list[i] = resp.getColumnDescription(i);
460:                }
461:                // Set up the result set to the result format and update the time taken to
462:                // execute the query on the server.
463:                result_set.connSetup(resp.getResultID(), col_list, resp
464:                        .getRowCount());
465:                result_set.setQueryTime(resp.getQueryTimeMillis());
466:
467:            }
468:
469:            /**
470:             * Called by MResultSet to query a part of a result from the server.  Returns
471:             * a List that represents the result from the server.
472:             */
473:            ResultPart requestResultPart(int result_id, int start_row,
474:                    int count_rows) throws SQLException {
475:                return db_interface.getResultPart(result_id, start_row,
476:                        count_rows);
477:            }
478:
479:            /**
480:             * Requests a part of a streamable object from the server.
481:             */
482:            StreamableObjectPart requestStreamableObjectPart(int result_id,
483:                    long streamable_object_id, long offset, int len)
484:                    throws SQLException {
485:                return db_interface.getStreamableObjectPart(result_id,
486:                        streamable_object_id, offset, len);
487:            }
488:
489:            /**
490:             * Disposes of the server-side resources associated with the result set with
491:             * result_id.  This should be called either before we start the download of
492:             * a new result set, or when we have finished with the resources of a result
493:             * set.
494:             */
495:            void disposeResult(int result_id) throws SQLException {
496:                // Clear the row cache.
497:                // It would be better if we only cleared row entries with this
498:                // table_id.  We currently clear the entire cache which means there will
499:                // be traffic created for other open result sets.
500:                //    System.out.println(result_id);
501:                //    row_cache.clear();
502:                // Only dispose if the connection is open
503:                if (!is_closed) {
504:                    db_interface.disposeResult(result_id);
505:                }
506:            }
507:
508:            /**
509:             * Adds a TriggerListener that listens for all triggers events with the name
510:             * given.  Triggers are created with the 'CREATE TRIGGER' syntax.
511:             */
512:            void addTriggerListener(String trigger_name,
513:                    TriggerListener listener) {
514:                synchronized (trigger_list) {
515:                    trigger_list.addElement(trigger_name);
516:                    trigger_list.addElement(listener);
517:                }
518:            }
519:
520:            /**
521:             * Removes the TriggerListener for the given trigger name.
522:             */
523:            void removeTriggerListener(String trigger_name,
524:                    TriggerListener listener) {
525:                synchronized (trigger_list) {
526:                    for (int i = trigger_list.size() - 2; i >= 0; i -= 2) {
527:                        if (trigger_list.elementAt(i).equals(trigger_name)
528:                                && trigger_list.elementAt(i + 1).equals(
529:                                        listener)) {
530:                            trigger_list.removeElementAt(i);
531:                            trigger_list.removeElementAt(i);
532:                        }
533:                    }
534:                }
535:            }
536:
537:            /**
538:             * Creates a StreamableObject on the JDBC client side given an InputStream,
539:             * and length and a type.  When this method returns, a StreamableObject
540:             * entry will be added to the hold.
541:             */
542:            StreamableObject createStreamableObject(InputStream x, int length,
543:                    byte type) {
544:                long ob_id;
545:                synchronized (s_object_hold) {
546:                    ob_id = s_object_id;
547:                    ++s_object_id;
548:                    // Add the stream to the hold and get the unique id
549:                    s_object_hold.put(new Long(ob_id), x);
550:                }
551:                // Create and return the StreamableObject
552:                return new StreamableObject(type, length, ob_id);
553:            }
554:
555:            /**
556:             * Removes the StreamableObject from the hold on the JDBC client.  This should
557:             * be called when the MPreparedStatement closes.
558:             */
559:            void removeStreamableObject(StreamableObject s_object) {
560:                s_object_hold.remove(new Long(s_object.getIdentifier()));
561:            }
562:
563:            // ---------- Implemented from DatabaseCallBack ----------
564:
565:            // NOTE: For JDBC standalone apps, the thread that calls this will be a
566:            //   WorkerThread.
567:            //   For JDBC client/server apps, the thread that calls this will by the
568:            //   connection thread that listens for data from the server.
569:            public void databaseEvent(int event_type, String event_message) {
570:                if (event_type == 99) {
571:                    if (trigger_thread == null) {
572:                        trigger_thread = new TriggerDispatchThread();
573:                        trigger_thread.start();
574:                    }
575:                    trigger_thread.dispatchTrigger(event_message);
576:                } else {
577:                    throw new Error("Unrecognised database event: "
578:                            + event_type);
579:                }
580:
581:                //    System.out.println("[com.mckoi.jdbc.MConnection] Event received:");
582:                //    System.out.println(event_type);
583:                //    System.out.println(event_message);
584:            }
585:
586:            // ---------- Implemented from Connection ----------
587:
588:            public Statement createStatement() throws SQLException {
589:                return new MStatement(this );
590:            }
591:
592:            public PreparedStatement prepareStatement(String sql)
593:                    throws SQLException {
594:                return new MPreparedStatement(this , sql);
595:            }
596:
597:            public CallableStatement prepareCall(String sql)
598:                    throws SQLException {
599:                throw MSQLException.unsupported();
600:            }
601:
602:            public String nativeSQL(String sql) throws SQLException {
603:                // We don't do any client side parsing of the sql statement.
604:                return sql;
605:            }
606:
607:            public void setAutoCommit(boolean autoCommit) throws SQLException {
608:                // The SQL to put into auto-commit mode.
609:                ResultSet result;
610:                if (autoCommit) {
611:                    result = createStatement().executeQuery(
612:                            "SET AUTO COMMIT ON");
613:                    auto_commit = true;
614:                    result.close();
615:                } else {
616:                    result = createStatement().executeQuery(
617:                            "SET AUTO COMMIT OFF");
618:                    auto_commit = false;
619:                    result.close();
620:                }
621:            }
622:
623:            public boolean getAutoCommit() throws SQLException {
624:                return auto_commit;
625:                //    // Query the database for this info.
626:                //    ResultSet result;
627:                //    result = createStatement().executeQuery(
628:                //                           "SHOW CONNECTION_INFO WHERE var = 'auto_commit'");
629:                //    boolean auto_commit_mode = false;
630:                //    if (result.next()) {
631:                //      auto_commit_mode = result.getString(2).equals("true");
632:                //    }
633:                //    result.close();
634:                //    return auto_commit_mode;
635:            }
636:
637:            public void commit() throws SQLException {
638:                ResultSet result;
639:                result = createStatement().executeQuery("COMMIT");
640:                result.close();
641:            }
642:
643:            public void rollback() throws SQLException {
644:                ResultSet result;
645:                result = createStatement().executeQuery("ROLLBACK");
646:                result.close();
647:            }
648:
649:            public void close() throws SQLException {
650:
651:                if (!isClosed()) {
652:                    internalClose();
653:                }
654:
655:                //    if (!isClosed()) {
656:                //      try {
657:                //        internalClose();
658:                //      }
659:                //      finally {
660:                //        MDriver.connectionClosed(this);
661:                //      }
662:                //    }
663:
664:                //    synchronized (lock) {
665:                //      if (!isClosed()) {
666:                //        try {
667:                //          db_interface.dispose();
668:                //          MDriver.connectionClosed(this);
669:                //        }
670:                //        finally {
671:                //          is_closed = true;
672:                //        }
673:                //      }
674:                //    }
675:            }
676:
677:            public boolean isClosed() throws SQLException {
678:                synchronized (lock) {
679:                    return is_closed;
680:                }
681:            }
682:
683:            //======================================================================
684:            // Advanced features:
685:
686:            public DatabaseMetaData getMetaData() throws SQLException {
687:                return new MDatabaseMetaData(this );
688:            }
689:
690:            public void setReadOnly(boolean readOnly) throws SQLException {
691:                // Hint ignored
692:            }
693:
694:            public boolean isReadOnly() throws SQLException {
695:                // Currently we don't support read locked transactions.
696:                return false;
697:            }
698:
699:            public void setCatalog(String catalog) throws SQLException {
700:                // Silently ignored ;-)
701:            }
702:
703:            public String getCatalog() throws SQLException {
704:                // Catalog's not supported
705:                return null;
706:            }
707:
708:            public void setTransactionIsolation(int level) throws SQLException {
709:                if (level != TRANSACTION_SERIALIZABLE) {
710:                    throw new SQLException(
711:                            "Only 'TRANSACTION_SERIALIZABLE' supported.");
712:                }
713:            }
714:
715:            public int getTransactionIsolation() throws SQLException {
716:                return TRANSACTION_SERIALIZABLE;
717:            }
718:
719:            public SQLWarning getWarnings() throws SQLException {
720:                synchronized (lock) {
721:                    return head_warning;
722:                }
723:            }
724:
725:            public void clearWarnings() throws SQLException {
726:                synchronized (lock) {
727:                    head_warning = null;
728:                }
729:            }
730:
731:            //#IFDEF(JDBC2.0)
732:
733:            //--------------------------JDBC 2.0-----------------------------
734:
735:            public Statement createStatement(int resultSetType,
736:                    int resultSetConcurrency) throws SQLException {
737:                Statement statement = createStatement();
738:                // PENDING - set default result set type and result set concurrency for
739:                //   statement
740:                return statement;
741:            }
742:
743:            public PreparedStatement prepareStatement(String sql,
744:                    int resultSetType, int resultSetConcurrency)
745:                    throws SQLException {
746:                PreparedStatement statement = prepareStatement(sql);
747:                // PENDING - set default result set type and result set concurrency for
748:                //   statement
749:                return statement;
750:            }
751:
752:            public CallableStatement prepareCall(String sql, int resultSetType,
753:                    int resultSetConcurrency) throws SQLException {
754:                throw MSQLException.unsupported();
755:            }
756:
757:            // ISSUE: I can see using 'Map' here is going to break compatibility with
758:            //   Java 1.1.  Even though testing with 1.1.8 on Linux and NT turned out
759:            //   fine, I have a feeling some verifiers on web browsers aren't going to
760:            //   like this.
761:            public Map getTypeMap() throws SQLException {
762:                throw MSQLException.unsupported();
763:            }
764:
765:            public void setTypeMap(Map map) throws SQLException {
766:                throw MSQLException.unsupported();
767:            }
768:
769:            //#ENDIF
770:
771:            //#IFDEF(JDBC3.0)
772:
773:            //--------------------------JDBC 3.0-----------------------------
774:
775:            public void setHoldability(int holdability) throws SQLException {
776:                // Currently holdability can not be set to CLOSE_CURSORS_AT_COMMIT though
777:                // it could be implemented.
778:                if (holdability == ResultSet.CLOSE_CURSORS_AT_COMMIT) {
779:                    throw new SQLException(
780:                            "CLOSE_CURSORS_AT_COMMIT holdability is not supported.");
781:                }
782:            }
783:
784:            public int getHoldability() throws SQLException {
785:                return ResultSet.HOLD_CURSORS_OVER_COMMIT;
786:            }
787:
788:            public Savepoint setSavepoint() throws SQLException {
789:                throw MSQLException.unsupported();
790:            }
791:
792:            public Savepoint setSavepoint(String name) throws SQLException {
793:                throw MSQLException.unsupported();
794:            }
795:
796:            public void rollback(Savepoint savepoint) throws SQLException {
797:                throw MSQLException.unsupported();
798:            }
799:
800:            public void releaseSavepoint(Savepoint savepoint)
801:                    throws SQLException {
802:                throw MSQLException.unsupported();
803:            }
804:
805:            public Statement createStatement(int resultSetType,
806:                    int resultSetConcurrency, int resultSetHoldability)
807:                    throws SQLException {
808:                // Currently holdability can not be set to CLOSE_CURSORS_AT_COMMIT though
809:                // it could be implemented.
810:                if (resultSetHoldability == ResultSet.CLOSE_CURSORS_AT_COMMIT) {
811:                    throw new SQLException(
812:                            "CLOSE_CURSORS_AT_COMMIT holdability is not supported.");
813:                }
814:                return createStatement(resultSetType, resultSetConcurrency);
815:            }
816:
817:            public PreparedStatement prepareStatement(String sql,
818:                    int resultSetType, int resultSetConcurrency,
819:                    int resultSetHoldability) throws SQLException {
820:                // Currently holdability can not be set to CLOSE_CURSORS_AT_COMMIT though
821:                // it could be implemented.
822:                if (resultSetHoldability == ResultSet.CLOSE_CURSORS_AT_COMMIT) {
823:                    throw new SQLException(
824:                            "CLOSE_CURSORS_AT_COMMIT holdability is not supported.");
825:                }
826:                return prepareStatement(sql, resultSetType,
827:                        resultSetConcurrency);
828:            }
829:
830:            public CallableStatement prepareCall(String sql, int resultSetType,
831:                    int resultSetConcurrency, int resultSetHoldability)
832:                    throws SQLException {
833:                throw MSQLException.unsupported();
834:            }
835:
836:            public PreparedStatement prepareStatement(String sql,
837:                    int autoGeneratedKeys) throws SQLException {
838:                throw MSQLException.unsupported();
839:            }
840:
841:            public PreparedStatement prepareStatement(String sql,
842:                    int columnIndexes[]) throws SQLException {
843:                throw MSQLException.unsupported();
844:            }
845:
846:            public PreparedStatement prepareStatement(String sql,
847:                    String columnNames[]) throws SQLException {
848:                throw MSQLException.unsupported();
849:            }
850:
851:            //#ENDIF
852:
853:            // ---------- Inner classes ----------
854:
855:            /**
856:             * The thread that handles all dispatching of trigger events.
857:             */
858:            private class TriggerDispatchThread extends Thread {
859:
860:                private Vector trigger_messages_queue = new Vector();
861:
862:                TriggerDispatchThread() {
863:                    setDaemon(true);
864:                    setName("Mckoi - Trigger Dispatcher");
865:                }
866:
867:                /**
868:                 * Dispatches a trigger message to the listeners.
869:                 */
870:                private void dispatchTrigger(String event_message) {
871:                    synchronized (trigger_messages_queue) {
872:                        trigger_messages_queue.addElement(event_message);
873:                        trigger_messages_queue.notifyAll();
874:                    }
875:                }
876:
877:                // Thread run method
878:                public void run() {
879:
880:                    while (true) {
881:                        try {
882:                            String message;
883:                            synchronized (trigger_messages_queue) {
884:                                while (trigger_messages_queue.size() == 0) {
885:                                    try {
886:                                        trigger_messages_queue.wait();
887:                                    } catch (InterruptedException e) { /* ignore */
888:                                    }
889:                                }
890:                                message = (String) trigger_messages_queue
891:                                        .elementAt(0);
892:                                trigger_messages_queue.removeElementAt(0);
893:                            }
894:
895:                            // 'message' is a message to process...
896:                            // The format of a trigger message is:
897:                            // "[trigger_name] [trigger_source] [trigger_fire_count]"
898:                            //          System.out.println("TRIGGER EVENT: " + message);
899:
900:                            StringTokenizer tok = new StringTokenizer(message,
901:                                    " ");
902:                            String trigger_name = (String) tok.nextElement();
903:                            String trigger_source = (String) tok.nextElement();
904:                            String trigger_fire_count = (String) tok
905:                                    .nextElement();
906:
907:                            Vector fired_triggers = new Vector();
908:                            // Create a list of Listener's that are listening for this trigger.
909:                            synchronized (trigger_list) {
910:                                for (int i = 0; i < trigger_list.size(); i += 2) {
911:                                    String to_listen_for = (String) trigger_list
912:                                            .elementAt(i);
913:                                    if (to_listen_for.equals(trigger_name)) {
914:                                        TriggerListener listener = (TriggerListener) trigger_list
915:                                                .elementAt(i + 1);
916:                                        // NOTE, we can't call 'listener.triggerFired' here because
917:                                        // it's not a good idea to call user code when we are
918:                                        // synchronized over 'trigger_list' (deadlock concerns).
919:                                        fired_triggers.addElement(listener);
920:                                    }
921:                                }
922:                            }
923:
924:                            // Fire them triggers.
925:                            for (int i = 0; i < fired_triggers.size(); ++i) {
926:                                TriggerListener listener = (TriggerListener) fired_triggers
927:                                        .elementAt(i);
928:                                listener.triggerFired(trigger_name);
929:                            }
930:
931:                        } catch (Throwable t) {
932:                            t.printStackTrace(System.err);
933:                        }
934:
935:                    }
936:
937:                }
938:
939:            }
940:
941:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.