KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jahia > services > database > ConnectionDispenser


1 package org.jahia.services.database;
2
3 import java.io.FileInputStream JavaDoc;
4 import java.io.FileNotFoundException JavaDoc;
5 import java.io.IOException JavaDoc;
6 import java.sql.Connection JavaDoc;
7 import java.sql.SQLException JavaDoc;
8 import java.util.Enumeration JavaDoc;
9 import java.util.Properties JavaDoc;
10
11 import javax.naming.Context JavaDoc;
12 import javax.naming.InitialContext JavaDoc;
13 import javax.naming.NamingException JavaDoc;
14 import javax.sql.DataSource JavaDoc;
15 import javax.transaction.HeuristicMixedException JavaDoc;
16 import javax.transaction.HeuristicRollbackException JavaDoc;
17 import javax.transaction.NotSupportedException JavaDoc;
18 import javax.transaction.RollbackException JavaDoc;
19 import javax.transaction.Status JavaDoc;
20 import javax.transaction.SystemException JavaDoc;
21 import javax.transaction.UserTransaction JavaDoc;
22
23 import org.apache.commons.dbcp.BasicDataSource;
24 import org.jahia.exceptions.JahiaInitializationException;
25 import org.jahia.settings.SettingsBean;
26 import org.jahia.utils.BeanTools;
27
28 /**
29  * <p>Title: </p>
30  * <p>Description: </p>
31  * <p>Copyright: Copyright (c) 2002</p>
32  * <p>Company: Jahia Ltd</p>
33  * @author Serge Huber
34  * @version 1.0
35  */

36
37 public class ConnectionDispenser {
38
39     protected static org.apache.log4j.Logger logger =
40         org.apache.log4j.Logger.getLogger(ConnectionDispenser.class);
41
42     private static final String JavaDoc DB_POOL_PROPERTIES_FILE = "dbpool.properties";
43     private static final String JavaDoc DB_EMPTY_POOL = "No available connections in pool";
44
45     private static final String JavaDoc DATASOURCE_NAME = "datasource.name";
46     
47     /* PAP: property keyword for JNDI name of JTA user transaction */
48     private static final String JavaDoc USER_TRANSACTION_NAME = "userTransaction.name";
49
50     private static ThreadLocalConnectionInfo threadLocalConnectionInfo = new
51         ThreadLocalConnectionInfo();
52     private static ThreadLocalConnectionInfo threadLocalTxConnectionInfo = new
53     ThreadLocalConnectionInfo();
54     
55     private static boolean autoCommit = true;
56     private String JavaDoc serviceName;
57     private static BasicDataSource basicDataSource = null;
58     private static DataSource JavaDoc ds = null;
59     protected static int count;
60     
61     /* PAP: user transaction */
62     private static UserTransaction JavaDoc ut = null;
63
64     /*EP specific dev*/
65     private static boolean usingDatasource = false;
66   
67     protected static boolean usingUserTransactions = false;
68     
69     protected static class ThreadLocalConnectionInfo extends ThreadLocal JavaDoc {
70         public Object JavaDoc initialValue () {
71             return null;
72         }
73     }
74
75     private static class ConnectionInfo {
76         private boolean alreadyTerminated = false;
77         private Connection JavaDoc connection = null;
78
79         public ConnectionInfo (Connection JavaDoc connection) {
80             this.connection = new ConnectionWrapper(connection);
81         }
82
83         public Connection JavaDoc getConnection () {
84             return connection;
85         }
86
87         public void setConnection (Connection JavaDoc connection) {
88             this.connection = new ConnectionWrapper(connection);
89         }
90
91         public void removeConnection () {
92             alreadyTerminated = true;
93             try {
94                 if (!usingUserTransactions && !connection.getAutoCommit()){
95                     connection.rollback();
96                 }
97             } catch (SQLException JavaDoc sqle) {
98                 logger.error("Error while rolling back database statements", sqle);
99             } finally {
100                 try {
101                     ((ConnectionWrapper)connection).realClose();
102                 } catch (SQLException JavaDoc sqle) {
103                     logger.error("Error while closing database connection", sqle);
104                 }
105                 count--;
106                 logger.debug("Connections still active :" + count);
107             }
108             connection = null;
109         }
110
111         public boolean isAlreadyTerminated () {
112             return alreadyTerminated;
113         }
114
115         public void setAlreadyTerminated (boolean alreadyTerminated) {
116             this.alreadyTerminated = alreadyTerminated;
117         }
118     }
119
120     public static void init (SettingsBean jSettings)
121         throws
122         JahiaInitializationException {
123         
124     // even if appServer datasource used, a fake basicDataSource is usefull...
125
basicDataSource = new BasicDataSource();
126     
127     /*2004/09/01 AppServer Datasource specific dev*/
128     //creating a context for weblogic pool
129
Context JavaDoc ctx = null;
130     //getting datasource defined AppServer through JNDI call
131
try {
132         String JavaDoc dsName = jSettings.getPropertiesFile().getProperty(DATASOURCE_NAME);
133         if (dsName == null || dsName.length() == 0) {
134             logger.debug("Datasource not defined in properties file...");
135         } else {
136             logger.info("Searching " + dsName + " datasource from app server context...");
137             // creating a default context
138
ctx = new InitialContext JavaDoc();
139             // retrieving datasource into the context
140
ds = (javax.sql.DataSource JavaDoc) ctx.lookup (dsName);
141             usingDatasource = true;
142             
143             // set default value for unused datasource...
144
basicDataSource.setMaxActive(0);
145             basicDataSource.setMaxIdle(0);
146             
147             logger.info("Datasource retrieved from context");
148         }
149     } catch (NamingException JavaDoc ne) {
150         logger.error("Couldn't find datasource into server context", ne);
151     }
152     /*end Datasource specific dev*/
153   
154     /* PAP: Initializing the transaction support - DB or JTA */
155     if (jSettings.isDb_transactions()) {
156         logger.debug(
157             "Transactions are supported by database or driver so activating support...");
158         autoCommit = false;
159         
160       //getting JTA user transaction through JNDI call
161
try {
162           String JavaDoc utName = jSettings.getPropertiesFile().getProperty(USER_TRANSACTION_NAME);
163           if (utName == null || utName.length() == 0) {
164             logger.debug("User transaction not defined in properties file...");
165           } else {
166             logger.info("Searching " + utName + " user transaction from app server context...");
167             // creating a default context
168
ctx = new InitialContext JavaDoc();
169             // retrieving datasource into the context
170
ut = (UserTransaction JavaDoc) ctx.lookup (utName);
171             usingUserTransactions = true;
172             logger.info("User transaction retrieved from context");
173           }
174       } catch (NamingException JavaDoc ne) {
175         logger.error("Couldn't find user transaction into server context", ne);
176       }
177       /*end Datasource specific dev*/
178     } else {
179         autoCommit = true;
180     }
181     
182     if (!usingDatasource) {
183         basicDataSource.setDriverClassName(jSettings.getDb_driver());
184         basicDataSource.setUsername(jSettings.getDb_username());
185         basicDataSource.setPassword(jSettings.getDb_password());
186         basicDataSource.setUrl(jSettings.getDb_url());
187         basicDataSource.setPoolPreparedStatements(jSettings.isDb_poolPreparedStatements());
188         basicDataSource.setMaxOpenPreparedStatements(jSettings.getDb_maxOpenPreparedStatements());
189
190         loadDBPoolConfiguration(jSettings);
191
192         ds = basicDataSource;
193     }
194
195     count = 0;
196     }
197
198     public static void shutdown()
199         throws SQLException JavaDoc {
200         if (basicDataSource != null) {
201             basicDataSource.close();
202         }
203     }
204
205     private static void loadDBPoolConfiguration (SettingsBean jSettings) {
206         try {
207             Properties JavaDoc dbPoolProperties = new Properties JavaDoc();
208             FileInputStream JavaDoc dbPoolPropertiesInput = new FileInputStream JavaDoc(
209                 jSettings.getJahiaEtcDiskPath() + "/config/" +
210                 DB_POOL_PROPERTIES_FILE);
211             dbPoolProperties.load(dbPoolPropertiesInput);
212             Enumeration JavaDoc propertyNameEnum = dbPoolProperties.propertyNames();
213             while (propertyNameEnum.hasMoreElements()) {
214                 String JavaDoc propertyName = (String JavaDoc) propertyNameEnum.nextElement();
215                 String JavaDoc propertyValue = dbPoolProperties.getProperty(propertyName);
216                 if (!"".equals(propertyValue.trim())) {
217                     if (propertyName.startsWith("boolean.")) {
218                         propertyName = propertyName.substring("boolean.".length());
219                         BeanTools.setBooleanProperty(basicDataSource,
220                             propertyName, propertyValue);
221                     } else if (propertyName.startsWith("int.")) {
222                         propertyName = propertyName.substring("int.".length());
223                         BeanTools.setIntProperty(basicDataSource, propertyName,
224                                                  propertyValue);
225                     } else if (propertyName.startsWith("long.")) {
226                         propertyName = propertyName.substring("long.".length());
227                         BeanTools.setLongProperty(basicDataSource, propertyName,
228                                                   propertyValue);
229                     } else if (propertyName.startsWith("String.")) {
230                         propertyName = propertyName.substring("String.".length());
231                         BeanTools.setStringProperty(basicDataSource,
232                             propertyName, propertyValue);
233                     }
234                 }
235             }
236         } catch (FileNotFoundException JavaDoc fnfe) {
237             logger.error("Couldn't find database pool configuration file", fnfe);
238         } catch (IOException JavaDoc ioe) {
239             logger.error("Error while reading database pool configuration file", ioe);
240         }
241     }
242
243     public static javax.sql.DataSource JavaDoc getDataSource() {
244         return ds;
245     }
246
247     public static Connection JavaDoc getConnection () {
248       return getConnection(autoCommit == true ? threadLocalConnectionInfo : threadLocalTxConnectionInfo, autoCommit);
249     }
250
251     public static Connection JavaDoc getTxConnection () {
252         return getConnection(threadLocalTxConnectionInfo, false);
253     }
254     
255     private static Connection JavaDoc getConnection (ThreadLocalConnectionInfo threadLocalConnectionInfo, boolean autoCommit) {
256         Connection JavaDoc newConnection = null;
257         
258         ConnectionInfo connectionInfo = (ConnectionInfo)
259                                         threadLocalConnectionInfo.get();
260                                        
261         if (connectionInfo == null) {
262             try {
263                 logger.debug("Retrieving new connection from pool..."+ basicDataSource.getNumActive() + "/" +basicDataSource.getNumIdle());
264                 /* PAP: Begin transaction with JTA */
265                 if (usingUserTransactions)
266                    ut.begin();
267                 newConnection = ds.getConnection();
268                 /* PAP: Don't use auto commit when JTA was used */
269                 if (!usingUserTransactions)
270                     newConnection.setAutoCommit(autoCommit);
271                 connectionInfo = new ConnectionInfo(newConnection);
272                 // connectionInfo.setConnection(newConnection);
273
connectionInfo.setAlreadyTerminated(false);
274                 count++;
275                 threadLocalConnectionInfo.set(connectionInfo);
276             } catch (SQLException JavaDoc sqle) {
277                 try {
278                   /* PAP: Call JTA rollback if transaction started but no connection returned */
279                   if (usingUserTransactions &&
280                       ut.getStatus() != Status.STATUS_NO_TRANSACTION) {
281                     ut.rollback();
282                   }
283                 }
284                 catch (Exception JavaDoc e) {
285                   logger.error("Error while aborting transaction", e);
286                 }
287                 String JavaDoc msg = "Error while retrieving connection to database";
288                 logger.error(msg + ": ", sqle);
289                 throw new IllegalStateException JavaDoc(msg);
290             /* PAP: Add JTA exceptions */
291             } catch (SystemException JavaDoc syse) {
292                 try {
293                     if (newConnection != null)
294                       newConnection.close();
295                 }
296                 catch (SQLException JavaDoc sqle) {
297                     logger.error("Error while closing database connection", sqle);
298                 }
299                 String JavaDoc msg = "Error while beginning user transaction";
300                 logger.error(msg + ": ", syse);
301                 throw new IllegalStateException JavaDoc(msg);
302             } catch (NotSupportedException JavaDoc nse) {
303                 try {
304                   /* PAP: Call JTA rollback if transaction started but no connection returned */
305                   if (usingUserTransactions &&
306                       ut.getStatus() != Status.STATUS_NO_TRANSACTION) {
307                     ut.rollback();
308                   }
309                 }
310                 catch (Exception JavaDoc e) {
311                   logger.error("Error while aborting transaction", e);
312                 }
313                 try {
314                     if (newConnection != null)
315                       newConnection.close();
316                 }
317                 catch (SQLException JavaDoc sqle) {
318                     logger.error("Error while closing database connection", sqle);
319                 }
320                 String JavaDoc msg = "Error while beginning user transaction";
321                 logger.error(msg + ": ", nse);
322                 throw new IllegalStateException JavaDoc(msg);
323             }
324         } else if (connectionInfo.getConnection() == null) {
325             try {
326                 logger.debug("Connection was closed previously in this thread, retrieving new connection from pool..."+ basicDataSource.getNumActive() + "/" +basicDataSource.getNumIdle());
327                 /* PAP: Rollback JTA transaction if one started, but connection got lost */
328                 if (usingUserTransactions &&
329                   ut.getStatus() != Status.STATUS_NO_TRANSACTION) {
330                   ut.rollback();
331                 }
332                 /* PAP: Begin transaction with JTA */
333                 if (usingUserTransactions)
334                    ut.begin();
335                 newConnection = ds.getConnection();
336                 /* PAP: Don't use auto commit when JTA was used */
337                 if (!usingUserTransactions)
338                     newConnection.setAutoCommit(autoCommit);
339                 connectionInfo.setConnection(newConnection);
340                 connectionInfo.setAlreadyTerminated(false);
341                 threadLocalConnectionInfo.set(connectionInfo);
342                 count++;
343             } catch (SQLException JavaDoc sqle) {
344                 try {
345                   /* PAP: Call JTA rollback if transaction started but no connection returned */
346                   if (usingUserTransactions &&
347                       ut.getStatus() != Status.STATUS_NO_TRANSACTION) {
348                     ut.rollback();
349                   }
350                 }
351                 catch (Exception JavaDoc e) {
352                   logger.error("Error while aborting transaction", e);
353                 }
354                 String JavaDoc msg = "Error while retrieving connection to database";
355                 logger.error(msg + ": ", sqle);
356                 throw new IllegalStateException JavaDoc(msg);
357             /* PAP: Add JTA exceptions */
358             } catch (SystemException JavaDoc syse) {
359                 try {
360                     if (newConnection != null)
361                       newConnection.close();
362                 }
363                 catch (SQLException JavaDoc sqle) {
364                     logger.error("Error while closing database connection", sqle);
365                 }
366                 String JavaDoc msg = "Error while beginning user transaction";
367                 logger.error(msg + ": ", syse);
368                 throw new IllegalStateException JavaDoc(msg);
369             } catch (NotSupportedException JavaDoc nse) {
370                 try {
371                   /* PAP: Call JTA rollback if transaction started but no connection returned */
372                   if (usingUserTransactions &&
373                       ut.getStatus() != Status.STATUS_NO_TRANSACTION) {
374                     ut.rollback();
375                   }
376                 }
377                 catch (Exception JavaDoc e) {
378                   logger.error("Error while aborting transaction", e);
379                 }
380                 try {
381                     if (newConnection != null)
382                       newConnection.close();
383                 }
384                 catch (SQLException JavaDoc sqle) {
385                     logger.error("Error while closing database connection", sqle);
386                 }
387                 String JavaDoc msg = "Error while beginning user transaction";
388                 logger.error(msg + ": ", nse);
389                 throw new IllegalStateException JavaDoc(msg);
390             }
391         }
392         return connectionInfo.getConnection();
393     }
394
395     public static boolean isAutoCommit () {
396         return autoCommit;
397     }
398     
399     public static boolean isUsingUserTransactions () {
400         return usingUserTransactions;
401     }
402
403     public static void setAutoCommit (boolean defaultAutoCommit) {
404         autoCommit = defaultAutoCommit;
405     }
406
407     public static void abortConnection () {
408         if (autoCommit == true) {
409             abortConnection(threadLocalConnectionInfo);
410         }
411         abortConnection(threadLocalTxConnectionInfo);
412     }
413
414     private static void abortConnection (ThreadLocalConnectionInfo threadLocalConnectionInfo) {
415         logger.info("abortConnection : " + threadLocalConnectionInfo.get());
416         ConnectionInfo curConnectionInfo = (ConnectionInfo)
417                                            threadLocalConnectionInfo.get();
418         if (curConnectionInfo == null) {
419             logger.debug("No connection in thread, exiting abort call...");
420             return;
421         }
422         if (curConnectionInfo.isAlreadyTerminated()) {
423             logger.debug(
424                 "Connection was already previously terminated, ignoring !");
425             return;
426         }
427         Connection JavaDoc curConnection = curConnectionInfo.getConnection();
428         try {
429             if (!curConnection.getAutoCommit()) {
430                 logger.debug("Rolling back database transactions...");
431                 
432                 /* PAP: Call JTA rollback or DB connection rollback */
433                 if (usingUserTransactions)
434                     ut.rollback();
435                 else
436                     curConnection.rollback();
437             }
438         } catch (SQLException JavaDoc sqle) {
439             logger.error("Error while rollbacking database transaction", sqle);
440         /* PAP: Add JTA exceptions */
441         } catch (SystemException JavaDoc syse) {
442             logger.error("Error while rollbacking JTA transaction", syse);
443         } finally {
444             curConnectionInfo.removeConnection();
445         }
446     }
447
448     public static void terminateConnection () {
449         if (autoCommit == true) {
450             terminateConnection(threadLocalConnectionInfo);
451         }
452         terminateConnection(threadLocalTxConnectionInfo);
453     }
454
455     private static void terminateConnection (ThreadLocalConnectionInfo threadLocalConnectionInfo) {
456         ConnectionInfo curConnectionInfo = (ConnectionInfo)
457                                            threadLocalConnectionInfo.get();
458         if (curConnectionInfo == null) {
459             logger.debug("No connection in thread, exiting terminate call...");
460             return;
461         }
462         if (curConnectionInfo.isAlreadyTerminated()) {
463             logger.debug(
464                 "Connection was already previously terminated, ignoring !");
465             return;
466         }
467         
468         Connection JavaDoc curConnection = curConnectionInfo.getConnection();
469         try {
470             if (!curConnection.getAutoCommit()) {
471                 logger.debug("Commiting database transactions...");
472                 
473                 /* PAP: Call JTA commit or DB connection commit */
474                 if (usingUserTransactions &&
475                     ut.getStatus() != Status.STATUS_NO_TRANSACTION) {
476                       
477                     ut.commit();
478                 }
479                 else
480                     curConnection.commit();
481             }
482         } catch (SQLException JavaDoc sqle) {
483             logger.error("Error while committing database transaction", sqle);
484         /* PAP: Add JTA exceptions */
485         } catch (SystemException JavaDoc syse) {
486             logger.error("Error while committing JTA transaction", syse);
487         } catch (HeuristicRollbackException JavaDoc hre) {
488             logger.error("Heuristic Rollback Error while committing JTA transaction", hre);
489         } catch (RollbackException JavaDoc re) {
490             logger.error("Error while committing JTA transaction", re);
491         } catch (HeuristicMixedException JavaDoc hme) {
492             logger.error("Heuristic Mixed Error while committing JTA transaction", hme);
493         } finally {
494             curConnectionInfo.removeConnection();
495         }
496     }
497
498     public static int getNbActive () {
499         return basicDataSource.getNumActive();
500     }
501
502     public static int getMaxActive () {
503         return basicDataSource.getMaxActive();
504         // return basicDataSource.getDefaultMaxActive();
505
}
506
507     public static int getNbIdle () {
508         return basicDataSource.getNumIdle();
509     }
510
511     public static int getMaxIdle () {
512         return basicDataSource.getMaxIdle();
513     }
514 }
Popular Tags