KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > resource > adapter > jdbc > BaseWrapperManagedConnection


1 /*
2  * JBoss, Home of Professional Open Source
3  * Copyright 2005, JBoss Inc., and individual contributors as indicated
4  * by the @authors tag. See the copyright.txt in the distribution for a
5  * full listing of individual contributors.
6  *
7  * This is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as
9  * published by the Free Software Foundation; either version 2.1 of
10  * the License, or (at your option) any later version.
11  *
12  * This software 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 GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this software; if not, write to the Free
19  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21  */

22 package org.jboss.resource.adapter.jdbc;
23
24 import java.io.PrintWriter JavaDoc;
25 import java.sql.CallableStatement JavaDoc;
26 import java.sql.Connection JavaDoc;
27 import java.sql.PreparedStatement JavaDoc;
28 import java.sql.SQLException JavaDoc;
29 import java.sql.Savepoint JavaDoc;
30 import java.sql.Statement JavaDoc;
31 import java.util.ArrayList JavaDoc;
32 import java.util.Collection JavaDoc;
33 import java.util.HashSet JavaDoc;
34 import java.util.Iterator JavaDoc;
35 import java.util.Properties JavaDoc;
36 import java.util.Set JavaDoc;
37
38 import javax.resource.ResourceException JavaDoc;
39 import javax.resource.spi.ConnectionEvent JavaDoc;
40 import javax.resource.spi.ConnectionEventListener JavaDoc;
41 import javax.resource.spi.ConnectionRequestInfo JavaDoc;
42 import javax.resource.spi.ManagedConnection JavaDoc;
43 import javax.resource.spi.ManagedConnectionMetaData JavaDoc;
44 import javax.resource.spi.ResourceAdapterInternalException JavaDoc;
45 import javax.security.auth.Subject JavaDoc;
46
47 import org.jboss.logging.Logger;
48 import org.jboss.resource.JBossResourceException;
49
50 import EDU.oswego.cs.dl.util.concurrent.SynchronizedBoolean;
51
52 /**
53  * BaseWrapperManagedConnection
54  *
55  * @author <a HREF="mailto:d_jencks@users.sourceforge.net">David Jencks</a>
56  * @author <a HREF="mailto:adrian@jboss.com">Adrian Brock</a>
57  * @author <a HREF="mailto:weston.price@jboss.com>Weston Price</a>
58  * @version $Revision: 54925 $
59  */

60
61 public abstract class BaseWrapperManagedConnection implements ManagedConnection JavaDoc
62 {
63    protected final BaseWrapperManagedConnectionFactory mcf;
64
65    protected final Connection JavaDoc con;
66
67    protected final Properties JavaDoc props;
68
69    private final int transactionIsolation;
70
71    private final boolean readOnly;
72
73    private final Collection JavaDoc cels = new ArrayList JavaDoc();
74
75    private final Set JavaDoc handles = new HashSet JavaDoc();
76
77    private PreparedStatementCache psCache = null;
78
79    protected final Object JavaDoc stateLock = new Object JavaDoc();
80
81    protected boolean inManagedTransaction = false;
82
83    protected SynchronizedBoolean inLocalTransaction = new SynchronizedBoolean(false);
84
85    protected boolean jdbcAutoCommit = true;
86
87    protected boolean underlyingAutoCommit = true;
88
89    protected boolean jdbcReadOnly;
90
91    protected boolean underlyingReadOnly;
92
93    protected int jdbcTransactionIsolation;
94
95    protected boolean destroyed = false;
96
97    public BaseWrapperManagedConnection(final BaseWrapperManagedConnectionFactory mcf, final Connection JavaDoc con,
98          final Properties JavaDoc props, final int transactionIsolation, final int psCacheSize) throws SQLException JavaDoc
99    {
100       this.mcf = mcf;
101       this.con = con;
102       this.props = props;
103
104       if (psCacheSize > 0)
105          psCache = new PreparedStatementCache(psCacheSize);
106
107       if (transactionIsolation == -1)
108          this.transactionIsolation = con.getTransactionIsolation();
109
110       else
111       {
112          this.transactionIsolation = transactionIsolation;
113          con.setTransactionIsolation(transactionIsolation);
114       }
115
116       readOnly = con.isReadOnly();
117
118       if (mcf.getNewConnectionSQL() != null)
119       {
120          Statement JavaDoc s = con.createStatement();
121          try
122          {
123             s.execute(mcf.getNewConnectionSQL());
124          }
125          finally
126          {
127             s.close();
128          }
129       }
130
131       underlyingReadOnly = readOnly;
132       jdbcReadOnly = readOnly;
133       jdbcTransactionIsolation = this.transactionIsolation;
134    }
135
136    public void addConnectionEventListener(ConnectionEventListener JavaDoc cel)
137    {
138       synchronized (cels)
139       {
140          cels.add(cel);
141       }
142    }
143
144    public void removeConnectionEventListener(ConnectionEventListener JavaDoc cel)
145    {
146       synchronized (cels)
147       {
148          cels.remove(cel);
149       }
150    }
151
152    public void associateConnection(Object JavaDoc handle) throws ResourceException JavaDoc
153    {
154       if (!(handle instanceof WrappedConnection))
155          throw new JBossResourceException("Wrong kind of connection handle to associate" + handle);
156       ((WrappedConnection) handle).setManagedConnection(this);
157       synchronized (handles)
158       {
159          handles.add(handle);
160       }
161    }
162
163    public PrintWriter JavaDoc getLogWriter() throws ResourceException JavaDoc
164    {
165       // TODO: implement this javax.resource.spi.ManagedConnection method
166
return null;
167    }
168
169    public ManagedConnectionMetaData JavaDoc getMetaData() throws ResourceException JavaDoc
170    {
171       // TODO: implement this javax.resource.spi.ManagedConnection method
172
return null;
173    }
174
175    public void setLogWriter(PrintWriter JavaDoc param1) throws ResourceException JavaDoc
176    {
177       // TODO: implement this javax.resource.spi.ManagedConnection method
178
}
179
180    public void cleanup() throws ResourceException JavaDoc
181    {
182       synchronized (handles)
183       {
184          for (Iterator JavaDoc i = handles.iterator(); i.hasNext();)
185          {
186             WrappedConnection lc = (WrappedConnection) i.next();
187             lc.setManagedConnection(null);
188          }
189          handles.clear();
190       }
191       //reset all the properties we know about to defaults.
192
synchronized (stateLock)
193       {
194          jdbcAutoCommit = true;
195          jdbcReadOnly = readOnly;
196          if (jdbcTransactionIsolation != transactionIsolation)
197          {
198             try
199             {
200                con.setTransactionIsolation(jdbcTransactionIsolation);
201                jdbcTransactionIsolation = transactionIsolation;
202             }
203             catch (SQLException JavaDoc e)
204             {
205                mcf.log.warn("Error resetting transaction isolation ", e);
206             }
207          }
208       }
209    }
210
211    public Object JavaDoc getConnection(Subject JavaDoc subject, ConnectionRequestInfo JavaDoc cri) throws ResourceException JavaDoc
212    {
213       checkIdentity(subject, cri);
214       WrappedConnection lc = new WrappedConnection(this);
215       synchronized (handles)
216       {
217          handles.add(lc);
218       }
219       return lc;
220    }
221
222    public void destroy() throws ResourceException JavaDoc
223    {
224       synchronized (stateLock)
225       {
226          destroyed = true;
227       }
228
229       cleanup();
230       try
231       {
232          con.close();
233       }
234       catch (SQLException JavaDoc ignored)
235       {
236          getLog().trace("Ignored error during close: ", ignored);
237       }
238    }
239
240    public boolean checkValid()
241    {
242       SQLException JavaDoc e = mcf.isValidConnection(con);
243
244       if (e == null)
245          // It's ok
246
return true;
247       else
248       {
249          getLog().warn("Destroying connection that is not valid, due to the following exception: " + con, e);
250          broadcastConnectionError(e);
251          return false;
252       }
253    }
254
255    public Properties JavaDoc getProperties()
256    {
257       return this.props;
258
259    }
260
261    void closeHandle(WrappedConnection handle)
262    {
263       synchronized (stateLock)
264       {
265          if (destroyed)
266             return;
267       }
268
269       synchronized (handles)
270       {
271          handles.remove(handle);
272       }
273       ConnectionEvent JavaDoc ce = new ConnectionEvent JavaDoc(this, ConnectionEvent.CONNECTION_CLOSED);
274       ce.setConnectionHandle(handle);
275       Collection JavaDoc copy = null;
276       synchronized (cels)
277       {
278          copy = new ArrayList JavaDoc(cels);
279       }
280       for (Iterator JavaDoc i = copy.iterator(); i.hasNext();)
281       {
282          ConnectionEventListener JavaDoc cel = (ConnectionEventListener JavaDoc) i.next();
283          cel.connectionClosed(ce);
284       }
285    }
286
287    Throwable JavaDoc connectionError(Throwable JavaDoc t)
288    {
289       if(t instanceof SQLException JavaDoc)
290       {
291          if(mcf.isStaleConnection((SQLException JavaDoc)t))
292          {
293             t = new StaleConnectionException((SQLException JavaDoc)t);
294          
295          }else
296          {
297             if(mcf.isExceptionFatal((SQLException JavaDoc)t))
298             {
299                broadcastConnectionError(t);
300                
301             }
302          }
303       }
304       else
305       {
306          broadcastConnectionError(t);
307       }
308
309       return t;
310    }
311
312
313    protected void broadcastConnectionError(Throwable JavaDoc e)
314    {
315       synchronized (stateLock)
316       {
317          if (destroyed)
318          {
319             Logger log = getLog();
320             if (log.isTraceEnabled())
321                log.trace("Not broadcasting error, already destroyed " + this, e);
322             return;
323          }
324       }
325
326       Exception JavaDoc ex = null;
327       if (e instanceof Exception JavaDoc)
328          ex = (Exception JavaDoc) e;
329       else
330          ex = new ResourceAdapterInternalException JavaDoc("Unexpected error", e);
331       ConnectionEvent JavaDoc ce = new ConnectionEvent JavaDoc(this, ConnectionEvent.CONNECTION_ERROR_OCCURRED, ex);
332       Collection JavaDoc copy = null;
333       synchronized (cels)
334       {
335          copy = new ArrayList JavaDoc(cels);
336       }
337       for (Iterator JavaDoc i = copy.iterator(); i.hasNext();)
338       {
339          ConnectionEventListener JavaDoc cel = (ConnectionEventListener JavaDoc) i.next();
340          try
341          {
342             cel.connectionErrorOccurred(ce);
343          }
344          catch (Throwable JavaDoc t)
345          {
346             getLog().warn("Error notifying of connection error for listener: " + cel, t);
347          }
348       }
349    }
350
351    Connection JavaDoc getConnection() throws SQLException JavaDoc
352    {
353       if (con == null)
354          throw new SQLException JavaDoc("Connection has been destroyed!!!");
355       return con;
356    }
357
358    PreparedStatement JavaDoc prepareStatement(String JavaDoc sql, int resultSetType, int resultSetConcurrency) throws SQLException JavaDoc
359    {
360       if (psCache != null)
361       {
362          PreparedStatementCache.Key key = new PreparedStatementCache.Key(sql,
363                PreparedStatementCache.Key.PREPARED_STATEMENT, resultSetType, resultSetConcurrency);
364          CachedPreparedStatement cachedps = (CachedPreparedStatement) psCache.get(key);
365          if (cachedps != null)
366          {
367             if (canUse(cachedps))
368                cachedps.inUse();
369             else
370                return doPrepareStatement(sql, resultSetType, resultSetConcurrency);
371          }
372          else
373          {
374             PreparedStatement JavaDoc ps = doPrepareStatement(sql, resultSetType, resultSetConcurrency);
375             cachedps = new CachedPreparedStatement(ps);
376             psCache.insert(key, cachedps);
377          }
378          return cachedps;
379       }
380       else
381          return doPrepareStatement(sql, resultSetType, resultSetConcurrency);
382    }
383
384    PreparedStatement JavaDoc doPrepareStatement(String JavaDoc sql, int resultSetType, int resultSetConcurrency) throws SQLException JavaDoc
385    {
386       return con.prepareStatement(sql, resultSetType, resultSetConcurrency);
387    }
388
389    CallableStatement JavaDoc prepareCall(String JavaDoc sql, int resultSetType, int resultSetConcurrency) throws SQLException JavaDoc
390    {
391       if (psCache != null)
392       {
393          PreparedStatementCache.Key key = new PreparedStatementCache.Key(sql,
394                PreparedStatementCache.Key.CALLABLE_STATEMENT, resultSetType, resultSetConcurrency);
395          CachedCallableStatement cachedps = (CachedCallableStatement) psCache.get(key);
396          if (cachedps != null)
397          {
398             if (canUse(cachedps))
399                cachedps.inUse();
400             else
401                return doPrepareCall(sql, resultSetType, resultSetConcurrency);
402          }
403          else
404          {
405             CallableStatement JavaDoc cs = doPrepareCall(sql, resultSetType, resultSetConcurrency);
406             cachedps = new CachedCallableStatement(cs);
407             psCache.insert(key, cachedps);
408          }
409          return cachedps;
410       }
411       else
412          return doPrepareCall(sql, resultSetType, resultSetConcurrency);
413    }
414
415    CallableStatement JavaDoc doPrepareCall(String JavaDoc sql, int resultSetType, int resultSetConcurrency) throws SQLException JavaDoc
416    {
417       return con.prepareCall(sql, resultSetType, resultSetConcurrency);
418    }
419
420    boolean canUse(CachedPreparedStatement cachedps)
421    {
422       // Nobody is using it so we are ok
423
if (cachedps.isInUse() == false)
424          return true;
425
426       // Cannot reuse prepared statements in auto commit mode
427
// if will close the previous usage of the PS
428
if (underlyingAutoCommit == true)
429          return false;
430
431       // We have been told not to share
432
return mcf.sharePS;
433    }
434
435    protected Logger getLog()
436    {
437       return mcf.log;
438    }
439
440    private void checkIdentity(Subject JavaDoc subject, ConnectionRequestInfo JavaDoc cri) throws ResourceException JavaDoc
441    {
442       Properties JavaDoc newProps = mcf.getConnectionProperties(subject, cri);
443       if (!props.equals(newProps))
444       {
445          throw new JBossResourceException("Wrong credentials passed to getConnection!");
446       } // end of if ()
447
}
448
449    /**
450     * The <code>checkTransaction</code> method makes sure the adapter follows the JCA
451     * autocommit contract, namely all statements executed outside a container managed transaction
452     * or a component managed transaction should be autocommitted. To avoid continually calling
453     * setAutocommit(enable) before and after container managed transactions, we keep track of the state
454     * and check it before each transactional method call.
455     */

456    void checkTransaction() throws SQLException JavaDoc
457    {
458       synchronized (stateLock)
459       {
460          if (inManagedTransaction)
461             return;
462
463          // Check autocommit
464
if (jdbcAutoCommit != underlyingAutoCommit)
465          {
466             con.setAutoCommit(jdbcAutoCommit);
467             underlyingAutoCommit = jdbcAutoCommit;
468          }
469       }
470
471       if (jdbcAutoCommit == false && inLocalTransaction.set(true) == false)
472       {
473          ArrayList JavaDoc copy;
474          synchronized (cels)
475          {
476             copy = new ArrayList JavaDoc(cels);
477          }
478          ConnectionEvent JavaDoc ce = new ConnectionEvent JavaDoc(this, ConnectionEvent.LOCAL_TRANSACTION_STARTED);
479          for (int i = 0; i < copy.size(); ++i)
480          {
481             ConnectionEventListener JavaDoc cel = (ConnectionEventListener JavaDoc) copy.get(i);
482             try
483             {
484                cel.localTransactionStarted(ce);
485             }
486             catch (Throwable JavaDoc t)
487             {
488                getLog().trace("Error notifying of connection committed for listener: " + cel, t);
489             }
490          }
491       }
492
493       checkState();
494    }
495
496    protected void checkState() throws SQLException JavaDoc
497    {
498       synchronized (stateLock)
499       {
500          // Check readonly
501
if (jdbcReadOnly != underlyingReadOnly)
502          {
503             con.setReadOnly(jdbcReadOnly);
504             underlyingReadOnly = jdbcReadOnly;
505          }
506       }
507    }
508
509    boolean isJdbcAutoCommit()
510    {
511       return inManagedTransaction ? false : jdbcAutoCommit;
512    }
513
514    void setJdbcAutoCommit(final boolean jdbcAutoCommit) throws SQLException JavaDoc
515    {
516       synchronized (stateLock)
517       {
518          if (inManagedTransaction)
519             throw new SQLException JavaDoc("You cannot set autocommit during a managed transaction!");
520          this.jdbcAutoCommit = jdbcAutoCommit;
521       }
522
523       if (jdbcAutoCommit && inLocalTransaction.set(false))
524       {
525          ArrayList JavaDoc copy;
526          synchronized (cels)
527          {
528             copy = new ArrayList JavaDoc(cels);
529          }
530          ConnectionEvent JavaDoc ce = new ConnectionEvent JavaDoc(this, ConnectionEvent.LOCAL_TRANSACTION_COMMITTED);
531          for (int i = 0; i < copy.size(); ++i)
532          {
533             ConnectionEventListener JavaDoc cel = (ConnectionEventListener JavaDoc) copy.get(i);
534             try
535             {
536                cel.localTransactionCommitted(ce);
537             }
538             catch (Throwable JavaDoc t)
539             {
540                getLog().trace("Error notifying of connection committed for listener: " + cel, t);
541             }
542          }
543       }
544    }
545
546    boolean isJdbcReadOnly()
547    {
548       return jdbcReadOnly;
549    }
550
551    void setJdbcReadOnly(final boolean readOnly) throws SQLException JavaDoc
552    {
553       synchronized (stateLock)
554       {
555          if (inManagedTransaction)
556             throw new SQLException JavaDoc("You cannot set read only during a managed transaction!");
557          this.jdbcReadOnly = readOnly;
558       }
559    }
560
561    int getJdbcTransactionIsolation()
562    {
563       return jdbcTransactionIsolation;
564    }
565
566    void setJdbcTransactionIsolation(final int isolationLevel) throws SQLException JavaDoc
567    {
568       synchronized (stateLock)
569       {
570          this.jdbcTransactionIsolation = isolationLevel;
571          con.setTransactionIsolation(jdbcTransactionIsolation);
572       }
573    }
574
575    void jdbcCommit() throws SQLException JavaDoc
576    {
577       synchronized (stateLock)
578       {
579          if (inManagedTransaction)
580             throw new SQLException JavaDoc("You cannot commit during a managed transaction!");
581          if (jdbcAutoCommit)
582             throw new SQLException JavaDoc("You cannot commit with autocommit set!");
583       }
584       con.commit();
585
586       if (inLocalTransaction.set(false))
587       {
588          ArrayList JavaDoc copy;
589          synchronized (cels)
590          {
591             copy = new ArrayList JavaDoc(cels);
592          }
593          ConnectionEvent JavaDoc ce = new ConnectionEvent JavaDoc(this, ConnectionEvent.LOCAL_TRANSACTION_COMMITTED);
594          for (int i = 0; i < copy.size(); ++i)
595          {
596             ConnectionEventListener JavaDoc cel = (ConnectionEventListener JavaDoc) copy.get(i);
597             try
598             {
599                cel.localTransactionCommitted(ce);
600             }
601             catch (Throwable JavaDoc t)
602             {
603                getLog().trace("Error notifying of connection committed for listener: " + cel, t);
604             }
605          }
606       }
607    }
608
609    void jdbcRollback() throws SQLException JavaDoc
610    {
611       synchronized (stateLock)
612       {
613          if (inManagedTransaction)
614             throw new SQLException JavaDoc("You cannot rollback during a managed transaction!");
615          if (jdbcAutoCommit)
616             throw new SQLException JavaDoc("You cannot rollback with autocommit set!");
617       }
618       con.rollback();
619
620       if (inLocalTransaction.set(false))
621       {
622          ArrayList JavaDoc copy;
623          synchronized (cels)
624          {
625             copy = new ArrayList JavaDoc(cels);
626          }
627          ConnectionEvent JavaDoc ce = new ConnectionEvent JavaDoc(this, ConnectionEvent.LOCAL_TRANSACTION_ROLLEDBACK);
628          for (int i = 0; i < copy.size(); ++i)
629          {
630             ConnectionEventListener JavaDoc cel = (ConnectionEventListener JavaDoc) copy.get(i);
631             try
632             {
633                cel.localTransactionRolledback(ce);
634             }
635             catch (Throwable JavaDoc t)
636             {
637                getLog().trace("Error notifying of connection rollback for listener: " + cel, t);
638             }
639          }
640       }
641    }
642
643    void jdbcRollback(Savepoint JavaDoc savepoint) throws SQLException JavaDoc
644    {
645       synchronized (stateLock)
646       {
647          if (inManagedTransaction)
648             throw new SQLException JavaDoc("You cannot rollback during a managed transaction!");
649          if (jdbcAutoCommit)
650             throw new SQLException JavaDoc("You cannot rollback with autocommit set!");
651       }
652       con.rollback(savepoint);
653    }
654
655    int getTrackStatements()
656    {
657       return mcf.trackStatements;
658    }
659
660    boolean isTransactionQueryTimeout()
661    {
662       return mcf.isTransactionQueryTimeout;
663    }
664
665    int getQueryTimeout()
666    {
667       return mcf.getQueryTimeout();
668    }
669
670    protected void checkException(SQLException JavaDoc e) throws ResourceException JavaDoc
671    {
672       connectionError(e);
673       throw new JBossResourceException("SQLException", e);
674    }
675 }
676
Popular Tags