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

Quick Search    Search Deep

Source code: com/lutris/appserver/server/sql/StandardDatabaseManager.java


1   /*
2    * Enhydra Java Application Server Project
3    * 
4    * The contents of this file are subject to the Enhydra Public License
5    * Version 1.1 (the "License"); you may not use this file except in
6    * compliance with the License. You may obtain a copy of the License on
7    * the Enhydra web site ( http://www.enhydra.org/ ).
8    * 
9    * Software distributed under the License is distributed on an "AS IS"
10   * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 
11   * the License for the specific terms governing rights and limitations
12   * under the License.
13   * 
14   * The Initial Developer of the Enhydra Application Server is Lutris
15   * Technologies, Inc. The Enhydra Application Server and portions created
16   * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
17   * All Rights Reserved.
18   * 
19   * Contributor(s):
20   * 
21   * $Id: StandardDatabaseManager.java,v 1.20.12.1 2000/10/19 17:59:05 jasona Exp $
22   */
23  
24  
25  
26  
27  
28  package com.lutris.appserver.server.sql;
29  
30  import com.lutris.util.*;
31  import com.lutris.appserver.server.Enhydra;
32  import com.lutris.appserver.server.sql.*;
33  import com.lutris.appserver.server.sql.standard.StandardLogicalDatabase;
34  import com.lutris.appserver.server.sql.oracle.OracleLogicalDatabase;
35  import com.lutris.appserver.server.sql.informix.InformixLogicalDatabase;
36  import com.lutris.appserver.server.sql.sybase.SybaseLogicalDatabase;
37  import com.lutris.appserver.server.sql.msql.MsqlLogicalDatabase;
38  import com.lutris.appserver.server.sql.postgresql.PostgreSQLLogicalDatabase;
39  import java.sql.*;
40  import java.util.Date;
41  import java.util.Hashtable;
42  import java.util.Enumeration;
43  
44  
45  /**
46   * The standard database manager implementation. A database manager
47   * manages logical databases. It provides a single object from which
48   * database connections, object ids (OIDs), transactions and queries
49   * can be obtained. The configuration file specifies what logical
50   * database to create.
51   * <P>
52   * The configuration data is specified as follows:
53   * <UL>
54   * <LI> <B><CODE>DatabaseManager.Databases</CODE></B> -
55   *  A list of logical SQL database names.
56   * <LI> <B><CODE>DatabaseManager.DefaultDatabase</CODE></B> -
57   *  The default logical database used by this application. Optional,
58   *  if not specified, then the first entry in
59   *  "DatabaseManager.Databases" is used.
60   * <LI> <B><CODE>DatabaseManager.Debug</CODE></B> -
61   *  Specify true to enable Query and Transaction logging, false to
62   *  disable it. Optional, false if not specified.
63   * </UL>
64   * For each logical database, there is a set of entry names in the form
65   * <B><CODE>DatabaseManager.DB.<I>dbname</I></CODE></B>.
66   * Where <CODE><I>dbname</I></CODE> is one of the listed logical databases.
67   * <P>
68   * <B><CODE>DatabaseManager.DB.<I>dbname</I>.ClassType</CODE></B> -
69   * This is an optional field which specifies the class of the logical
70   * database implementation or a symbolic name if one on the standard types
71   * are selected. This is recommended because although JDBC abstracts the
72   * data access, the functionality of each database is slightly different
73   * and this parameter allows for optimised usage. The following are
74   * standard types:
75   * <UL>
76   * <LI> <I>Oracle</I> - For optimized Oracle 7/8 usage.
77   * <LI> <I>Informix</I> - For optimized Informix usage.
78   * <LI> <I>Sybase</I> - For optimized Sybase usage.
79   * <LI> <I>Msql</I> - For optimized Microsoft MSQL usage.
80   * <LI> <I>Standard</I> - For all other JDBC databases. <B>(Default)</B>
81   * <LI> <I>class</I> - For vendor supplied database classes.
82   * </UL>
83   * <P>
84   * Note that since a single SQL user is used to access the database by
85   * the entire application, connections maybe kept open, thus saving this
86   * overhead on each request.  Connections are opened as desired until
87   * the maximum configured is reached.
88   * <P>
89   * If a thread needs to process a transaction, it requests a connection.
90   * If none are available, then a new connection is created up to the
91   * configured maximum.  A thread is queued waiting for a connection to be
92   * returned if a new connection can't be created.
93   * <P>
94   * Note also that multiple logical names may map to the same actual
95   * database, making it easy to migrate databases if necessary and to
96   * provide access through multiple users.
97   *
98   * @version  $Revision: 1.20.12.1 $
99   * @since  LBS1.8
100  * @author  Paul Morgan
101  * @author  Kyle Clark
102  */
103 public class StandardDatabaseManager implements DatabaseManager {
104 
105     /**
106      * Table of named logical databases.
107      */
108     private Hashtable logicalDatabases = new Hashtable ();
109 
110     /**
111      * Default logical database.
112      */
113     private LogicalDatabase defaultLogicalDatabase = null;
114 
115     /**
116      * Controls debugging for Transactions and Queries.
117      */
118     protected boolean debug = false;
119 
120 
121     /**
122      * Creates a new <code>DatabaseManager</code> object and configures
123      * the logical databases defined in the config file.
124      *
125      * @param config
126      *  The configuration data for logical databases.
127      * @exception ConfigException
128      *  If there is an error in the configuration file.
129      * @exception DatabaseManagerException
130      *  If a logical database name is specified twice in the configuration file.
131      * @exception SQLException
132      *  If a SQL error occurs.
133      */
134     public StandardDatabaseManager(Config config)
135         throws ConfigException, DatabaseManagerException, SQLException {
136 
137         String[] databases = config.getStrings ("Databases");
138         if (databases == null)
139             return;
140 
141   /**
142    * Configure each logical database.
143    */
144   Config dbConfig;
145         for (int idx = 0; idx < databases.length; idx++) {
146       String dbName = databases[idx];
147       try {
148     dbConfig = (Config)config.getSection("DB." + dbName);
149       } catch (KeywordValueException except) {
150     throw new ConfigException("No DatabaseManager.DB." + dbName + " defined in config file.");
151       }
152 
153       if (logicalDatabases.get (dbName) != null) {
154     throw new DatabaseManagerException
155     ("duplicate logical database name: \"" + dbName + "\"");
156       }
157 
158       LogicalDatabase logicalDatabase =
159     loadLogicalDatabase (dbName, dbConfig);
160 
161       logicalDatabases.put (dbName, logicalDatabase);
162         }
163 
164   /**
165    * Set default database if supplied.
166    */
167         String defaultDB = config.getString ("DefaultDatabase", databases[0]);
168         setDefaultDatabase(defaultDB);
169 
170   /**
171    * Set debug logging of Queries and Transactions.
172    */
173         boolean debugLogging = config.getBoolean ("Debug", false);
174   setDebugLogging(debugLogging);
175 
176   /**
177    * Set the oid and version column names in CoreDO.
178    * Note that these could be configured for each logical
179    * database but this would require some complex extensions
180    * to DBQuery and DBTransaction in order to ensure that
181    * the correct values were always being used without
182    * creating race conditions.
183    * This means that the limitation is currently that all
184    * databases accessed by your application must use the
185    * same column names.
186    */
187         String oidColumnName = config.getString("ObjectIdColumnName", null);
188   if (oidColumnName != null) {
189             CoreDO.setOIdColumnName(oidColumnName);
190   }
191         String versionColumnName = config.getString("VersionColumnName", null);
192   if (versionColumnName != null) {
193             CoreDO.setVersionColumnName(versionColumnName);
194   }
195     }
196 
197 
198     /**
199      * Actually load the specified logical database. This method provides
200      * an easy way to override the default behavour.
201      *
202      * @return
203      *   The logical database.
204      * @exception DatabaseManagerException
205      *   if an error occurs creating the logical database.
206      */
207     public LogicalDatabase loadLogicalDatabase (String dbName,
208             Config dbConfig)
209   throws DatabaseManagerException {
210 
211   LogicalDatabase lDB = null;
212   try {
213       String dbClassName = dbConfig.getString ("ClassType", "Standard");
214       if (dbClassName.equals ("Standard")) {
215     lDB = new StandardLogicalDatabase (dbName, dbConfig);
216       } else if (dbClassName.equals ("Oracle")) {
217     lDB = new OracleLogicalDatabase (dbName, dbConfig);
218       } else if (dbClassName.equals ("Informix")) {
219     lDB = new InformixLogicalDatabase (dbName, dbConfig);
220       } else if (dbClassName.equals ("Sybase")) {
221     lDB = new SybaseLogicalDatabase (dbName, dbConfig);
222       } else if (dbClassName.equals ("Msql")) {
223     lDB = new MsqlLogicalDatabase (dbName, dbConfig);
224       } else if (dbClassName.equals ("PostgreSQL")) {
225     lDB = new PostgreSQLLogicalDatabase (dbName, dbConfig);
226       } else {
227     // Must be a custom class. Make instance and call init
228     // method to configure.  Also we must use the application
229     // class loader.
230     ClassLoader appClassLoader =
231         Enhydra.getApplication().getClass().getClassLoader();
232     Class dbClass = appClassLoader.loadClass(dbClassName);
233     lDB = (LogicalDatabase) dbClass.newInstance ();
234     lDB.init (dbName, dbConfig);
235       }
236   } catch (Exception except) {
237       throw new DatabaseManagerException ("Could not create logical database " + dbName, except);
238   }
239 
240   return lDB;
241     }
242 
243 
244     /**
245      * Allocate a connection to a thread. The connection should be returned
246      * to the allocator by calling its
247      * <a href=com.lutris.appserver.server.sql.DBConnection#release>
248      * release()</a> function.  A thread will wait if
249      * no connections are available.
250      * Interupted exceptions are converted to
251      * errors.
252      * N.B. Can't be synchronized, as connection allocator
253      * <CODE>allocate</CODE> may wait.
254      *
255      * @param dbName
256      *   Logical name of the database to allocate a connection to.
257      * @return
258      *   The allocated connection object.
259      * @exception DatabaseManagerException
260      *   If a nonexistent logical database name is supplied.
261      * @exception SQLException
262      *   If a SQL error occures.
263      */
264     public DBConnection allocateConnection (String dbName)
265         throws DatabaseManagerException, SQLException {
266 
267         LogicalDatabase logicalDatabase = findLogicalDatabase (dbName);
268         return logicalDatabase.allocateConnection();
269     }
270 
271 
272     /**
273      * Allocate a connection to a thread. The connection should be returned
274      * to the allocator by calling its
275      * <a href=com.lutris.appserver.server.sql.DBConnection#release>
276      * release()</a> function.  A thread will wait if
277      * no connections are available.
278      * Interupted exceptions are converted to
279      * errors.  The connection is allocated from the default logical
280      * database.
281      *
282      * @return
283      *   The allocated connection object.
284      * @exception DatabaseManagerException
285      *   If no default logical database has been set.
286      * @exception SQLException
287      *   If a SQL error occurs.
288      * @see
289      *   #setDefaultDatabase
290      */
291     public DBConnection allocateConnection ()
292         throws DatabaseManagerException, SQLException {
293 
294         if (defaultLogicalDatabase == null)
295             throw new DatabaseManagerException ("Default logical database " +
296                                                  "has not been specified.");
297         return defaultLogicalDatabase.allocateConnection ();
298     }
299 
300 
301     /**
302      * Allocate an object id from the specified logical database.
303      *
304      * @param name
305      *   Logical name of the database from which to obtain an object id.
306      * @return The allocated unique OID
307      * @exception DatabaseManagerException
308      *   If a nonexistent logical database name is supplied.
309      * @exception ObjectIdException
310      *   If a problem (e.g. SQL error) occured in obtaining the OID.
311      */
312     public ObjectId allocateObjectId (String dbName)
313         throws DatabaseManagerException, ObjectIdException {
314 
315         LogicalDatabase logicalDatabase = findLogicalDatabase (dbName);
316         return logicalDatabase.allocateObjectId();
317     }
318 
319 
320     /**
321      * Allocate an object id from the specified logical database.
322      *
323      * @return The allocated connection object.
324      * @exception DatabaseManagerException
325      *   If a nonexistent default logical database has been set.
326      * @exception ObjectIdException
327      *   If a problem (e.g. SQL error) occured in obtaining the OID.
328      * @see
329      *   #setDefaultDatabase
330      */
331     public ObjectId allocateObjectId ()
332         throws DatabaseManagerException, ObjectIdException {
333 
334         if (defaultLogicalDatabase == null)
335             throw new DatabaseManagerException ("Default logical database " +
336                                                  "has not been specified.");
337         return defaultLogicalDatabase.allocateObjectId ();
338     }
339 
340 
341     /**
342      * Create a transaction object for the specified logical database.
343      *
344      * @param dbName
345      *   Logical name of the database from which to obtain a transaction.
346      * @return The transaction
347      * @exception DatabaseManagerException
348      *   If a nonexistent or invalid logical database name is supplied.
349      * @exception SQLException
350      *   If a problem occured creating the transaction.
351      */
352     public DBTransaction createTransaction (String dbName)
353         throws DatabaseManagerException, SQLException {
354 
355         LogicalDatabase logicalDatabase = findLogicalDatabase (dbName);
356         return logicalDatabase.createTransaction ();
357     }
358 
359 
360     /**
361      * Create a transaction object for the default logical database.
362      *
363      * @param dbName
364      *   Logical name of the database from which to obtain a transaction.
365      * @return The transaction
366      * @exception DatabaseManagerException
367      *   If a nonexistent default logical database has been set.
368      * @exception SQLException
369      *   If a problem occured creating the transaction.
370      * @see
371      *   #setDefaultDatabase
372      */
373     public DBTransaction createTransaction ()
374         throws DatabaseManagerException, SQLException {
375 
376         if (defaultLogicalDatabase == null)
377             throw new DatabaseManagerException ("Default logical database " +
378                                                  "has not been specified.");
379         return defaultLogicalDatabase.createTransaction ();
380     }
381 
382 
383     /**
384      * Create a query object for the specified logical database.
385      *
386      * @param dbName
387      *   Logical name of the database from which to obtain a query.
388      * @return The query
389      * @exception DatabaseManagerException
390      *   If a nonexistent or invalid logical database name is supplied.
391      * @exception SQLException
392      *   If a problem occured creating the query.
393      */
394     public DBQuery createQuery (String dbName)
395         throws DatabaseManagerException, SQLException {
396 
397         LogicalDatabase logicalDatabase = findLogicalDatabase (dbName);
398         return logicalDatabase.createQuery ();
399     }
400 
401 
402     /**
403      * Create a query object for the default logical database.
404      *
405      * @param dbName
406      *   Logical name of the database from which to obtain a query.
407      * @return The query
408      * @exception DatabaseManagerException
409      *   If a nonexistent default logical database has been set.
410      * @exception SQLException
411      *   If a problem occured creating the query.
412      * @see
413      *   #setDefaultDatabase
414      */
415     public DBQuery createQuery ()
416         throws DatabaseManagerException, SQLException {
417 
418         if (defaultLogicalDatabase == null)
419             throw new DatabaseManagerException ("Default logical database " +
420                                                  "has not been specified.");
421         return defaultLogicalDatabase.createQuery ();
422     }
423 
424 
425     /**
426      * Find the named logical database in hash table.
427      *
428      * @param dbName Logical name of the database to locate.
429      * @exception DatabaseManagerException If a nonexistant logical database
430      *  name is supplied.
431      */
432     private LogicalDatabase findLogicalDatabase (String dbName)
433         throws DatabaseManagerException {
434 
435         LogicalDatabase logicalDatabase =
436       (LogicalDatabase) logicalDatabases.get (dbName);
437         if (logicalDatabase == null) {
438             throw new DatabaseManagerException
439                 ("unknown logical database name: \"" +
440                  dbName + "\"");
441         }
442         return logicalDatabase;
443     }
444 
445 
446     /**
447      * Set the default logical database. This should only be called
448      * after the logical database
449      * (<A HREF=com.lutris.appserver.server.sql.LogicalDatabase></A>
450      * has been established.
451      *
452      * @param dbName The default logical database.
453      * @exception DatabaseManagerException
454      *   if the logical database name is invalid or not found.
455      */
456     public void setDefaultDatabase (String dbName)
457         throws DatabaseManagerException {
458 
459         defaultLogicalDatabase = findLogicalDatabase (dbName);
460     }
461 
462     /**
463      * Shutdown the database manager. All logical databases will be
464      * shutdown and all connections closed.
465      */
466     public void shutdown () {
467 
468   for (Enumeration keys = logicalDatabases.keys ();
469     keys.hasMoreElements();) {
470 
471       LogicalDatabase logicalDatabase = (LogicalDatabase)
472     logicalDatabases.get ((String)keys.nextElement());
473 
474       logicalDatabase.shutdown();
475   }
476     }
477 
478 
479     //====================================================================
480     // The following are primarily for management purposes...
481     //====================================================================
482 
483     /**
484      * Returns the list of managed logical databases.
485      *
486      * @return  List of logical database names.
487      */
488     public String[] getLogicalDatabaseNames () {
489 
490   String[] names = new String[logicalDatabases.size()];
491   int idx = 0;
492         Enumeration keys = logicalDatabases.keys();
493         while (keys.hasMoreElements()) {
494             names[idx++] = (String) keys.nextElement();
495         }
496   return names;
497     }
498 
499 
500     /**
501      * Returns a description of the logical database type.
502      *
503      * @param dbName
504      *   The logical database name.
505      * @return
506      *   A text description of the logical database type.
507      * @exception DatabaseManagerException
508      *   If a nonexistent logical database name is supplied.
509      */
510     public String getType(String dbName)
511   throws DatabaseManagerException {
512 
513         LogicalDatabase logicalDatabase = findLogicalDatabase (dbName);
514         return logicalDatabase.getType();
515     }
516 
517 
518     /**
519      * Gets the number of requests made to the database since startup time.
520      *
521      * @param  The name of the logical database.
522      * @exception DatabaseManagerException
523      *   If a nonexistent logical database name is supplied.
524      * @return  The number of database requests since the server started.
525      */
526     public long getRequestCount (String dbName)
527         throws DatabaseManagerException {
528 
529         LogicalDatabase logicalDatabase = findLogicalDatabase (dbName);
530         return logicalDatabase.getRequestCount();
531     }
532 
533 
534     /**
535      * Gets the number of currently active connections.
536      *
537      * @param  dbName The name of the logical database.
538      * @exception DatabaseManagerException
539      *   If a nonexistent logical database name is supplied.
540      * @return  The number of currently active connections.
541      */
542     public int getActiveConnectionCount (String dbName)
543         throws DatabaseManagerException {
544 
545         LogicalDatabase logicalDatabase = findLogicalDatabase (dbName);
546         return logicalDatabase.getActiveConnectionCount();
547     }
548 
549 
550     /**
551      * Gets the maximum number of concurent connections that existed
552      * at any time since this object was created, or
553      * <CODE>resetMaxConnectionCount()</CODE> was called.
554      * This is a historical highwater mark.
555      * If you do not implement this feature, return -1.
556      *
557      * @param  dbName The name of the logical database.
558      * @exception DatabaseManagerException
559      *   If a nonexistent logical database name is supplied.
560      * @return The highwater mark for number of connections, or -1.
561      */
562     public int getMaxConnectionCount (String dbName)
563         throws DatabaseManagerException {
564 
565         LogicalDatabase logicalDatabase = findLogicalDatabase (dbName);
566         return logicalDatabase.getMaxConnectionCount();
567     }
568 
569 
570     /**
571      * Gets the time when the maximum refered to by
572      * <CODE>maxConnectionCount()</CODE> occured.
573      *
574      * @param  dbName The name of the logical database.
575      * @exception DatabaseManagerException
576      *   If a nonexistent logical database name is supplied.
577      * @return The Date of when the maximum number of connections occured.
578      */
579     public Date getMaxConnectionCountDate (String dbName)
580         throws DatabaseManagerException {
581 
582         LogicalDatabase logicalDatabase = findLogicalDatabase (dbName);
583         return logicalDatabase.getMaxConnectionCountDate();
584     }
585 
586 
587     /**
588      * Reset the maximum connection count. See
589      * <CODE>maxConnectionCount()</CODE>. The highwater mark should be
590      * reset to the current number of connections.
591      *
592      * @param  dbName The name of the logical database.
593      * @exception DatabaseManagerException
594      *   If a nonexistent logical database name is supplied.
595      */
596     public void resetMaxConnectionCount (String dbName)
597         throws DatabaseManagerException {
598 
599         LogicalDatabase logicalDatabase = findLogicalDatabase (dbName);
600         logicalDatabase.resetMaxConnectionCount();
601   return;
602     }
603 
604 
605     /**
606      * Turn debugging on or off.
607      *
608      * @param  condition on of off.
609      */
610     public void setDebugLogging (boolean condition) {
611   debug = condition;
612     }
613 }