KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > opensubsystems > core > persist > db > connectionpool > PooledDatabaseConnectionFactoryImpl


1 /*
2  * Copyright (c) 2003 - 2007 OpenSubsystems s.r.o. Slovak Republic. All rights reserved.
3  *
4  * Project: OpenSubsystems
5  *
6  * $Id: PooledDatabaseConnectionFactoryImpl.java,v 1.8 2007/01/07 06:14:58 bastafidli Exp $
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; version 2 of the License.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */

21
22 package org.opensubsystems.core.persist.db.connectionpool;
23
24 import java.sql.Connection JavaDoc;
25 import java.sql.SQLException JavaDoc;
26 import java.util.Hashtable JavaDoc;
27 import java.util.Iterator JavaDoc;
28 import java.util.Map JavaDoc;
29 import java.util.logging.Level JavaDoc;
30 import java.util.logging.Logger JavaDoc;
31
32 import org.opensubsystems.core.error.OSSConfigException;
33 import org.opensubsystems.core.error.OSSDatabaseAccessException;
34 import org.opensubsystems.core.error.OSSException;
35 import org.opensubsystems.core.persist.db.DatabaseConnectionFactoryImpl;
36 import org.opensubsystems.core.persist.db.DatabaseTransactionFactoryImpl;
37 import org.opensubsystems.core.util.GlobalConstants;
38 import org.opensubsystems.core.util.Log;
39
40 /**
41  * Base class for implementation of factories for retrieving and returning of
42  * database connections, which are maintained in a pool of always ready connections.
43  *
44  * @version $Id: PooledDatabaseConnectionFactoryImpl.java,v 1.8 2007/01/07 06:14:58 bastafidli Exp $
45  * @author Miro Halas
46  * @code.reviewer Miro Halas
47  * @code.reviewed 1.6 2006/05/21 03:43:47 bastafidli
48  */

49 public abstract class PooledDatabaseConnectionFactoryImpl extends DatabaseConnectionFactoryImpl
50 {
51    /**
52     * Simple structure collecting all information about the connection pool.
53     * Connection pool coresponds to a pool of connections.
54     */

55    class ConnectionPoolDefinition
56    {
57       /**
58        * Name of the connection pool.
59        */

60       protected String JavaDoc m_strConnectionPoolName;
61
62       /**
63        * JDBC driver user by this connection pool.
64        */

65       protected String JavaDoc m_strDriverName;
66
67       /**
68        * URL to connect to the database.
69        */

70       protected String JavaDoc m_strUrl;
71       
72       /**
73        * User name to use to connect to the database.
74        */

75       protected String JavaDoc m_strUser;
76       
77       /**
78        * Password to use to connect to the database.
79        */

80       protected String JavaDoc m_strPassword;
81       
82       /**
83        * The connection pool however it is implemented.
84        */

85       protected Object JavaDoc m_connectionPool;
86
87       /**
88        * Number of requested connections for particular data source.
89        */

90       protected int m_requestedConnectionCount;
91
92       /**
93        * @param connectionPoolName - name of the connection pool
94        * @param driverName - JDBC driver user by this connection pool
95        * @param url - URL to connect to the database
96        * @param user - User name to use to connect to the database
97        * @param password - Password to use to connect to the database
98        * @param connectionPool - connection pool however it is implemented
99        */

100       public ConnectionPoolDefinition(
101          String JavaDoc connectionPoolName,
102          String JavaDoc driverName,
103          String JavaDoc url,
104          String JavaDoc user,
105          String JavaDoc password,
106          Object JavaDoc connectionPool
107       )
108       {
109          super();
110          m_strConnectionPoolName = connectionPoolName;
111          m_strDriverName = driverName;
112          m_strUrl = url;
113          m_strUser = user;
114          m_strPassword = password;
115          m_connectionPool = connectionPool;
116          m_requestedConnectionCount = 0;
117       }
118       
119       /**
120        * @return Object
121        */

122       public Object JavaDoc getConnectionPool()
123       {
124          return m_connectionPool;
125       }
126       
127       /**
128        * @return String
129        */

130       public String JavaDoc getConnectionPoolName()
131       {
132          return m_strConnectionPoolName;
133       }
134       
135       /**
136        * @return String
137        */

138       public String JavaDoc getDriverName()
139       {
140          return m_strDriverName;
141       }
142       
143       /**
144        * @return String
145        */

146       public String JavaDoc getPassword()
147       {
148          return m_strPassword;
149       }
150       
151       /**
152        * @return String
153        */

154       public String JavaDoc getUrl()
155       {
156          return m_strUrl;
157       }
158       
159       /**
160        * @return String
161        */

162       public String JavaDoc getUser()
163       {
164          return m_strUser;
165       }
166       
167       /**
168        * @return int
169        */

170       public int getRequestedConnectionCount()
171       {
172          return m_requestedConnectionCount;
173       }
174
175       /**
176        * Method increments number of requested connections
177        *
178        * @return int
179        */

180       public int connectionRequested()
181       {
182          return m_requestedConnectionCount++;
183       }
184
185       /**
186        * Method decrements number of requested connections
187        *
188        * @return int
189        */

190       public int connectionReturned()
191       {
192          if (GlobalConstants.ERROR_CHECKING)
193          {
194             assert m_requestedConnectionCount > 0
195                    : "Cannot return connection that wasn't requested.";
196          }
197          return m_requestedConnectionCount--;
198       }
199       
200       /**
201        * {@inheritDoc}
202        */

203       public String JavaDoc toString()
204       {
205          StringBuffer JavaDoc dump = new StringBuffer JavaDoc();
206          
207          dump.append("ConnectionPoolDefinition[");
208          dump.append("\n m_strConnectionPoolName = ");
209          if (m_strConnectionPoolName != null)
210          {
211             dump.append(m_strConnectionPoolName);
212          }
213          else
214          {
215             dump.append("null");
216          }
217          dump.append("\n m_strDriverName = ");
218          if (m_strDriverName != null)
219          {
220             dump.append(m_strDriverName);
221          }
222          else
223          {
224             dump.append("null");
225          }
226          dump.append("\n m_strUrl = ");
227          if (m_strUrl != null)
228          {
229             dump.append(m_strUrl);
230          }
231          else
232          {
233             dump.append("null");
234          }
235          dump.append("\n m_strUser = ");
236          if (m_strUser != null)
237          {
238             dump.append(m_strUser);
239          }
240          else
241          {
242             dump.append("null");
243          }
244          dump.append("\n m_strPassword = ");
245          if (m_strUser != null)
246          {
247             dump.append(m_strUser);
248          }
249          else
250          {
251             dump.append("null");
252          }
253          dump.append("\n m_requestedConnectionCount = ");
254          dump.append(m_requestedConnectionCount);
255          dump.append("\n m_connectionPool = ");
256          if (m_connectionPool != null)
257          {
258             dump.append(m_connectionPool.toString());
259          }
260          else
261          {
262             dump.append("null");
263          }
264          dump.append("]");
265          
266          return dump.toString();
267       }
268    }
269
270    // Constants ////////////////////////////////////////////////////////////////
271

272    /**
273     * Name that will be used for default datasource when the connection factory
274     * is started and no default datasource is defined. Make this name somehow
275     * meaningful because for example for J2EE CF this name has to be configured
276     * in external configuration file.
277     */

278    public static final String JavaDoc DEFAULT_DATASOURCE_NAME = "OSSDS";
279
280    // Attributes ///////////////////////////////////////////////////////////////
281

282    /**
283     * Default connection pool used for all connections.
284     */

285    protected ConnectionPoolDefinition m_defaultConnectionPool;
286    
287    /**
288     * Registered connection pools. Key is String, connection pool name
289     * and value is a ConnectionPoolDefinition.
290     */

291    protected Map JavaDoc m_mpConnectionPools;
292
293    /**
294     * Map of not pooled connections which needs to be closed explicitely. This
295     * allows the implementing connection factory also have some connections which
296     * are not pooled and by putting them into this map the connection factory
297     * can make sure that they are closed when the factory is stopped (if they
298     * were not returned earlier, since then they are closed immidiately).
299     * Key is connection and value is the same connection.
300     */

301    protected Map JavaDoc m_mpNotPooledConnections;
302
303    /**
304     * Map used to cross reference connection to their pool so that we can
305     * correctly manage counts of requested connections per pool
306     */

307    protected Map JavaDoc m_mpConnectionPoolCrossRef;
308    
309    // Cached values ////////////////////////////////////////////////////////////
310

311    /**
312     * Logger for this class
313     */

314    private static Logger JavaDoc s_logger = Log.getInstance(PooledDatabaseConnectionFactoryImpl.class);
315
316    // Constructors /////////////////////////////////////////////////////////////
317

318    /**
319     * Default constructor.
320     */

321    public PooledDatabaseConnectionFactoryImpl(
322    )
323    {
324       this(null);
325    }
326
327    /**
328     * Default constructor.
329     *
330     * @param transactionFactory - transaction factory to use for this
331     * connection factory, can be null
332     */

333    public PooledDatabaseConnectionFactoryImpl(
334       DatabaseTransactionFactoryImpl transactionFactory
335    )
336    {
337       super(transactionFactory);
338
339       // Use Hashtable so that it is synchronized
340
m_mpNotPooledConnections = new Hashtable JavaDoc();
341       m_mpConnectionPools = new Hashtable JavaDoc();
342       m_mpConnectionPoolCrossRef = new Hashtable JavaDoc();
343    }
344
345    /**
346     * Constructor with explicitely specified JDBC driver.
347     *
348     * @param strDriver - JDBC driver to connect to the database
349     * @param strURL - URL of database to connect to
350     * @param strUser - user name to connect to the database
351     * @param strPassword - password to the database
352     * @param transactionFactory - transaction factory to use for this
353     * connection factory, can be null
354     * @throws OSSConfigException - problem accessing or locating the config file.
355     * @throws OSSDatabaseAccessException - an error has occured accessing
356     * the database
357     */

358    public PooledDatabaseConnectionFactoryImpl(
359       String JavaDoc strDriver,
360       String JavaDoc strURL,
361       String JavaDoc strUser,
362       String JavaDoc strPassword,
363       DatabaseTransactionFactoryImpl transactionFactory
364    ) throws OSSConfigException,
365             OSSDatabaseAccessException
366    {
367       super(strDriver, strURL, strUser, strPassword, transactionFactory);
368       
369       // Use Hashtable so that it is synchronized
370
m_mpNotPooledConnections = new Hashtable JavaDoc();
371       m_mpConnectionPools = new Hashtable JavaDoc();
372    }
373    
374    // Public methods ///////////////////////////////////////////////////////////
375

376    /**
377     * {@inheritDoc}
378     */

379    public final String JavaDoc getDefaultDataSourceName(
380    )
381    {
382       String JavaDoc strName;
383       
384       if (m_defaultConnectionPool != null)
385       {
386          strName = m_defaultConnectionPool.getConnectionPoolName();
387       }
388       else
389       {
390          strName = "";
391       }
392       
393       return strName;
394    }
395
396    /**
397     * {@inheritDoc}
398     */

399    public final void addDataSource(
400       String JavaDoc strDataSourceName,
401       String JavaDoc strDriverName,
402       String JavaDoc strUrl,
403       String JavaDoc strUser,
404       String JavaDoc strPassword
405    ) throws OSSDatabaseAccessException
406    {
407       if (m_mpConnectionPools.get(strDataSourceName) == null)
408       {
409          // Data source with this name doesn't exists yet
410
Object JavaDoc connectionPool;
411          
412          try
413          {
414             connectionPool = createConnectionPool(strDataSourceName,
415                                                   strDriverName,
416                                                   strUrl,
417                                                   strUser,
418                                                   strPassword);
419          }
420          catch (OSSDatabaseAccessException odaExc)
421          {
422             // Catch and just propagate OSSDatabaseAccessException since we can
423
// use it for detection in case data source is not created yet
424
// and then create one. We do not want to create another wrapper.
425
throw odaExc;
426          }
427          catch (OSSException ossExc)
428          {
429             // This has to be OSSDatabaseAccessException so that we can
430
// detect this situation for example in case the user doesn't exist
431
// and create the user
432
throw new OSSDatabaseAccessException("Cannot create connection pool "
433                                                  + strDataSourceName, ossExc);
434          }
435
436          m_mpConnectionPools.put(strDataSourceName, new ConnectionPoolDefinition(
437                                                          strDataSourceName,
438                                                          strDriverName,
439                                                          strUrl,
440                                                          strUser,
441                                                          strPassword,
442                                                          connectionPool));
443    
444          s_logger.fine("Connection pool " + strDataSourceName + " registered.");
445       }
446       else
447       {
448          s_logger.fine("Connection pool " + strDataSourceName + " already exists.");
449          throw new OSSDatabaseAccessException("Connection pool " + strDataSourceName
450                                               + " already exists.");
451       }
452    }
453    
454    /**
455     * {@inheritDoc}
456     */

457    public final void setDefaultDataSourceName(
458       String JavaDoc strDataSourceName
459    )
460    {
461       ConnectionPoolDefinition definition;
462       
463       // Don't assign it to the member variable so that we don't override
464
// existing connection pool if there is one
465
definition = (ConnectionPoolDefinition)m_mpConnectionPools.get(strDataSourceName);
466       if (definition == null)
467       {
468          throw new IllegalArgumentException JavaDoc("Connection pool with name "
469                                             + strDataSourceName
470                                             + " doesn't exist.");
471       }
472
473       m_defaultConnectionPool = definition;
474       m_strDatabaseDriver = definition.getDriverName();
475       m_strDatabaseURL = definition.getUrl();
476       m_strDatabaseUser = definition.getUser();
477       m_strDatabasePassword = definition.getPassword();
478    }
479
480    /**
481     * {@inheritDoc}
482     */

483    public boolean isDataSourceDefined(
484       String JavaDoc strDataSourceName
485    )
486    {
487       return (m_mpConnectionPools.get(strDataSourceName) != null);
488    }
489    
490    /**
491     * {@inheritDoc}
492     */

493    public final void stop(
494    ) throws OSSException
495    {
496       s_logger.fine("Stopping connection pool.");
497
498       Iterator JavaDoc entries;
499       Map.Entry JavaDoc entry;
500       
501       // First close all non pooled connections
502
for (entries = m_mpNotPooledConnections.entrySet().iterator(); entries.hasNext();)
503       {
504          entry = (Map.Entry JavaDoc)entries.next();
505          try
506          {
507             ((Connection JavaDoc)entry.getValue()).close();
508          }
509          catch (Throwable JavaDoc thr)
510          {
511             // Catch throwable so that we can try to close others even if one fail
512
// Do not throw exception since this usually doesn't mean anything
513
s_logger.log(Level.WARNING, "Cannot close nonpoolable connection",
514                                   thr);
515          }
516          entries.remove();
517          s_logger.fine("Nonpooled connection " + entry.getKey()
518                        + " closed. THIS CONNECTION SHOULD"
519                        + " HAVE BEEN PROBABLY CLOSED EXPLICITELY.");
520       }
521       
522       // Now close all the connections pools
523
for (entries = m_mpConnectionPools.entrySet().iterator(); entries.hasNext();)
524       {
525          entry = (Map.Entry JavaDoc)entries.next();
526          try
527          {
528             closeConnectionPool((ConnectionPoolDefinition)entry.getValue());
529          }
530          catch (Throwable JavaDoc thr)
531          {
532             // Catch throwable so that we can try to close others even if one fail
533
throw new OSSDatabaseAccessException(
534                          "Unexpected exception while closing connection pool"
535                          + entry.getKey(), thr);
536          }
537          entries.remove();
538          s_logger.fine("Connection pool " + entry.getKey()
539                        + " shutdown and unregistered.");
540       }
541       
542       if (GlobalConstants.ERROR_CHECKING)
543       {
544          assert m_mpNotPooledConnections.isEmpty()
545                 : "Not all nonpooled connection were closed.";
546          assert m_mpConnectionPools.isEmpty()
547                 : "Not all connection pools were closed.";
548       }
549       
550       // Reset the default connection pool as well, if the pool is restarted next
551
// time, the default connection pool will have to be recreated
552
m_defaultConnectionPool = null;
553       
554       s_logger.fine("Connection pool is stopped.");
555    }
556
557    /**
558     * {@inheritDoc}
559     */

560    public int getRequestedConnectionCount()
561    {
562       return m_defaultConnectionPool.getRequestedConnectionCount();
563    }
564
565    /**
566     * {@inheritDoc}
567     */

568    public int getRequestedConnectionCount(
569       String JavaDoc strDataSourceName
570    )
571    {
572       ConnectionPoolDefinition definition;
573       int iConnectionCountReturn = 0;
574
575       // Don't assign it to the member variable so that we don't override
576
// existing connection pool if there is one
577
definition = (ConnectionPoolDefinition)m_mpConnectionPools.get(strDataSourceName);
578       if (definition == null)
579       {
580          throw new IllegalArgumentException JavaDoc("Connection pool with name " + strDataSourceName
581                                             + " doesn't exist.");
582       }
583       else
584       {
585          iConnectionCountReturn = definition.getRequestedConnectionCount();
586       }
587
588       return iConnectionCountReturn;
589    }
590
591    /**
592     * {@inheritDoc}
593     */

594    public String JavaDoc debug(
595    )
596    {
597       StringBuffer JavaDoc dump = new StringBuffer JavaDoc();
598       
599       dump.append("PooledDatabaseConnectionFactoryImpl[");
600       if (m_defaultConnectionPool != null)
601       {
602          dump.append("\n m_defaultConnectionPool.getConnectionPoolName() = ");
603          dump.append(m_defaultConnectionPool.getConnectionPoolName());
604       }
605       else
606       {
607          dump.append("\n m_defaultConnectionPool = null");
608       }
609       dump.append("\n m_mpConnectionPools = ");
610       if (m_mpConnectionPools != null)
611       {
612          dump.append(m_mpConnectionPools);
613       }
614       else
615       {
616          dump.append("null");
617       }
618       dump.append("\n m_mpNotPooledConnections = ");
619       if (m_mpNotPooledConnections != null)
620       {
621          dump.append(m_mpNotPooledConnections);
622       }
623       else
624       {
625          dump.append("null");
626       }
627       dump.append("]");
628
629       // TODO: Improve: For now do not report these two and do not report on base class
630
// m_defaultConnectionPool;
631
// m_mpConnectionPoolCrossRef;
632

633       return dump.toString();
634    }
635    
636    // Helper methods ///////////////////////////////////////////////////////////
637

638    /**
639     * {@inheritDoc}
640     */

641    protected Connection JavaDoc requestNonTransactionalConnection(
642       boolean bAutoCommit
643    ) throws OSSDatabaseAccessException
644    {
645       Connection JavaDoc cntDBConnection;
646
647       // If somebody is requesting connection the normal behaviour is that
648
// he will get it. If he doesn't get it, thats an exeption. Therefore
649
// I decide to don't return null since then everybody has to check
650
// for the null value and throw an exception instead
651

652       if (m_defaultConnectionPool == null)
653       {
654          start();
655       }
656
657       // Connection pool contains connection pool
658
if (m_defaultConnectionPool != null)
659       {
660          // Instead of directly getting connection, ask connection pool for one
661
// cntDBConnection = DriverManager.getConnection(s_strDatabaseURL,
662
// s_strDatabaseUser,
663
// s_strDatabasePassword);
664
cntDBConnection = getPooledConnection(m_defaultConnectionPool);
665
666          if (cntDBConnection == null)
667          {
668             throw new OSSDatabaseAccessException("Cannot get database connection" +
669                                                     " for an unknown reason");
670          }
671
672          // Increase total number of requested connections
673
m_iRequestedConnectionCount++;
674
675          // Increase number of connections for particular data source
676
// and associate them together so that when connection is returned
677
// we can decrement count for correct pool
678
m_mpConnectionPoolCrossRef.put(cntDBConnection, m_defaultConnectionPool);
679          m_defaultConnectionPool.connectionRequested();
680
681          try
682          {
683             initializeConnection(cntDBConnection, bAutoCommit);
684          }
685          catch (SQLException JavaDoc sqleExc)
686          {
687             // Do not return the connection here since user MUST call returnConnection
688
// even if exception occurs during requestConnection
689
throw new OSSDatabaseAccessException(
690                          "Cannot initialize database connection", sqleExc);
691          }
692       }
693       else
694       {
695          throw new OSSDatabaseAccessException("Cannot get database connection" +
696                                                  " since no default connection pool is defined.");
697          
698       }
699
700       return cntDBConnection;
701    }
702    
703    /**
704     * {@inheritDoc}
705     */

706    protected final Connection JavaDoc requestNonTransactionalConnection(
707       boolean bAutoCommit,
708       String JavaDoc strUser,
709       String JavaDoc strPassword
710    ) throws OSSDatabaseAccessException
711    {
712       Connection JavaDoc cntDBConnection;
713
714       // If somebody is requesting connection the normal behaviour is that
715
// he will get it. If he doesn't get it, thats an exeption. Therefore
716
// I decide to don't return null since then everybody has to check
717
// for the null value and throw an exception instead
718

719       if ((m_defaultConnectionPool != null)
720          && (m_defaultConnectionPool.getUser().equals(strUser))
721          && (m_defaultConnectionPool.getPassword().equals(strPassword)))
722       {
723          // The user name and password are the same as for regular connection pool
724
// so just use the regular method to get the connection
725
cntDBConnection = requestNonTransactionalConnection(bAutoCommit);
726       }
727       else
728       {
729          // Instead of directly getting connection, ask connection pool for one
730
// cntDBConnection = DriverManager.getConnection(s_strDatabaseURL,
731
// s_strDatabaseUser,
732
// s_strDatabasePassword);
733
cntDBConnection = getPooledConnection(m_defaultConnectionPool,
734                                                strUser, strPassword);
735
736          if (cntDBConnection == null)
737          {
738             throw new OSSDatabaseAccessException("Cannot get database connection" +
739                                                     " for an unknown reason");
740          }
741          // Increase total number of requested connections
742
m_iRequestedConnectionCount++;
743
744          // Increase number of connections for particular data source
745
// and associate them together so that when connection is returned
746
// we can decrement count for correct pool
747
m_mpConnectionPoolCrossRef.put(cntDBConnection, m_defaultConnectionPool);
748          m_defaultConnectionPool.connectionRequested();
749
750          try
751          {
752             initializeConnection(cntDBConnection, bAutoCommit);
753          }
754          catch (SQLException JavaDoc sqleExc)
755          {
756             // Do not return the connection here since user MUST call returnConnection
757
// even if exception occurs during requestConnection
758
throw new OSSDatabaseAccessException(
759                          "Cannot initialize database connection", sqleExc);
760          }
761       }
762
763       return cntDBConnection;
764    }
765
766    /**
767     * {@inheritDoc}
768     */

769    protected final Connection JavaDoc requestNonTransactionalConnection(
770       boolean bAutoCommit,
771       String JavaDoc strDataSourceName
772    ) throws OSSDatabaseAccessException
773    {
774       ConnectionPoolDefinition connectionPool;
775       Connection JavaDoc cntDBConnection;
776
777       // Don't assign it to the member variable so that we don't override
778
// existing connection pool if there is one
779
connectionPool = (ConnectionPoolDefinition)m_mpConnectionPools.get(strDataSourceName);
780       if (connectionPool == null)
781       {
782          throw new IllegalArgumentException JavaDoc("Connection pool with name " + strDataSourceName
783                                             + " doesn't exist.");
784       }
785       else
786       {
787          cntDBConnection = getPooledConnection(connectionPool);
788
789          // Increase total number of requested connections
790
m_iRequestedConnectionCount++;
791
792          // Increase number of connections for particular data source
793
// and associate them together so that when connection is returned
794
// we can decrement count for correct pool
795
m_mpConnectionPoolCrossRef.put(cntDBConnection, connectionPool);
796          connectionPool.connectionRequested();
797
798          try
799          {
800             initializeConnection(cntDBConnection, bAutoCommit);
801          }
802          catch (SQLException JavaDoc sqleExc)
803          {
804             // Do not return the connection here since user MUST call returnConnection
805
// even if exception occurs during requestConnection
806
throw new OSSDatabaseAccessException(
807                          "Cannot initialize database connection", sqleExc);
808          }
809       }
810
811       return cntDBConnection;
812    }
813
814    /**
815     * {@inheritDoc}
816     */

817    protected final Connection JavaDoc requestNonTransactionalConnection(
818       boolean bAutoCommit,
819       String JavaDoc strDataSourceName,
820       String JavaDoc strUser,
821       String JavaDoc strPassword
822    ) throws OSSDatabaseAccessException
823    {
824       ConnectionPoolDefinition connectionPool;
825       Connection JavaDoc cntDBConnection;
826
827       // Don't assign it to the member variable so that we don't override
828
// existing connection pool if there is one
829
connectionPool = (ConnectionPoolDefinition)m_mpConnectionPools.get(strDataSourceName);
830       if (connectionPool == null)
831       {
832          throw new IllegalArgumentException JavaDoc("Connection pool with name " + strDataSourceName
833                                             + " doesn't exist.");
834       }
835       else
836       {
837          cntDBConnection = getPooledConnection(connectionPool, strUser, strPassword);
838
839          // Increase total number of requested connections
840
m_iRequestedConnectionCount++;
841
842          // Increase number of connections for particular data source
843
// and associate them together so that when connection is returned
844
// we can decrement count for correct pool
845
m_mpConnectionPoolCrossRef.put(cntDBConnection, connectionPool);
846          connectionPool.connectionRequested();
847
848          try
849          {
850             initializeConnection(cntDBConnection, bAutoCommit);
851          }
852          catch (SQLException JavaDoc sqleExc)
853          {
854             // Do not return the connection here since user MUST call returnConnection
855
// even if exception occurs during requestConnection
856
throw new OSSDatabaseAccessException(
857                          "Cannot initialize database connection", sqleExc);
858          }
859       }
860
861       return cntDBConnection;
862    }
863
864    /**
865     * {@inheritDoc}
866     */

867    public final void returnNonTransactionalConnection(
868       Connection JavaDoc cntDBConnection
869    )
870    {
871       if (cntDBConnection != null)
872       {
873          if (GlobalConstants.ERROR_CHECKING)
874          {
875             try
876             {
877                if (cntDBConnection.isClosed())
878                {
879                   assert false : "Returning closed connection.";
880                }
881             }
882             catch (SQLException JavaDoc sqleExc)
883             {
884                s_logger.log(Level.WARNING,
885                                    "Cannot check if database connection is closed",
886                                    sqleExc);
887             }
888          }
889
890          /*
891          Disabled, because it is not probably necessary to do this and we let the
892          driver deal with this
893          // Before we close the connection, let's rollback any changes we may have
894          // made that are not commited
895          try
896          {
897             cntDBConnection.rollback();
898          }
899          catch (SQLException sqleExc)
900          {
901             Log.getLogger().log(Level.WARNING,
902                                 "Rollback before closing connection has failed.",
903                                 sqleExc);
904          }
905          */

906
907          // Decrease total number of requested connections
908
if (GlobalConstants.ERROR_CHECKING)
909          {
910             assert m_iRequestedConnectionCount > 0
911                    : "Cannot return connection that wasn't requested.";
912          }
913          
914          m_iRequestedConnectionCount--;
915          // Figure out from what pool was the connection retrieved and
916
// adjust the count
917
ConnectionPoolDefinition connectionPool;
918          
919          connectionPool = (ConnectionPoolDefinition)m_mpConnectionPoolCrossRef.remove(
920                                                        cntDBConnection);
921          if (connectionPool != null)
922          {
923             // Decrease number of connections for particular data source
924
connectionPool.connectionReturned();
925          }
926          
927          // Try to see if this connection is not pooled connection
928
if (m_mpNotPooledConnections.remove(cntDBConnection) != null)
929          {
930             // This connection is not from the pool and needs to be closed explicitely
931
try
932             {
933                cntDBConnection.close();
934             }
935             catch (SQLException JavaDoc sqleExc)
936             {
937                s_logger.log(Level.WARNING, "Closing of connection has failed.",
938                             sqleExc);
939             }
940          }
941          else
942          {
943             returnPooledConnection(cntDBConnection);
944          }
945       }
946    }
947
948    /**
949     * Start the connection factory.
950     *
951     * @throws OSSDatabaseAccessException - an error has occured
952     */

953    protected void start(
954    ) throws OSSDatabaseAccessException
955    {
956       if (m_defaultConnectionPool == null)
957       {
958          // To start the connection factory, we just create the default data source
959
addDataSource(DEFAULT_DATASOURCE_NAME,
960                        getDatabaseDriver(),
961                        getDatabaseURL(),
962                        getDatabaseUser(),
963                        getDatabasePassword());
964          setDefaultDataSourceName(DEFAULT_DATASOURCE_NAME);
965       }
966       
967       s_logger.fine("Connection pool is running...");
968    }
969       
970    /**
971     * Get connection for given connection pool.
972     *
973     * @param connectionpool - connection pool to get connection for
974     * @return Connection - this can be null if connection is not available
975     * @throws OSSDatabaseAccessException - an error getting connection
976     */

977    protected abstract Connection JavaDoc getPooledConnection(
978       ConnectionPoolDefinition connectionpool
979    ) throws OSSDatabaseAccessException;
980    
981    /**
982     * Get connection using the same settings as given connection pool but
983     * get the connection under different name and password.
984     *
985     * @param connectionpool - connection pool defining settings to get connection for
986     * @param strUser - user name to get the connection for
987     * @param strPassword - password to get the connection for
988     * @return Connection - this can be null if connection is not available
989     * @throws OSSDatabaseAccessException - an error getting connection
990     */

991    protected abstract Connection JavaDoc getPooledConnection(
992       ConnectionPoolDefinition connectionpool,
993       String JavaDoc strUser,
994       String JavaDoc strPassword
995    ) throws OSSDatabaseAccessException;
996
997    /**
998     * Return connection which was taken from the pool. Since most pool
999     * implementation will return connection to the pool as soon as it is closed
1000    * the default implementation is provided to just close the connection. If
1001    * the derived class needs to do something specific, it can do so by
1002    * overriding this method.
1003    *
1004    * @param cntDBConnection - connection taked from the pool
1005    */

1006   protected void returnPooledConnection(
1007      Connection JavaDoc cntDBConnection
1008   )
1009   {
1010      try
1011      {
1012         cntDBConnection.close();
1013      }
1014      catch (SQLException JavaDoc sqleExc)
1015      {
1016         // Do not throw exception since this usually doesn't mean anything
1017
s_logger.log(Level.WARNING, "Cannot return connection to pool",
1018                               sqleExc);
1019      }
1020   }
1021
1022   /**
1023    * Create new connection pool with specified parameters.
1024    *
1025    * @param strConnectionPoolName - connection pool name
1026    * @param strDriverName - name of the JDBC driver
1027    * @param strUrl - url by which data source connects to the database
1028    * @param strUser - user name to connects to the database
1029    * @param strPassword - password to connects to the database
1030    * @return Object - connection pool
1031    * @throws OSSException - an error has occured during creation of connection pool
1032    */

1033   protected abstract Object JavaDoc createConnectionPool(
1034      String JavaDoc strConnectionPoolName,
1035      String JavaDoc strDriverName,
1036      String JavaDoc strUrl,
1037      String JavaDoc strUser,
1038      String JavaDoc strPassword
1039   ) throws OSSException;
1040
1041   /**
1042    * Close the specified connection pool and all connections maintained to database
1043    * by this connection pool.
1044    *
1045    * @param connectionpool - connection pool to close.
1046    * @throws OSSException - an error has occured during closing of the connection pool
1047    */

1048   protected abstract void closeConnectionPool(
1049      ConnectionPoolDefinition connectionpool
1050   ) throws OSSException;
1051}
1052
Popular Tags