Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: javatools/db/DbDatabase.java


1   /*
2       Javatools (modified version) - Some useful general classes.
3       Copyright (C) 2002-2003  Chris Bitmead (original) Antonio Petrelli (modified)
4   
5       This program is free software; you can redistribute it and/or modify
6       it under the terms of the GNU General Public License as published by
7       the Free Software Foundation; either version 2 of the License, or
8       (at your option) any later version.
9   
10      This program is distributed in the hope that it will be useful,
11      but WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13      GNU General Public License for more details.
14  
15      You should have received a copy of the GNU General Public License
16      along with this program; if not, write to the Free Software
17      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  
19      Contact me at: brenmcguire@users.sourceforge.net
20   */
21  package javatools.db;
22  import java.util.*;
23  import java.sql.*;
24  import java.io.*;
25  import javatools.util.FileLog;
26  
27  /**
28   * A class that represents a particular database. A DbDatabase basically
29   * consists of some connection parameters plus we keep track of the open
30   * connections. The constructor is not public. Use DbManager.getDatabase().
31   *
32   * @author Chris Bitmead (original), Antonio Petrelli (modified)
33   * @created 29 August 2001
34   * @version 0.1.10
35   * @commentedby Antonio Petrelli
36   */
37  public class DbDatabase {
38      /** A map to reference each thread to each connection.
39       */    
40    Map threadConnectionMap = new HashMap();
41          /** A map to reference each connection to each thread.
42           */        
43    Map connectionThreadMap = new HashMap();
44          /** A map to access easily tables.
45           */        
46    Map tables = new HashMap();
47          /** The manager for databases.
48           */        
49    DbManager manager;
50          /** The name of this DBMS.
51           */        
52    String name;
53          /** The JDBC driver to access this DBMS.
54           */        
55    String driver;
56          /** The connection string for this DBMS-database.
57           */        
58    String connectString;
59          /** The user name to use in connection.
60           */        
61    String userName;
62          /** The password to use in connection.
63           */        
64    String password;
65          /** <CODE>true</CODE>: each database update is autocommitted;
66           * <CODE>false</CODE>: commit must be made manually.
67           */        
68          boolean autoCommit = true;
69  
70          /** Builds a new DbDatabase empty object.
71           */        
72          public DbDatabase() {
73          }
74          
75          /** Builds a new DbDatabase object.
76           * @param manager The manager of all databases.
77           * @param name The name of DBMS.
78           * @param driver The JDBC driver for this DBMS.
79           * @param connectString The connection string to connect the DBMS to.
80           * @param userName the user name to be used in connection.
81           * @param password The password to be used in connection.
82           */        
83    public DbDatabase(DbManager manager, String name, String driver, String connectString, String userName, String password) {
84      this.manager = manager;
85      this.name = name;
86      this.driver = driver;
87      this.connectString = connectString;
88      this.userName = userName;
89      this.password = password;
90                  getEmulationsNeeded();
91    }
92          
93          /** Sets autocommit property.
94           * @param pAutoCommit <CODE>true</CODE>: each database update is autocommitted;
95           * <CODE>false</CODE>: commit must be made manually.
96           */        
97          public void setAutoCommit(boolean pAutoCommit) {
98              autoCommit = pAutoCommit;
99          }
100 
101   /**
102          * Set a property for this database.
103          *
104          * @param pname The new property name
105          * @param value            The new property value
106          * @exception DbException If something goes wrong.
107          */
108   public void setProperty(String pname, String value) throws DbException {
109     try {
110       if (name != null) {
111         pname = name + "." + pname;
112       }
113       manager.getProps().setProperty(pname, value);
114     } catch (IOException e) {
115       throw new DbException("Can't find db.properties", e);
116     }
117   }
118 
119   /**
120          * A database can have a set of properties associated with it. We use <dbname>
121          * .<parametername>
122          *
123          * in a properties file and by default we use "driver", "userId", "password"
124          * and "connect".
125          *
126          * @param pname The name of the property.
127          * @return The property value
128          * @exception DbException If something goes wrong.
129          */
130   public String getProperty(String pname) throws DbException {
131     try {
132       if (name != null) {
133         pname = name + "." + pname;
134       }
135       String rtn = manager.getProps().getProperty(pname);
136       if (rtn == null) {
137         throw new DbException("Can't find DbDatabase property: '" + pname + "' in Props: '" + manager.getProps().getFullName() + "\n" + manager.getProps().toString());
138       }
139       return rtn;
140     } catch (IOException e) {
141       throw new DbException("Can't find db.properties", e);
142     }
143   }
144 
145   /**
146          * Return an object representing a particular table in the database.
147          *
148          * @param name The name of the table.
149          * @return The table value
150          * @exception DbException If something goes wrong.
151          */
152   public DbTable getTable(String name) throws DbException {
153     // I guess we really should cache these.
154     try {
155       DbTable rtn = (DbTable) tables.get(name);
156       if (rtn == null) {
157         DbConnection con = getNewConnection();
158         PreparedStatement ps = con.con.prepareStatement("SELECT * FROM " + name + " WHERE 1=0");
159         ResultSet rs = ps.executeQuery();
160         rtn = new DbTable(this);
161         rtn.setResultSet(ps, rs);
162         rtn.setTableName(name);
163         tables.put(name, rtn);
164         ps.close();
165         con.close();
166       }
167       return rtn;
168     } catch (SQLException e) {
169       throw new DbException(e);
170     }
171   }
172         
173         /** Returns a joined table.
174          * @param tableLeft The table to be joined on the left.
175          * @param tableRight The table to be joined on the right.
176          * @param joinType The type of joining.
177          * @param joinCondition The join condition.
178          * @throws DbException If something goes wrong.
179          * @return The joined table.
180          */        
181         public DbJoinedTable getJoinedTable(DbAbstractTable tableLeft,
182                 DbAbstractTable tableRight, int joinType, DbExpr joinCondition)
183                 throws DbException {
184             return new DbJoinedTable(this, tableLeft, tableRight, joinType,
185                 joinCondition);
186         }
187 
188         /** Ahem... uncommented. It is obscure, call Chris Bitmead.
189          * @param name A name?
190          * @return A DbSequence.
191          */        
192   public DbSequence getSequence(String name) {
193     return new DbSequence(this, name);
194   }
195 
196   /**
197          * Get a DbConnection that will be associated with this Thread.
198          *
199          * @return The threadConnection value
200          * @exception DbException If something goes wrong.
201          */
202   public synchronized DbConnection getThreadConnection() throws DbException {
203     Thread thread = Thread.currentThread();
204     DbConnection rtn = (DbConnection) threadConnectionMap.get(thread);
205     if (rtn == null || rtn.isClosed()) {
206       FileLog.singleton().debug("getThreadConnection", "creating Connection");
207       rtn = getNewConnection();
208       threadConnectionMap.put(thread, rtn);
209       connectionThreadMap.put(rtn, thread);
210     }
211     FileLog.singleton().debug("getThreadConnection", "returning Connection: " + rtn + " for thread: " + Thread.currentThread().getName());
212     return rtn;
213   }
214 
215   /**
216          * Get a DbConnection that will be associated with this Thread, but only if
217          * one exists already.
218          *
219          * @return The existingThreadConnection value
220          * @exception DbException If something goes wrong.
221          */
222   public synchronized DbConnection getExistingThreadConnection() throws DbException {
223     Thread thread = Thread.currentThread();
224     DbConnection rtn = (DbConnection) threadConnectionMap.get(thread);
225     return rtn;
226   }
227 
228   /**
229          * Return a brand new DbConnection.
230          *
231          * @return The newConnection value
232          * @exception DbException If something goes wrong.
233          */
234   public DbConnection getNewConnection() throws DbException {
235     try {
236       Class.forName(driver);
237     } catch (ClassNotFoundException e) {
238       throw new DbException("SQL Driver class not found", e);
239     }
240     try {
241       Connection conn = DriverManager.getConnection(connectString, userName, password);
242       conn.setAutoCommit(autoCommit);
243       return new DbConnection(this, conn);
244     } catch (SQLException e) {
245                         System.out.println(e.getMessage());
246       throw new DbException(e);
247     }
248   }
249 
250         /** Checks if a DbDatabase object equals this one.
251          * @param o The object to compare to.
252          * @return <CODE>true</CODE>: the objects are equal;
253          * <CODE>false</CODE>: otherwise.
254          */        
255   public boolean equals(Object o) {
256     if (!(o instanceof DbDatabase)) {
257       return false;
258     }
259     DbDatabase db = (DbDatabase) o;
260     return name.equals(db.name);
261   }
262 
263   /**
264          * Create a new DbSelector.
265          *
266          * @return A selector to perform SELECT operation.
267          * @exception DbException If something goes wrong.
268          */
269   public DbSelector selector() throws DbException {
270     return new DbSelector(this);
271   }
272 
273   /**
274          * Does this thread have a default connection associated with it? (i.e. has
275          * this Thread called getThreadConnection()).
276          *
277          * @return <CODE>true</CODE>: Yes it does;
278          * <CODE>false</CODE>: No it does not.
279          */
280   public boolean hasThreadConnection() {
281     Thread thread = Thread.currentThread();
282     DbConnection con = (DbConnection) threadConnectionMap.get(thread);
283     return con != null;
284   }
285 
286   /**
287          * Return an expression representing an SQL true expression. We use the
288          * expression "0 = 0" for this purpose. This is handy when using complex code
289          * to construct a big conditional clause, it can be easier to start with a
290          * true expression and "AND" expressions onto the end.
291          *
292          * @return A true expression.
293          */
294   public DbExpr trueExpr() {
295     return new DbTrueExpr(this);
296   }
297 
298   /**
299          * Return an expression representing an SQL false expression. We use the
300          * expression "0 = 1" for this purpose. This is handy when using complex code
301          * to construct a big conditional clause, it can be easier to start with a
302          * false expression and "OR" expressions onto the end.
303          *
304          * @return A false expression.
305          */
306   public DbExpr falseExpr() {
307     return new DbFalseExpr(this);
308   }
309         
310         /** Returns a value list.
311          * @param col The collection containing the value list.
312          * @return The value list.
313          */        
314         public DbExpr valueList(Collection col) {
315             return new DbValueList(this, col);
316         }
317 
318         /** A database to a string? Ok if you want it...
319          * @return A string representing the database.
320          */        
321   public String toString() {
322     return "DbDatabase: " + name;
323   }
324         
325         public String getUserName() {
326             return userName;
327         }
328         
329         public String getPassword() {
330             return password;
331         }
332         
333         /** Returns the capability of DBMS to handle foreign keys.
334          * @return <CODE>true</CODE>: the DBMS supports foreign keys;
335          * <CODE>false</CODE>: otherwise.
336          */        
337         public boolean getForeignKey() {
338             return foreignKey;
339         }
340 
341         /** Returns the capability of DBMS to handle check statements.
342          * @return <CODE>true</CODE>: the DBMS supports check clauses;
343          * <CODE>false</CODE>: otherwise.
344          */        
345         public boolean getCheckStatement() {
346             return checkStatement;
347         }
348 
349         /** Returns the capability of DBMS to handle ON DELETE CASCADE clauses.
350          * @return <CODE>true</CODE>: the DBMS supports ON DELETE CASCADE clauses;
351          * <CODE>false</CODE>: otherwise.
352          */        
353         public boolean getOnDeleteCascade() {
354             return onDeleteCascade;
355         }
356 
357         /** Returns the capability of DBMS to handle ON DELETE SET DEFAULT clauses.
358          * @return <CODE>true</CODE>: the DBMS supports ON DELETE SET DEFAULT clauses;
359          * <CODE>false</CODE>: otherwise.
360          */        
361         public boolean getOnDeleteSetDefault (){
362             return onDeleteSetDefault;
363         }
364 
365         /** Returns the capability of DBMS to handle ON DELETE SET NULL clauses.
366          * @return <CODE>true</CODE>: the DBMS supports ON DELETE SET NULL clauses;
367          * <CODE>false</CODE>: otherwise.
368          */        
369         public boolean getOnDeleteSetNull() {
370             return onDeleteSetNull;
371         }
372 
373         /** Returns the capability of DBMS to handle ON UPDATE CASCADE clauses.
374          * @return <CODE>true</CODE>: the DBMS supports ON UPDATE CASCADE clauses;
375          * <CODE>false</CODE>: otherwise.
376          */        
377         public boolean getOnUpdateCascade() {
378             return onUpdateCascade;
379         }
380 
381         /** Returns the capability of DBMS to handle ON UPDATE SET DEFAULT clauses.
382          * @return <CODE>true</CODE>: the DBMS supports ON UPDATE SET DEFAULT clauses;
383          * <CODE>false</CODE>: otherwise.
384          */        
385         public boolean getOnUpdateSetDefault() {
386             return onUpdateSetDefault;
387         }
388 
389         /** Returns the capability of DBMS to handle ON UPDATE SET NULL clauses.
390          * @return <CODE>true</CODE>: the DBMS supports ON UPDATE SET NULL clauses;
391          * <CODE>false</CODE>: otherwise.
392          */        
393         public boolean getOnUpdateSetNull (){
394             return onUpdateSetNull;
395         }
396 
397   /**
398    *  Notify the DbDatabase that one of its connections has closed.
399    *
400    * @param  con  Description of Parameter
401    */
402   void notifyClose(DbConnection con) {
403     Object thread = connectionThreadMap.get(con);
404     if (thread != null) {
405       connectionThreadMap.remove(con);
406       threadConnectionMap.remove(thread);
407     }
408   }
409         
410     // Variables for needed emulation...
411     
412     /** A flag indicating if a DBMS supports foreign keys.
413      * <CODE>true</CODE>: the DBMS supports foreign keys;
414      * <CODE>false</CODE>: otherwise.
415      */
416     protected boolean foreignKey;
417     /** A flag indicating if a DBMS supports check clauses in its constraints.
418      * <CODE>true</CODE>: the DBMS supports check clauses;
419      * <CODE>false</CODE>: otherwise.
420      */    
421     protected boolean checkStatement;
422     /** A flag indicating if a DBMS supports ON DELETE CASCADE clauses in its
423      * constraints.
424      * <CODE>true</CODE>: the DBMS supports ON DELETE CASCADE clauses;
425      * <CODE>false</CODE>: otherwise.
426      */    
427     protected boolean onDeleteCascade;
428     /** A flag indicating if a DBMS supports ON DELETE SET DEFAULT clauses in its
429      * constraints.
430      * <CODE>true</CODE>: the DBMS supports ON DELETE SET DEFAULT clauses;
431      * <CODE>false</CODE>: otherwise.
432      */    
433     protected boolean onDeleteSetDefault;
434     /** A flag indicating if a DBMS supports ON DELETE SET NULL clauses in its
435      * constraints.
436      * <CODE>true</CODE>: the DBMS supports ON DELETE SET NULL clauses;
437      * <CODE>false</CODE>: otherwise.
438      */    
439     protected boolean onDeleteSetNull;
440     /** A flag indicating if a DBMS supports ON UPDATE CASCADE clauses in its
441      * constraints.
442      * <CODE>true</CODE>: the DBMS supports ON UPDATE CASCADE clauses;
443      * <CODE>false</CODE>: otherwise.
444      */    
445     protected boolean onUpdateCascade;
446     /** A flag indicating if a DBMS supports ON UPDATE SET DEFAULT clauses in its
447      * constraints.
448      * <CODE>true</CODE>: the DBMS supports ON UPDATE SET DEFAULT clauses;
449      * <CODE>false</CODE>: otherwise.
450      */    
451     protected boolean onUpdateSetDefault;
452     /** A flag indicating if a DBMS supports ON UPDATE SET NULL clauses in its
453      * constraints.
454      * <CODE>true</CODE>: the DBMS supports ON UPDATE SET NULL clauses;
455      * <CODE>false</CODE>: otherwise.
456      */    
457     protected boolean onUpdateSetNull;
458         
459     private void getEmulationsNeeded() {
460         foreignKey          = false;
461         checkStatement      = false;
462         onDeleteCascade     = false;
463         onDeleteSetDefault  = false;
464         onDeleteSetNull     = false;
465         onUpdateCascade     = false;
466         onUpdateSetDefault  = false;
467         onUpdateSetNull     = false;
468         try {
469             foreignKey = string2boolean(getProperty("foreignKey"));
470             if (foreignKey) {
471                 checkStatement      = string2boolean(getProperty("checkStatement"));
472                 onDeleteCascade     = string2boolean(getProperty("onDeleteCascade"));
473                 onDeleteSetDefault  = string2boolean(getProperty("onDeleteSetDefault"));
474                 onDeleteSetNull     = string2boolean(getProperty("onDeleteSetNull"));
475                 onUpdateCascade     = string2boolean(getProperty("onUpdateCascade"));
476                 onUpdateSetDefault  = string2boolean(getProperty("onUpdateSetDefault"));
477                 onUpdateSetNull     = string2boolean(getProperty("onUpdateSetNull"));
478             }
479         }
480         catch (DbException e) {
481         }
482     }
483     
484     private boolean string2boolean (String value) {
485         if (value.equals("true"))
486             return true;
487         else
488             return false;
489     }
490 }