Source Code Cross Referenced for DatabaseDriver.java in  » Workflow-Engines » pegasus-2.1.0 » org » griphyn » vdl » dbdriver » 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 » Workflow Engines » pegasus 2.1.0 » org.griphyn.vdl.dbdriver 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * This file or a portion of this file is licensed under the terms of
003:         * the Globus Toolkit Public License, found in file GTPL, or at
004:         * http://www.globus.org/toolkit/download/license.html. This notice must
005:         * appear in redistributions of this file, with or without modification.
006:         *
007:         * Redistributions of this Software, with or without modification, must
008:         * reproduce the GTPL in: (1) the Software, or (2) the Documentation or
009:         * some other similar material which is provided with the Software (if
010:         * any).
011:         *
012:         * Copyright 1999-2004 University of Chicago and The University of
013:         * Southern California. All rights reserved.
014:         */
015:        package org.griphyn.vdl.dbdriver;
016:
017:        import java.lang.reflect.*;
018:        import java.sql.*;
019:        import java.util.*;
020:        import java.io.PrintWriter;
021:        import java.io.IOException;
022:        import org.griphyn.vdl.util.ChimeraProperties;
023:        import org.griphyn.common.util.DynamicLoader;
024:        import org.griphyn.vdl.util.Logging;
025:
026:        /**
027:         * This common database interface that defines basic functionalities
028:         * for interacting with backend SQL database. The implementation
029:         * usually requires specific attention to the details between different
030:         * databases, as each does things slightly different. The API provides
031:         * a functionality that is independent of the schemas to be used.<p>
032:         * The schema classes implement all their database access in terms of
033:         * this database driver classes.<p>
034:         * The separation of database driver and schema lowers the implementation
035:         * cost, as only N driver and M schemas need to be implemented, instead
036:         * of N x M schema-specific database-specific drivers.
037:         *
038:         * @author Jens-S. Vöckler
039:         * @author Yong Zhao
040:         * @version $Revision: 50 $
041:         * @see org.griphyn.vdl.dbschema
042:         */
043:        public abstract class DatabaseDriver {
044:            /**
045:             * This variable keeps the JDBC handle for the database connection.
046:             */
047:            protected Connection m_connection = null;
048:
049:            /**
050:             * This list stores the prepared statements by their position.
051:             * The constructor will initialize it. Explicit destruction can
052:             * be requested per statement.
053:             */
054:            protected Map m_prepared;
055:
056:            //
057:            // class methods
058:            //
059:
060:            /**
061:             * Instantiates the appropriate child according to property values.
062:             * This method is a factory. Currently, drivers may be instantiated
063:             * multiple times.<p>
064:             *
065:             * @param dbDriverName is the name of the class that conforms to
066:             * the DatabaseDriver API. This class will be dynamically loaded.
067:             * The passed value should not be <code>null</code>.
068:             * @param propertyPrefix is the property prefix string to use.
069:             * @param arguments are arguments to the constructor of the driver
070:             * to load. Please use "new Object[0]" for the argumentless default
071:             * constructor.
072:             *
073:             * @exception ClassNotFoundException if the driver for the database
074:             * cannot be loaded. You might want to check your CLASSPATH, too.
075:             * @exception NoSuchMethodException if the driver's constructor interface
076:             * does not comply with the database driver API.
077:             * @exception InstantiationException if the driver class is an abstract
078:             * class instead of a concrete implementation.
079:             * @exception IllegalAccessException if the constructor for the driver
080:             * class it not publicly accessible to this package.
081:             * @exception InvocationTargetException if the constructor of the driver
082:             * throws an exception while being dynamically loaded.
083:             * @exception SQLException if the driver for the database can be
084:             * loaded, but faults when initially accessing the database
085:             *
086:             * @see org.griphyn.vdl.util.ChimeraProperties#getDatabaseDriverName
087:             */
088:            static public DatabaseDriver loadDriver(String dbDriverName,
089:                    String propertyPrefix, Object[] arguments)
090:                    throws ClassNotFoundException, IOException,
091:                    NoSuchMethodException, InstantiationException,
092:                    IllegalAccessException, InvocationTargetException,
093:                    SQLException {
094:                Logging log = Logging.instance();
095:                log.log("dbdriver", 3, "accessing loadDriver( "
096:                        + (dbDriverName == null ? "(null)" : dbDriverName)
097:                        + ", "
098:                        + (propertyPrefix == null ? "(null)" : propertyPrefix)
099:                        + " )");
100:
101:                // determine the database driver to load
102:                if (dbDriverName == null) {
103:                    dbDriverName = ChimeraProperties.instance()
104:                            .getDatabaseDriverName(propertyPrefix);
105:                    if (dbDriverName == null)
106:                        throw new RuntimeException("You need to specify the "
107:                                + propertyPrefix + " property");
108:                }
109:
110:                // syntactic sugar adds absolute class prefix
111:                if (dbDriverName.indexOf('.') == -1) {
112:                    // how about xxx.getClass().getPackage().getName()?
113:                    dbDriverName = "org.griphyn.vdl.dbdriver." + dbDriverName;
114:                }
115:
116:                // POSTCONDITION: we have now a fully-qualified class name
117:                log.log("dbdriver", 3, "trying to load " + dbDriverName);
118:                DynamicLoader dl = new DynamicLoader(dbDriverName);
119:                DatabaseDriver result = (DatabaseDriver) dl
120:                        .instantiate(arguments);
121:
122:                // done
123:                if (result == null)
124:                    log.log("dbdriver", 0, "unable to load " + dbDriverName);
125:                else
126:                    log.log("dbdriver", 3, "successfully loaded "
127:                            + dbDriverName);
128:                return result;
129:            }
130:
131:            /**
132:             * Convenience method instantiates the appropriate child according to
133:             * property values. Effectively, the following abbreviation is called:
134:             *
135:             * <pre>
136:             * loadDriver( null, propertyPrefix, new Object[0] );
137:             * </pre>
138:             *
139:             * @param propertyPrefix is the property prefix string to use.
140:             *
141:             * @exception ClassNotFoundException if the driver for the database
142:             * cannot be loaded. You might want to check your CLASSPATH, too.
143:             * @exception NoSuchMethodException if the driver's constructor interface
144:             * does not comply with the database driver API.
145:             * @exception InstantiationException if the driver class is an abstract
146:             * class instead of a concrete implementation.
147:             * @exception IllegalAccessException if the constructor for the driver
148:             * class it not publicly accessible to this package.
149:             * @exception InvocationTargetException if the constructor of the driver
150:             * throws an exception while being dynamically loaded.
151:             * @exception SQLException if the driver for the database can be
152:             * loaded, but faults when initially accessing the database
153:             *
154:             * @see #loadDriver( String, String, Object[] )
155:             */
156:            static public DatabaseDriver loadDriver(String propertyPrefix)
157:                    throws ClassNotFoundException, IOException,
158:                    NoSuchMethodException, InstantiationException,
159:                    IllegalAccessException, InvocationTargetException,
160:                    SQLException {
161:                return loadDriver(null, propertyPrefix, new Object[0]);
162:            }
163:
164:            /**
165:             * Default constructor. As the constructor will do nothing, please use
166:             * the connect method to obtain a database connection. This is the
167:             * constructor that will be invoked when dynamically loading a driver.
168:             *
169:             * @see #connect( String, Properties, Set )
170:             */
171:            public DatabaseDriver() {
172:                this .m_connection = null;
173:                this .m_prepared = new TreeMap();
174:            }
175:
176:            /**
177:             * Establishes a connection to the specified database. The parameters
178:             * will often be ignored or abused for different purposes on different
179:             * backends. It is assumed that the connection is not in auto-commit
180:             * mode, and explicit commits must be issued.<p>
181:             * Essentially, the deriving class will overwrite their connect method
182:             * to fill in the appropriate driver, and otherwise just call this
183:             * method.
184:             *
185:             * @param driver   is the Java class name of the database driver package
186:             * @param url      the contact string to database, or schema location
187:             * @param info     additional parameters, usually username and password
188:             * @param tables   is a set of all table names in the schema. The
189:             *                 existence of all tables will be checked to verify
190:             *                 that the schema is active in the database.
191:             * @return true if the connection succeeded, false otherwise. Usually,
192:             * false is returned, if the any of the tables or sequences is missing.
193:             *
194:             * @see #connect( String, Properties, Set )
195:             * @see org.griphyn.vdl.util.ChimeraProperties#getDatabaseDriverName
196:             * @see org.griphyn.vdl.util.ChimeraProperties#getDatabaseURL
197:             * @see org.griphyn.vdl.util.ChimeraProperties#getDatabaseDriverProperties
198:             * @exception if the driver is incapable of establishing a connection.
199:             */
200:            protected boolean connect(String driver, String url,
201:                    Properties info, Set tables) throws SQLException,
202:                    ClassNotFoundException {
203:                // load specificed driver class into memory
204:                Class.forName(driver);
205:
206:                Logging.instance().log("xaction", 1, "START connect to dbase");
207:                m_connection = DriverManager.getConnection(url, info);
208:                DriverManager.setLogWriter(new PrintWriter(System.err));
209:                Logging.instance()
210:                        .log("xaction", 1, "FINAL connected to dbase");
211:
212:                // determine that database version and driver version match
213:                this .driverMatch();
214:
215:                // disable auto commit, required for transaction (and speed).
216:                Logging.instance().log("xaction", 1,
217:                        "START disable auto-commit");
218:                m_connection.setAutoCommit(false);
219:                Logging.instance().log("xaction", 1,
220:                        "FINAL disabled auto-commit");
221:
222:                // auto-disconnect, should we forget it, or die in an orderly fashion
223:                Runtime.getRuntime().addShutdownHook(new Thread() {
224:                    public void run() {
225:                        try {
226:                            disconnect();
227:                        } catch (SQLException e) {
228:                            e.printStackTrace();
229:                        }
230:                    }
231:                });
232:
233:                // final function return value
234:                boolean result = true;
235:
236:                /* ### disabled
237:                // check for the presence of all tables in schema
238:                if ( result && tables != null && tables.size() > 0 ) {
239:                  Logging.instance().log("xaction", 1, "START checking for tables" );
240:
241:                  List columns = new ArrayList();
242:                  columns.add( "tablename" );
243:
244:                  Map where = new HashMap();
245:                  where.put( "tableowner", info.get("username") );
246:
247:                  Set temp = new TreeSet();
248:                  ResultSet rs = this.select( columns, "pg_tables", where, null );
249:                  while ( rs.next() ) {
250:                temp.add( rs.getString() );
251:                  }
252:                  result = temp.containsAll( tables );
253:                  Logging.instance().log("xaction", 1, "FINAL checking for tables" );
254:                }
255:                ### */
256:
257:                return result;
258:            }
259:
260:            /**
261:             * Establish a connection to your database. The parameters will often
262:             * be ignored or abused for different purposes on different backends.
263:             * It is assumed that the connection is not in auto-commit mode, and
264:             * explicit commits must be issued.
265:             *
266:             * @param url      the contact string to database, or schema location
267:             * @param info     additional parameters, usually username and password
268:             * @param tables   is a set of all table names in the schema. The
269:             *                 existence of all tables will be checked to verify
270:             *                 that the schema is active in the database.
271:             * @return true if the connection succeeded, false otherwise. Usually,
272:             * false is returned, if the any of the tables or sequences is missing.
273:             * @exception if the driver is incapable of establishing a connection.
274:             */
275:            abstract public boolean connect(String url, Properties info,
276:                    Set tables) throws SQLException, ClassNotFoundException;
277:
278:            /**
279:             * Determines, if the JDBC driver is the right one for the database we
280:             * talk to. Throws an exception if not.
281:             */
282:            public void driverMatch() throws SQLException {
283:                // empty on purpose
284:            }
285:
286:            /**
287:             * Close an established database connection.
288:             *
289:             * @exception if the driver threw up on the data.
290:             */
291:            public void disconnect() throws SQLException {
292:                if (this .m_connection != null) {
293:                    this .m_connection.close();
294:                    this .m_connection = null;
295:                }
296:            }
297:
298:            /**
299:             * Closes an open connection to the database whenever this object
300:             * is destroyed. This is still not foolproof.
301:             *
302:             */
303:            protected void finalize() throws Throwable {
304:                if (this .m_connection != null) {
305:                    this .m_connection.close();
306:                    this .m_connection = null;
307:                }
308:
309:                super .finalize();
310:            }
311:
312:            /**
313:             * Determines, if the backend is expensive, and results should be cached.
314:             * Ideally, this will move transparently into the backend itself.
315:             * @return true if caching is advisable, false for no caching.
316:             */
317:            abstract public boolean cachingMakesSense();
318:
319:            /**
320:             * Quotes a string that may contain special SQL characters.
321:             * @param s is the raw string.
322:             * @return the quoted string, which may be just the input string.
323:             */
324:            public String quote(String s) {
325:                // not implemented.
326:                return s;
327:            }
328:
329:            /**
330:             * Commits the latest changes to the database.
331:             * @exception SQLException is propagated from the commit.
332:             */
333:            public void commit() throws SQLException {
334:                this .m_connection.commit();
335:            }
336:
337:            /**
338:             * Rolls back the latest changes to the database. Some databases may
339:             * be incapable of rolling back.
340:             * @exception SQLException is propagated from the rollback operation.
341:             */
342:            public void rollback() throws SQLException {
343:                this .m_connection.rollback();
344:            }
345:
346:            /**
347:             * Clears all warnings reported for this database driver. After a call
348:             * to this method, the internal warnings are cleared until the next one
349:             * occurs.
350:             */
351:            public void clearWarnings() throws SQLException {
352:                this .m_connection.clearWarnings();
353:            }
354:
355:            /**
356:             * Retrieves the first warning reported by calls on this Connection
357:             * object.
358:             * @return the first SQLWarning object or null if there are none
359:             * @throws SQLException if a database access error occurs or this
360:             * method is called on a closed connection
361:             * @see java.sql.Connection#getWarnings
362:             */
363:            public SQLWarning getWarnings() throws SQLException {
364:                return this .m_connection.getWarnings();
365:            }
366:
367:            /**
368:             * Obtains the next value from a sequence. JDBC drivers which allow
369:             * explicit access to sequence generator will return a valid value
370:             * in this function. All other JDBC drivers should return -1.
371:             *
372:             * @param name is the name of the sequence.
373:             * @return the next sequence number.
374:             * @exception if something goes wrong while fetching the new value.
375:             */
376:            abstract public long sequence1(String name) throws SQLException;
377:
378:            /**
379:             * Obtains the sequence value for the current statement. JDBC driver
380:             * that permit insertion of NULL into auto-increment value should use
381:             * this method to return the inserted ID value via the statements
382:             * getGeneratedKeys(). Other JDBC drivers should treat return the
383:             * parametric id.
384:             *
385:             * @param s is a statment or prepared statement
386:             * @param name is the name of the sequence.
387:             * @param pos is the column number of the auto-increment column.
388:             * @return the next sequence number.
389:             * @exception if something goes wrong while fetching the new value.
390:             */
391:            abstract public long sequence2(Statement s, String name, int pos)
392:                    throws SQLException;
393:
394:            /**
395:             * Removes all rows that match the provided keyset from a table.
396:             * @param table is the name of the table to remove values from
397:             * @param columns is a set of column names and their associated
398:             *                values to select the removed columns. The map
399:             *                may be null to remove all rows in a table.
400:             * @return the number of rows removed.
401:             * @exception if something goes wrong while removing the values.
402:             */
403:            public int delete(String table, Map columns) throws SQLException {
404:                StringBuffer request = new StringBuffer();
405:
406:                request.append("DELETE FROM ").append(table);
407:                if (columns != null && columns.size() > 0) {
408:                    request.append(" WHERE ");
409:                    for (Iterator i = columns.entrySet().iterator(); i
410:                            .hasNext();) {
411:                        Map.Entry me = (Map.Entry) i.next();
412:                        request.append((String) me.getKey()).append("='");
413:                        request.append(this .quote((String) me.getValue()))
414:                                .append('\'');
415:                        if (i.hasNext())
416:                            request.append(" AND ");
417:                    }
418:                }
419:
420:                String query = request.toString();
421:                Logging.instance().log("sql", 2, query);
422:                Logging.instance()
423:                        .log("xaction", 1, "START DELETE in " + table);
424:                int count = m_connection.createStatement().executeUpdate(query);
425:                Logging.instance().log("xaction", 1,
426:                        "FINAL DELETE in " + table + ": " + count);
427:
428:                return count;
429:            }
430:
431:            /**
432:             * Inserts a row in one given database table.
433:             *
434:             * @param table is the name of the table to insert into.
435:             * @param keycolumns is a set of primary keys and their associated values.
436:             *                   For special tables, the primary key set may be null
437:             *                   or empty (e.g. a table without primary keys).
438:             * @param columns is a set of regular keys and their associated values.
439:             * @return the number of rows affected.
440:             * @exception if something goes wrong while inserting the values.
441:             */
442:            public long insert(String table, Map keycolumns, Map columns)
443:                    throws SQLException {
444:                StringBuffer request = new StringBuffer();
445:                StringBuffer values = new StringBuffer();
446:
447:                request.append("INSERT INTO ").append(table).append('(');
448:                values.append('(');
449:
450:                // conditionally add primary key columns, if they exist
451:                if (keycolumns != null && keycolumns.size() > 0) {
452:                    for (Iterator i = keycolumns.entrySet().iterator(); i
453:                            .hasNext();) {
454:                        Map.Entry me = (Map.Entry) i.next();
455:                        request.append((String) me.getKey());
456:                        values.append(quote((String) me.getValue()));
457:                        if (i.hasNext()) {
458:                            request.append(", ");
459:                            values.append(", ");
460:                        }
461:                    }
462:                }
463:
464:                // conditionally add all columns
465:                if (columns != null && columns.size() > 0) {
466:                    for (Iterator i = columns.entrySet().iterator(); i
467:                            .hasNext();) {
468:                        Map.Entry me = (Map.Entry) i.next();
469:                        request.append((String) me.getKey());
470:                        values.append(quote((String) me.getValue()));
471:                        if (i.hasNext()) {
472:                            request.append(", ");
473:                            values.append(", ");
474:                        }
475:                    }
476:                }
477:
478:                String query = request.toString() + " VALUES "
479:                        + values.toString();
480:                Logging.instance().log("sql", 2, query);
481:                Logging.instance()
482:                        .log("xaction", 1, "START INSERT in " + table);
483:                Statement st = m_connection.createStatement();
484:                long count = st.executeUpdate(query);
485:                Logging.instance().log("xaction", 1,
486:                        "FINAL INSERT in " + table + ": " + count);
487:                return count;
488:            }
489:
490:            /**
491:             * Updates matching rows in one given database table.
492:             * @param table is the name of the table to insert into.
493:             * @param keycolumns is a set of primary keys and their associated values.
494:             *                   For special tables, the primary key set may be null
495:             *                   or empty (e.g. a table without primary keys).
496:             * @param columns is a set of regular keys and their associated values.
497:             * @return the number of rows affected
498:             * @exception if something goes wrong while updating the values.
499:             */
500:            public int update(String table, Map keycolumns, Map columns)
501:                    throws SQLException {
502:                StringBuffer request = new StringBuffer();
503:
504:                request.append("UPDATE ").append(table).append(' ');
505:
506:                // unconditionally add all columns
507:                for (Iterator i = columns.entrySet().iterator(); i.hasNext();) {
508:                    Map.Entry me = (Map.Entry) i.next();
509:                    request.append("SET ").append((String) me.getKey()).append(
510:                            "='");
511:                    request.append(quote((String) me.getValue())).append('\'');
512:                    if (i.hasNext())
513:                        request.append(", ");
514:                }
515:
516:                // conditionally add primary key columns, if they exist
517:                if (keycolumns != null && keycolumns.size() > 0) {
518:                    request.append(" WHERE ");
519:                    for (Iterator i = keycolumns.entrySet().iterator(); i
520:                            .hasNext();) {
521:                        Map.Entry me = (Map.Entry) i.next();
522:                        request.append((String) me.getKey()).append("='");
523:                        request.append(quote((String) me.getValue())).append(
524:                                '\'');
525:                        if (i.hasNext())
526:                            request.append(" AND ");
527:                    }
528:                }
529:
530:                // so far, so good
531:                String query = request.toString();
532:                Logging.instance().log("sql", 2, query);
533:                Logging.instance()
534:                        .log("xaction", 1, "START UPDATE in " + table);
535:                int count = m_connection.createStatement().executeUpdate(query);
536:                Logging.instance().log("xaction", 1,
537:                        "FINAL UPDATE in " + table + ": " + count);
538:                return count;
539:            }
540:
541:            /**
542:             * Selects any rows in one or more colums from one or more tables
543:             * restricted by some condition, possibly ordered.
544:             * @param select is the ordered set of column names to select, or
545:             *               simply a one-value list with an asterisk.
546:             * @param table is the name of the table to select from.
547:             * @param where is a collection of column names and values they must equal.
548:             * @param order is an optional ordering string.
549:             */
550:            public ResultSet select(List select, String table, Map where,
551:                    String order) throws SQLException {
552:                StringBuffer request = new StringBuffer();
553:
554:                request.append("SELECT ");
555:                for (Iterator i = select.iterator(); i.hasNext();) {
556:                    request.append((String) i.next());
557:                    if (i.hasNext())
558:                        request.append(',');
559:                }
560:
561:                request.append(" FROM ").append(table);
562:
563:                if (where != null && where.size() > 0) {
564:                    request.append(" WHERE ");
565:                    for (Iterator i = where.entrySet().iterator(); i.hasNext();) {
566:                        Map.Entry me = (Map.Entry) i.next();
567:                        request.append((String) me.getKey()).append("=\'");
568:                        request.append(quote((String) me.getValue())).append(
569:                                '\'');
570:                        if (i.hasNext())
571:                            request.append(" AND ");
572:                    }
573:                }
574:
575:                if (order != null && order.length() > 0)
576:                    request.append(order);
577:
578:                String query = request.toString();
579:                Logging.instance().log("sql", 2, query);
580:                Logging.instance().log("xaction", 1,
581:                        "START SELECT FROM " + table);
582:                ResultSet result = m_connection.createStatement().executeQuery(
583:                        query);
584:                Logging.instance().log("xaction", 1,
585:                        "FINAL SELECT FROM " + table);
586:                return result;
587:            }
588:
589:            /**
590:             * Selects any rows in one or more colums from one or more tables
591:             * restricted by some condition that allows operators. Permissable
592:             * operators include =, &lt;&gt;, &gt;, &gt;=, &lt;, &lt;=, like, etc.
593:             * possibly ordered.
594:             *
595:             * @param select is the ordered set of column names to select, or
596:             *               simply a one-value list with an asterisk.
597:             * @param table is the name of the table to select from.
598:             * @param where is a collection of column names and values
599:             * @param operator is a collection of column names and operators
600:             *        if no entry is found for the name, then use '=' as default
601:             * @param order is an optional ordering string.
602:             */
603:            public ResultSet select(List select, String table, Map where,
604:                    Map operator, String order) throws SQLException {
605:                StringBuffer request = new StringBuffer();
606:                Logging l = Logging.instance();
607:
608:                request.append("SELECT ");
609:                for (Iterator i = select.iterator(); i.hasNext();) {
610:                    request.append((String) i.next());
611:                    if (i.hasNext())
612:                        request.append(',');
613:                }
614:
615:                request.append(" FROM ").append(table);
616:
617:                if (where != null && where.size() > 0) {
618:                    l.log("xaction", 1, "adding WHERE clause");
619:                    request.append(" WHERE ");
620:                    for (Iterator i = where.keySet().iterator(); i.hasNext();) {
621:                        String key = (String) i.next();
622:                        request.append(key);
623:                        String op = (String) operator.get(key);
624:                        request.append(op == null ? "=\'" : (" " + op + " \'"));
625:                        request.append(quote((String) where.get(key))).append(
626:                                '\'');
627:                        if (i.hasNext())
628:                            request.append(" AND ");
629:                    }
630:                } else {
631:                    l.log("xaction", 1, "no WHERE clause");
632:                }
633:
634:                if (order != null && order.length() > 0)
635:                    request.append(order);
636:
637:                String query = request.toString();
638:                l.log("sql", 2, query);
639:                l.log("xaction", 1, "START " + query);
640:                ResultSet result = m_connection.createStatement().executeQuery(
641:                        query);
642:                l.log("xaction", 1, "FINAL " + query);
643:                return result;
644:            }
645:
646:            /**
647:             * Drills a hole into the nice database driver abstraction to the JDBC3
648:             * level. Use with caution.
649:             * @param query is an SQL query statement.
650:             * @exception SQLException if something goes wrong during the query
651:             */
652:            public ResultSet backdoor(String query) throws SQLException {
653:                Logging.instance().log("sql", 2, query);
654:                Logging.instance().log("xaction", 1, "START " + query);
655:                ResultSet result = m_connection.createStatement().executeQuery(
656:                        query);
657:                Logging.instance().log("xaction", 1, "FINAL " + query);
658:                return result;
659:            }
660:
661:            //
662:            // handle prepared statements
663:            //
664:
665:            /**
666:             * Predicate to tell the schema, if using a string instead of number
667:             * will result in the speedier index scans instead of sequential scans.
668:             * PostGreSQL has this problem, but using strings in the place of
669:             * integers may not be universally portable.
670:             *
671:             * @return true, if using strings instead of integers and bigints
672:             * will yield better performance.
673:             *
674:             */
675:            abstract public boolean preferString();
676:
677:            /**
678:             * Inserts a new prepared statement into the list of prepared
679:             * statements. If the id is already taken, it will be
680:             * rejected.
681:             *
682:             * @param id is the id into which to parse the statement
683:             * @param statement is the before-parsing statement string
684:             * @return true, if the statement was parsed and added at the id,
685:             * false, if the id was already taken. The statement is not parsed
686:             * in that case.
687:             *
688:             * @exception SQLException may be thrown by parsing the statement.
689:             *
690:             * @see #removePreparedStatement( String )
691:             * @see #getPreparedStatement( String )
692:             * @see #cancelPreparedStatement( String )
693:             */
694:            public boolean addPreparedStatement(String id, String statement)
695:                    throws SQLException {
696:                // sanity check
697:                if (this .m_prepared == null)
698:                    throw new RuntimeException(
699:                            "You forgot to initialize the prepared statement length");
700:
701:                // duplicate check
702:                if (this .m_prepared.containsKey(id))
703:                    return false;
704:
705:                // add to id
706:                Logging.instance().log("sql", 2, statement);
707:                Logging.instance().log("xaction", 1,
708:                        "START prepare " + statement);
709:
710:                try {
711:                    this .m_prepared.put(id, this .m_connection
712:                            .prepareStatement(statement));
713:                } catch (SQLException original) {
714:                    SQLException sql = original;
715:                    for (int i = 0; sql != null; ++i) {
716:                        Logging.instance().log(
717:                                "sql",
718:                                0,
719:                                "SQL error " + i + ": " + sql.getErrorCode()
720:                                        + ": " + sql.getMessage());
721:                        sql = sql.getNextException();
722:                    }
723:                    throw original;
724:                } catch (NullPointerException e) {
725:                    Logging.instance().log("sql", 0, "stumbled over null");
726:                    e.printStackTrace();
727:                    System.exit(1);
728:                }
729:
730:                Logging.instance().log("xaction", 1,
731:                        "FINAL prepare " + statement);
732:                return true;
733:            }
734:
735:            /**
736:             * Inserts a new prepared statement into the list of prepared
737:             * statements. If the id is already taken, it will be
738:             * rejected. This method can only be used with JDBC drivers
739:             * that support auto-increment columns. It might fail with JDBC
740:             * drivers that do not support auto-increment columns, depending
741:             * on the driver's implementation.
742:             *
743:             * @param id is the id into which to parse the statement
744:             * @param statement is the before-parsing statement string
745:             * @param autoGeneratedKeys is true, if the statement should reserve
746:             * space to return autoinc columns, false, if the statement does not
747:             * have any such keys.
748:             * @return true, if the statement was parsed and added at the id,
749:             * false, if the id was already taken. The statement is not parsed
750:             * in that case.
751:             *
752:             * @exception SQLException may be thrown by parsing the statement.
753:             *
754:             * @see #removePreparedStatement( String )
755:             * @see #getPreparedStatement( String )
756:             * @see #cancelPreparedStatement( String )
757:             */
758:            protected boolean addPreparedStatement(String id, String statement,
759:                    boolean autoGeneratedKeys) throws SQLException {
760:                // sanity check
761:                if (this .m_prepared == null)
762:                    throw new RuntimeException(
763:                            "You forgot to initialize the prepared statement length");
764:
765:                // duplicate check
766:                if (this .m_prepared.containsKey(id))
767:                    return false;
768:
769:                // add to id
770:                Logging.instance().log("sql", 2, statement);
771:                Logging.instance().log("xaction", 1,
772:                        "START prepare " + statement);
773:
774:                try {
775:                    this .m_prepared.put(id, this .m_connection.prepareStatement(
776:                            statement,
777:                            autoGeneratedKeys ? Statement.RETURN_GENERATED_KEYS
778:                                    : Statement.NO_GENERATED_KEYS));
779:                } catch (SQLException original) {
780:                    SQLException sql = original;
781:                    for (int i = 0; sql != null; ++i) {
782:                        Logging.instance().log(
783:                                "sql",
784:                                0,
785:                                "SQL error " + i + ": " + sql.getErrorCode()
786:                                        + ": " + sql.getMessage());
787:                        sql = sql.getNextException();
788:                    }
789:                    throw original;
790:                } catch (NullPointerException e) {
791:                    Logging.instance().log("sql", 0, "stumbled over null");
792:                    e.printStackTrace();
793:                    System.exit(1);
794:                }
795:
796:                Logging.instance().log("xaction", 1,
797:                        "FINAL prepare " + statement);
798:                return true;
799:            }
800:
801:            /**
802:             * Inserts a new prepared statement into the list of prepared
803:             * statements. If the id is already taken, an error will be
804:             * printed and execution aborted.
805:             *
806:             * @param id is the id into which to parse the statement
807:             * @param statement is the before-parsing statement string
808:             * @return true, if the statement was parsed and added at the id,
809:             * false, if the id was already taken. The statement is not parsed
810:             * in that case.
811:             *
812:             * @exception SQLException may be thrown by parsing the statement.
813:             *
814:             * @see #addPreparedStatement( String, String )
815:             * @see #getPreparedStatement( String )
816:             * @see #cancelPreparedStatement( String )
817:             */
818:            public boolean insertPreparedStatement(String id, String statement)
819:                    throws SQLException {
820:                boolean result = addPreparedStatement(id, statement);
821:                if (result == false) {
822:                    System.err.println("Duplicate key " + id);
823:                    System.exit(1);
824:                }
825:                return result;
826:            }
827:
828:            /**
829:             * Obtains a reference to a prepared statement to be used from
830:             * the caller. This function will also reset the input values
831:             * in the prepared statement.
832:             *
833:             * @param id is the place of the statement to free up.
834:             * @exception SQLException if the database does not like the disconnect.
835:             *
836:             * @see java.sql.PreparedStatement#clearParameters()
837:             * @see #addPreparedStatement( String, String )
838:             * @see #removePreparedStatement( String )
839:             * @see #cancelPreparedStatement( String )
840:             */
841:            public PreparedStatement getPreparedStatement(String id)
842:                    throws SQLException {
843:                PreparedStatement result = (PreparedStatement) this .m_prepared
844:                        .get(id);
845:                if (result != null)
846:                    result.clearParameters();
847:                else
848:                    throw new SQLException("unknown prepared statement " + id);
849:                return result;
850:            }
851:
852:            /**
853:             * Explicitely requests a prepared id to be destroyed and its resources
854:             * freed. Multiple invocation for the same id are harmless.
855:             *
856:             * @param id is the place of the statement to free up.
857:             * @exception SQLException if the database does not like the disconnect.
858:             *
859:             * @see #addPreparedStatement( String, String )
860:             * @see #getPreparedStatement( String )
861:             * @see #cancelPreparedStatement( String )
862:             */
863:            public void removePreparedStatement(String id) throws SQLException {
864:                PreparedStatement ps = (PreparedStatement) this .m_prepared
865:                        .remove(id);
866:                if (ps != null)
867:                    ps.close();
868:            }
869:
870:            /**
871:             * Cancels and resets all previous values of a prepared statement.
872:             *
873:             * @param id is the id for which to obtain the previously
874:             * prepared statement.
875:             *
876:             * @exception SQLException if a database access error occurs while
877:             * clearing the parameters.
878:             * @exception ArrayIndexOutOfBoundsException if a non-existing id
879:             * is being requested.
880:             *
881:             * @see java.sql.PreparedStatement#clearParameters()
882:             * @see #addPreparedStatement( String, String )
883:             * @see #getPreparedStatement( String )
884:             * @see #removePreparedStatement( String )
885:             */
886:            public void cancelPreparedStatement(String id) throws SQLException,
887:                    ArrayIndexOutOfBoundsException {
888:                PreparedStatement ps = (PreparedStatement) this.m_prepared
889:                        .get(id);
890:                if (ps != null) {
891:                    ps.cancel();
892:                    ps.clearParameters();
893:                }
894:            }
895:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.