KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > sql > ManagedConnectionImpl


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Scott Ferguson
28  */

29
30 package com.caucho.sql;
31
32 import com.caucho.log.Log;
33 import com.caucho.sql.spy.SpyConnection;
34 import com.caucho.sql.spy.SpyXAResource;
35 import com.caucho.util.Alarm;
36 import com.caucho.util.L10N;
37 import com.caucho.util.LruCache;
38
39 import javax.resource.NotSupportedException JavaDoc;
40 import javax.resource.ResourceException JavaDoc;
41 import javax.resource.spi.ConnectionEvent JavaDoc;
42 import javax.resource.spi.ConnectionEventListener JavaDoc;
43 import javax.resource.spi.ConnectionRequestInfo JavaDoc;
44 import javax.resource.spi.LocalTransaction JavaDoc;
45 import javax.resource.spi.ManagedConnection JavaDoc;
46 import javax.resource.spi.ManagedConnectionMetaData JavaDoc;
47 import javax.security.auth.Subject JavaDoc;
48 import javax.sql.PooledConnection JavaDoc;
49 import javax.sql.XAConnection JavaDoc;
50 import javax.transaction.xa.XAResource JavaDoc;
51 import java.io.PrintWriter JavaDoc;
52 import java.sql.Connection JavaDoc;
53 import java.sql.PreparedStatement JavaDoc;
54 import java.sql.ResultSet JavaDoc;
55 import java.sql.SQLException JavaDoc;
56 import java.sql.Statement JavaDoc;
57 import java.util.Iterator JavaDoc;
58 import java.util.Map JavaDoc;
59 import java.util.logging.Level JavaDoc;
60 import java.util.logging.Logger JavaDoc;
61
62 /**
63  * Represents a single pooled connection. For the most part, it just
64  * passes the requests to the underlying JDBC connection.
65  *
66  * <p>Closing the connection will return the real connection to the pool
67  * and close any statements.
68  */

69 public class ManagedConnectionImpl
70   implements ManagedConnection JavaDoc, javax.sql.ConnectionEventListener JavaDoc {
71   protected static final Logger JavaDoc log = Log.open(ManagedConnectionImpl.class);
72   protected static L10N L = new L10N(ManagedConnectionImpl.class);
73
74   // Identifier for spy, etc.
75
private int _id;
76
77   private ManagedFactoryImpl _factory;
78   private DBPoolImpl _dbPool;
79   
80   private DriverConfig _driver;
81   private ConnectionConfig _connConfig;
82
83   private Credential _credentials;
84
85   private PooledConnection JavaDoc _pooledConnection;
86   private Connection _driverConnection;
87
88   private XAResource _xaResource;
89   private LocalTransaction JavaDoc _localTransaction;
90
91   private ConnectionEventListener JavaDoc _listener;
92   private ConnectionEvent JavaDoc _connClosedEvent;
93
94   private ResourceException JavaDoc _connException;
95
96   private long _lastEventTime;
97
98   // Cached prepared statements.
99
private LruCache<PreparedStatementKey,PreparedStatementCacheItem>
100     _preparedStatementCache;
101
102   // Static prepared statement key.
103
private PreparedStatementKey _key;
104
105   // Current value for isolation
106
private int _isolation = -1;
107
108   // Value for getAutoCommit
109
private boolean _autoCommit = true;
110   // old value for getReadOnly
111
private boolean _readOnly = false;
112   // old value for getCatalog
113
private String JavaDoc _catalog = null;
114   // old value for isolation
115
private int _oldIsolation = -1;
116   // old value for getTypeMap
117
private Map JavaDoc _typeMap;
118
119   ManagedConnectionImpl(ManagedFactoryImpl factory,
120             DriverConfig driver,
121             ConnectionConfig connConfig,
122             Credential credentials)
123     throws SQLException JavaDoc
124   {
125     _factory = factory;
126     _dbPool = factory.getDBPool();
127     _id = _dbPool.newSpyId();
128       
129     _driver = driver;
130     _connConfig = connConfig;
131     _credentials = credentials;
132
133     _connClosedEvent = new ConnectionEvent JavaDoc(this,
134                        ConnectionEvent.CONNECTION_CLOSED);
135
136     initDriverConnection();
137
138     _lastEventTime = Alarm.getCurrentTime();
139
140     int preparedStatementCacheSize = _dbPool.getPreparedStatementCacheSize();
141
142     if (preparedStatementCacheSize > 0) {
143       _preparedStatementCache = new LruCache<PreparedStatementKey,PreparedStatementCacheItem>(preparedStatementCacheSize);
144       _key = new PreparedStatementKey();
145     }
146   }
147
148   /**
149    * Returns the db pool.
150    */

151   DBPoolImpl getDBPool()
152   {
153     return _dbPool;
154   }
155
156   /**
157    * Returns the credentials.
158    */

159   Credential getCredentials()
160   {
161     return _credentials;
162   }
163
164   /**
165    * Returns true if statements should be wrapped.
166    */

167   boolean isWrapStatements()
168   {
169     return _dbPool.isWrapStatements();
170   }
171
172   /**
173    * Returns the underlying connection.
174    */

175   public Object JavaDoc getConnection(Subject JavaDoc subject,
176                   ConnectionRequestInfo JavaDoc info)
177     throws ResourceException JavaDoc
178   {
179     if (_connException != null)
180       throw _connException;
181
182     ping();
183     _lastEventTime = Alarm.getCurrentTime();
184
185     return new UserConnection(this);
186   }
187
188   /**
189    * Associates the associate connection.
190    */

191   public void associateConnection(Object JavaDoc connection)
192     throws ResourceException JavaDoc
193   {
194     _lastEventTime = Alarm.getCurrentTime();
195
196     UserConnection uConn = (UserConnection) connection;
197
198     uConn.associate(this);
199   }
200
201   /**
202    * Adds a connection event listener.
203    */

204   public void addConnectionEventListener(ConnectionEventListener JavaDoc listener)
205   {
206     if (_listener != null && _listener != listener)
207       throw new IllegalStateException JavaDoc();
208
209     _listener = listener;
210   }
211
212   /**
213    * Removes a connection event listener.
214    */

215   public void removeConnectionEventListener(ConnectionEventListener JavaDoc listener)
216   {
217     if (_listener == listener)
218       _listener = null;
219   }
220
221   /**
222    * Returns the driver connection.
223    */

224   private void initDriverConnection()
225     throws SQLException JavaDoc
226   {
227     if (_driverConnection != null)
228       throw new IllegalStateException JavaDoc();
229
230     String JavaDoc user = _driver.getUser();
231     String JavaDoc password = _driver.getPassword();;
232
233     if (_credentials != null) {
234       user = _credentials.getUserName();
235       password = _credentials.getPassword();
236     }
237
238     _pooledConnection = _driver.createPooledConnection(user, password);
239
240     if (_pooledConnection != null) {
241       _pooledConnection.addConnectionEventListener(this);
242
243       _driverConnection = _pooledConnection.getConnection();
244     }
245
246     if (_driverConnection == null)
247       _driverConnection = _driver.createDriverConnection(user, password);
248
249     if (_driverConnection == null)
250       throw new SQLException JavaDoc(L.l("Failed to create driver connection."));
251
252     DBPoolImpl dbPool = getDBPool();
253
254     long transactionTimeout = dbPool.getTransactionTimeout();
255     if (dbPool.isXA() && ! _connConfig.isReadOnly()) {
256       if (_pooledConnection instanceof XAConnection JavaDoc) {
257     try {
258       _xaResource = ((XAConnection JavaDoc) _pooledConnection).getXAResource();
259     } catch (SQLException JavaDoc e) {
260       log.log(Level.FINE, e.toString(), e);
261     }
262       }
263
264       if (_xaResource != null && dbPool.isXAForbidSameRM())
265     _xaResource = new DisjointXAResource(_xaResource);
266       
267       if (transactionTimeout > 0 && _xaResource != null) {
268     try {
269       _xaResource.setTransactionTimeout((int) (transactionTimeout / 1000));
270     } catch (Throwable JavaDoc e) {
271       log.log(Level.FINER, e.toString(), e);
272     }
273       }
274
275       boolean allowLocalTransaction = true;
276       String JavaDoc className = "";
277
278       if (_pooledConnection != null)
279     className = _pooledConnection.getClass().getName();
280       
281       if (! (_pooledConnection instanceof XAConnection JavaDoc)) {
282       }
283       else if (className.startsWith("oracle")) {
284     // Oracle does not allow local transactions
285
allowLocalTransaction = false;
286       }
287       else if (className.equals("com.mysql.jdbc.jdbc2.optional.MysqlXAConnection")) {
288     allowLocalTransaction = false;
289       }
290
291       if (allowLocalTransaction)
292     _localTransaction = new LocalTransactionImpl();
293     }
294
295     if (dbPool.isSpy()) {
296       _driverConnection = new SpyConnection(_driverConnection, _id);
297
298       if (_xaResource != null)
299     _xaResource = new SpyXAResource(_id, _xaResource);
300     }
301
302     int isolation = _connConfig.getTransactionIsolation();
303     if (isolation >= 0)
304       _driverConnection.setTransactionIsolation(isolation);
305
306     if (_connConfig.isReadOnly())
307       _driverConnection.setReadOnly(true);
308
309     if (_connConfig.getCatalog() != null)
310       _driverConnection.setCatalog(_connConfig.getCatalog());
311   }
312
313   /**
314    * Returns the driver connection.
315    */

316   Connection getDriverConnection()
317   {
318     return _driverConnection;
319   }
320
321   /**
322    * Returns the XA resource for the connection.
323    */

324   public XAResource getXAResource()
325     throws ResourceException JavaDoc
326   {
327     if (_xaResource != null)
328       return _xaResource;
329
330     throw new NotSupportedException JavaDoc();
331   }
332
333   /**
334    * Returns the XA resource for the connection.
335    */

336   public LocalTransaction JavaDoc getLocalTransaction()
337     throws ResourceException JavaDoc
338   {
339     return _localTransaction;
340   }
341
342   /**
343    * Returns the meta data.
344    */

345   public ManagedConnectionMetaData JavaDoc getMetaData()
346     throws ResourceException JavaDoc
347   {
348     throw new NotSupportedException JavaDoc();
349   }
350
351   /**
352    * Sets the log writer.
353    */

354   public void setLogWriter(PrintWriter JavaDoc out)
355     throws ResourceException JavaDoc
356   {
357   }
358
359   /**
360    * Gets the log writer.
361    */

362   public PrintWriter JavaDoc getLogWriter()
363     throws ResourceException JavaDoc
364   {
365     return null;
366   }
367
368   /**
369    * Sets the isolation.
370    */

371   public void setIsolation(int isolation)
372     throws SQLException JavaDoc
373   {
374   }
375
376   /**
377    * Returns a new or cached prepared statement.
378    */

379   PreparedStatement JavaDoc prepareStatement(UserConnection uConn,
380                      String JavaDoc sql,
381                      int resultType)
382     throws SQLException JavaDoc
383   {
384     Connection conn = getDriverConnection();
385
386     if (conn == null)
387       throw new IllegalStateException JavaDoc(L.l("can't prepare statement from closed connection"));
388
389     if (resultType > 0)
390       return conn.prepareStatement(sql, resultType);
391     else
392       return conn.prepareStatement(sql);
393   }
394
395   /**
396    * Returns a new or cached prepared statement.
397    */

398   PreparedStatement JavaDoc prepareStatement(UserConnection uConn, String JavaDoc sql)
399     throws SQLException JavaDoc
400   {
401     PreparedStatementKey key = _key;
402
403     Connection conn = getDriverConnection();
404
405     if (conn == null)
406       throw new IllegalStateException JavaDoc(L.l("can't prepare statement from closed connection"));
407
408     if (key == null) {
409       return conn.prepareStatement(sql);
410     }
411
412     boolean hasItem = false;
413
414     synchronized (key) {
415       key.init(sql);
416
417       PreparedStatementCacheItem item = _preparedStatementCache.get(key);
418
419       if (item != null) {
420     UserPreparedStatement upStmt = item.toActive(uConn);
421
422     if (upStmt != null)
423       return upStmt;
424
425     hasItem = ! item.isRemoved();
426       }
427     }
428
429     PreparedStatement JavaDoc pStmt;
430     pStmt = conn.prepareStatement(sql);
431
432     if (hasItem)
433       return pStmt;
434
435     key = new PreparedStatementKey(sql);
436
437     PreparedStatementCacheItem item;
438     item = new PreparedStatementCacheItem(key, pStmt, this);
439
440     UserPreparedStatement upStmt = item.toActive(uConn);
441
442     if (upStmt == null)
443       throw new IllegalStateException JavaDoc("preparedStatement can't activate");
444
445     _preparedStatementCache.put(key, item);
446
447     return upStmt;
448   }
449
450   /**
451    * Removes a cached item.
452    */

453   void remove(PreparedStatementKey key)
454   {
455     _preparedStatementCache.remove(key);
456   }
457
458   public void connectionClosed(javax.sql.ConnectionEvent JavaDoc event)
459   {
460     sendFatalEvent(new SQLException JavaDoc(L.l("unexpected close event from pool")));
461     closeEvent(null);
462   }
463
464   public void connectionErrorOccurred(javax.sql.ConnectionEvent JavaDoc event)
465   {
466     sendFatalEvent(event.getSQLException());
467   }
468
469   /**
470    * Sends the close event.
471    */

472   public void closeEvent(UserConnection userConn)
473   {
474     if (_listener != null) {
475       if (_connException != null) {
476     sendFatalEvent(_connException);
477       }
478
479       ConnectionEvent JavaDoc evt;
480       synchronized (this) {
481     evt = _connClosedEvent;
482     _connClosedEvent = null;
483       }
484
485       if (evt == null)
486     evt = new ConnectionEvent JavaDoc(this, ConnectionEvent.CONNECTION_CLOSED);
487
488       evt.setConnectionHandle(userConn);
489
490       _listener.connectionClosed(evt);
491
492       evt.setConnectionHandle(null);
493
494       _connClosedEvent = evt;
495
496       _lastEventTime = Alarm.getCurrentTime();
497     }
498   }
499
500   /**
501    * Sends the fatal event.
502    */

503   public void fatalEvent()
504   {
505     fatalEvent(new ResourceException JavaDoc("fatal event"));
506   }
507
508   /**
509    * Sends the fatal event.
510    */

511   public void fatalEvent(Exception JavaDoc e)
512   {
513     if (_pooledConnection != null) {
514     }
515     else if (e instanceof ResourceException JavaDoc)
516       _connException = (ResourceException JavaDoc) e;
517     else
518       _connException = new ResourceException JavaDoc(e);
519   }
520
521   /**
522    * Sends the fatal event.
523    */

524   public void sendFatalEvent(Exception JavaDoc e)
525   {
526     if (_listener != null) {
527       ConnectionEvent JavaDoc event;
528
529       event = new ConnectionEvent JavaDoc(this,
530                   ConnectionEvent.CONNECTION_ERROR_OCCURRED,
531                   e);
532
533       _listener.connectionErrorOccurred(event);
534     }
535   }
536
537   /**
538    * Sets the auto-commit.
539    */

540   public void setAutoCommit(boolean autoCommit)
541     throws SQLException JavaDoc
542   {
543     try {
544       _autoCommit = autoCommit;
545       _driverConnection.setAutoCommit(autoCommit);
546     } catch (SQLException JavaDoc e) {
547       fatalEvent();
548       throw e;
549     }
550   }
551
552   /**
553    * Sets the read only attribute.
554    */

555   public void setReadOnly(boolean readOnly)
556     throws SQLException JavaDoc
557   {
558     try {
559       _readOnly = readOnly;
560       _driverConnection.setReadOnly(readOnly);
561     } catch (SQLException JavaDoc e) {
562       fatalEvent();
563       throw e;
564     }
565   }
566
567   /**
568    * Sets the JDBC catalog.
569    */

570   public void setCatalog(String JavaDoc catalog)
571     throws SQLException JavaDoc
572   {
573     try {
574       if (_catalog == null)
575         _catalog = _driverConnection.getCatalog();
576
577       _driverConnection.setCatalog(catalog);
578     } catch (SQLException JavaDoc e) {
579       fatalEvent();
580       throw e;
581     }
582   }
583
584   /**
585    * Sets the connection's type map.
586    */

587   public void setTypeMap(Map JavaDoc map)
588     throws SQLException JavaDoc
589   {
590     try {
591       if (_typeMap == null)
592         _typeMap = _driverConnection.getTypeMap();
593
594       _driverConnection.setTypeMap(map);
595     } catch (SQLException JavaDoc e) {
596       throw e;
597     }
598   }
599
600
601   /**
602    * Sets the connection's isolation.
603    */

604   public void setTransactionIsolation(int isolation)
605     throws SQLException JavaDoc
606   {
607     try {
608       _oldIsolation = _driverConnection.getTransactionIsolation();
609       _isolation = isolation;
610
611       _driverConnection.setTransactionIsolation(isolation);
612     } catch (SQLException JavaDoc e) {
613       throw e;
614     }
615   }
616
617   /**
618    * Cleans up the instance.
619    */

620   public void cleanup()
621     throws ResourceException JavaDoc
622   {
623     Connection conn = _driverConnection;
624
625     if (conn == null)
626       return;
627
628     try {
629       /*
630       // If there's a pooled connection, it can cleanup itself
631       if (_pooledConnection != null) {
632     _autoCommit = true;
633     _driverConnection = _pooledConnection.getConnection();
634     _isolation = _oldIsolation = -1;
635     return;
636       }
637       */

638
639       if (_readOnly)
640     conn.setReadOnly(false);
641       _readOnly = false;
642
643       if (_catalog != null && ! _catalog.equals(""))
644     conn.setCatalog(_catalog);
645       _catalog = null;
646
647       if (_typeMap != null)
648     conn.setTypeMap(_typeMap);
649       _typeMap = null;
650
651       // Oracle requires a rollback after a reset of
652
// the transaction isolation, since setting the isolation
653
// starts a new transaction
654
boolean needsRollback = ! _autoCommit;
655       if (_isolation != _oldIsolation) {
656     needsRollback = true;
657     conn.setTransactionIsolation(_oldIsolation);
658       }
659       _isolation = _oldIsolation;
660
661       if (needsRollback)
662     conn.rollback();
663       
664       if (! _autoCommit) {
665     conn.setAutoCommit(true);
666       }
667       _autoCommit = true;
668
669       conn.clearWarnings();
670     } catch (SQLException JavaDoc e) {
671       throw new ResourceException JavaDoc(e);
672     }
673   }
674
675   /**
676    * Returns true if the connection is valid.
677    */

678   boolean isValid()
679   {
680     try {
681       ping();
682
683       return true;
684     } catch (Throwable JavaDoc e) {
685       log.log(Level.FINE, e.toString(), e);
686
687       return false;
688     }
689   }
690
691   /**
692    * Checks the validity with ping.
693    */

694   private void ping()
695     throws ResourceException JavaDoc
696   {
697     DBPoolImpl dbPool = _factory.getDBPool();
698
699     long now = Alarm.getCurrentTime();
700
701     if (now < _lastEventTime + 1000)
702       return;
703
704     if (! dbPool.isPing())
705       return;
706
707     long pingInterval = dbPool.getPingInterval();
708     if (pingInterval > 0 && now < _lastEventTime + pingInterval)
709       return;
710
711     String JavaDoc pingQuery = dbPool.getPingQuery();
712
713     if (pingQuery == null)
714       return;
715
716     if (_driverConnection == null)
717       return;
718
719     try {
720       Statement JavaDoc stmt = _driverConnection.createStatement();
721
722       try {
723     ResultSet JavaDoc rs = stmt.executeQuery(pingQuery);
724     rs.close();
725       } finally {
726     stmt.close();
727       }
728     } catch (SQLException JavaDoc e) {
729       throw new ResourceException JavaDoc(e);
730     }
731   }
732
733   /**
734    * Destroys the physical connection.
735    */

736   public void destroy()
737     throws ResourceException JavaDoc
738   {
739     log.finer("destroy " + this);
740
741     PooledConnection JavaDoc poolConn = _pooledConnection;
742     _pooledConnection = null;
743
744     Connection driverConn = _driverConnection;
745     _driverConnection = null;
746
747     if (_preparedStatementCache != null) {
748       Iterator JavaDoc<PreparedStatementCacheItem> iter;
749
750       iter = _preparedStatementCache.values();
751
752       while (iter.hasNext()) {
753     PreparedStatementCacheItem item = iter.next();
754
755     item.destroy();
756       }
757     }
758
759     try {
760       if (poolConn != null) {
761     poolConn.close();
762     driverConn = null;
763       }
764     } catch (SQLException JavaDoc e) {
765       throw new ResourceException JavaDoc(e);
766     }
767
768     try {
769       if (driverConn != null)
770     driverConn.close();
771     } catch (SQLException JavaDoc e) {
772       log.log(Level.WARNING, e.toString(), e);
773     }
774   }
775
776   class LocalTransactionImpl implements LocalTransaction JavaDoc {
777     private boolean _oldAutoCommit;
778
779     public void begin()
780       throws ResourceException JavaDoc
781     {
782       try {
783     _oldAutoCommit = _autoCommit;
784
785     setAutoCommit(false);
786       } catch (SQLException JavaDoc e) {
787     throw new ResourceException JavaDoc(e) ;
788       }
789     }
790
791     public void commit()
792       throws ResourceException JavaDoc
793     {
794       Connection conn = _driverConnection;
795
796       if (conn == null)
797     throw new ResourceException JavaDoc(L.l("connection is closed"));
798
799       try {
800     conn.commit();
801       } catch (SQLException JavaDoc e) {
802     throw new ResourceException JavaDoc(e) ;
803       }
804
805       try {
806     setAutoCommit(_oldAutoCommit);
807       } catch (SQLException JavaDoc e) {
808     throw new ResourceException JavaDoc(e) ;
809       }
810     }
811
812     public void rollback()
813       throws ResourceException JavaDoc
814     {
815       Connection conn = _driverConnection;
816
817       if (conn == null)
818     throw new ResourceException JavaDoc(L.l("connection is closed"));
819
820       try {
821     conn.rollback();
822       } catch (SQLException JavaDoc e) {
823     throw new ResourceException JavaDoc(e) ;
824       }
825
826       try {
827     setAutoCommit(_oldAutoCommit);
828       } catch (SQLException JavaDoc e) {
829     throw new ResourceException JavaDoc(e) ;
830       }
831     }
832   }
833 }
834
Popular Tags