Source Code Cross Referenced for JManagedConnection.java in  » J2EE » ow2-easybeans » org » ow2 » easybeans » component » jdbcpool » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » J2EE » ow2 easybeans » org.ow2.easybeans.component.jdbcpool 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /**
002:         * EasyBeans
003:         * Copyright (C) 2006 Bull S.A.S.
004:         * Contact: easybeans@ow2.org
005:         *
006:         * This library is free software; you can redistribute it and/or
007:         * modify it under the terms of the GNU Lesser General Public
008:         * License as published by the Free Software Foundation; either
009:         * version 2.1 of the License, or any later version.
010:         *
011:         * This library is distributed in the hope that it will be useful,
012:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
013:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014:         * Lesser General Public License for more details.
015:         *
016:         * You should have received a copy of the GNU Lesser General Public
017:         * License along with this library; if not, write to the Free Software
018:         * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
019:         * USA
020:         *
021:         * --------------------------------------------------------------------------
022:         * $Id: JManagedConnection.java 1970 2007-10-16 11:49:25Z benoitf $
023:         * --------------------------------------------------------------------------
024:         */package org.ow2.easybeans.component.jdbcpool;
025:
026:        import java.sql.Connection;
027:        import java.sql.PreparedStatement;
028:        import java.sql.ResultSet;
029:        import java.sql.SQLException;
030:        import java.util.Collections;
031:        import java.util.HashMap;
032:        import java.util.Iterator;
033:        import java.util.Map;
034:        import java.util.Vector;
035:
036:        import javax.sql.ConnectionEvent;
037:        import javax.sql.ConnectionEventListener;
038:        import javax.sql.XAConnection;
039:        import javax.transaction.Synchronization;
040:        import javax.transaction.Transaction;
041:        import javax.transaction.xa.XAException;
042:        import javax.transaction.xa.XAResource;
043:        import javax.transaction.xa.Xid;
044:
045:        import org.ow2.util.log.Log;
046:        import org.ow2.util.log.LogFactory;
047:
048:        /**
049:         * This class represents the connection managed by the pool. This connection is
050:         * a managed connection and is notified of the transaction events.
051:         * @author Philippe Durieux
052:         * @author Florent Benoit
053:         */
054:        public class JManagedConnection implements  Comparable, XAConnection,
055:                XAResource, Synchronization {
056:
057:            /**
058:             * Logger.
059:             */
060:            private static Log logger = LogFactory
061:                    .getLog(JManagedConnection.class);
062:
063:            /**
064:             * Connection to the database.
065:             */
066:            private Connection physicalConnection = null;
067:
068:            /**
069:             * Connection returned to the user.
070:             */
071:            private Connection implConn = null;
072:
073:            /**
074:             * Maximum of prepared statements.
075:             */
076:            private int pstmtmax = 0;
077:
078:            /**
079:             * Current number of opened prepared statements.
080:             */
081:            private int psOpenNb = 0;
082:
083:            /**
084:             * Event listeners (of PooledConnection).
085:             */
086:            private Vector<ConnectionEventListener> eventListeners = new Vector<ConnectionEventListener>();
087:
088:            /**
089:             * count of opening this connection. >0 if open.
090:             */
091:            private int open = 0;
092:
093:            /**
094:             * Transaction timeout value.
095:             */
096:            private int timeout = 0;
097:
098:            /**
099:             * Transaction the connection is involved with.
100:             */
101:            private Transaction tx = null;
102:
103:            /**
104:             * Counter of all managed connections created.
105:             */
106:            private static int objcount = 0;
107:
108:            /**
109:             * Identifier of this connection.
110:             */
111:            private final int identifier;
112:
113:            /**
114:             * Prepared statements that were reused.
115:             */
116:            private int reUsedPreparedStatements = 0;
117:
118:            /**
119:             * List of PreparedStatement in the pool.
120:             */
121:            private Map<String, JStatement> psList = null;
122:
123:            /**
124:             * Link to the connection manager.
125:             */
126:            private ConnectionManager ds = null;
127:
128:            /**
129:             * Time of the death for this connection.
130:             */
131:            private long deathTime = 0;
132:
133:            /**
134:             * Time for closing this connection.
135:             */
136:            private long closeTime = 0;
137:
138:            /**
139:             * Builds a new managed connection on a JDBC connection.
140:             * @param physicalConnection the physical JDBC Connection.
141:             * @param ds the connection manager
142:             */
143:            public JManagedConnection(final Connection physicalConnection,
144:                    final ConnectionManager ds) {
145:                this .physicalConnection = physicalConnection;
146:                this .ds = ds;
147:
148:                // An XAConnection holds 2 objects: 1 Connection + 1 XAResource
149:                this .implConn = new JConnection(this , physicalConnection);
150:
151:                open = 0;
152:                deathTime = System.currentTimeMillis() + ds.getMaxAgeMilli();
153:
154:                identifier = objcount++;
155:
156:                // Prepared statement.
157:                pstmtmax = ds.getPstmtMax();
158:                psOpenNb = 0;
159:                psList = Collections
160:                        .synchronizedMap(new HashMap<String, JStatement>());
161:
162:            }
163:
164:            /**
165:             * @return The identifier of this JManagedConnection
166:             */
167:            public int getIdentifier() {
168:                return identifier;
169:            }
170:
171:            /**
172:             * Dynamically change the prepared statement pool size.
173:             * @param max the maximum of prepared statement.
174:             */
175:            public void setPstmtMax(final int max) {
176:                pstmtmax = max;
177:                if (psList == null) {
178:                    psList = Collections
179:                            .synchronizedMap(new HashMap<String, JStatement>(
180:                                    pstmtmax));
181:                }
182:            }
183:
184:            /**
185:             * Commit the global transaction specified by xid.
186:             * @param xid transaction xid
187:             * @param onePhase true if one phase commit
188:             * @throws XAException XA protocol error
189:             */
190:            public void commit(final Xid xid, final boolean onePhase)
191:                    throws XAException {
192:                logger.debug("XA-COMMIT for {0}", xid);
193:
194:                // Commit the transaction
195:                try {
196:                    physicalConnection.commit();
197:                } catch (SQLException e) {
198:                    logger.error("Cannot commit transaction", e);
199:                    notifyError(e);
200:                    throw new XAException("Error on commit");
201:                }
202:            }
203:
204:            /**
205:             * Ends the work performed on behalf of a transaction branch.
206:             * @param xid transaction xid
207:             * @param flags currently unused
208:             * @throws XAException XA protocol error
209:             */
210:            public void end(final Xid xid, final int flags) throws XAException {
211:                logger.debug("XA-END for {0}", xid);
212:            }
213:
214:            /**
215:             * Tell the resource manager to forget about a heuristically completed
216:             * transaction branch.
217:             * @param xid transaction xid
218:             * @throws XAException XA protocol error
219:             */
220:            public void forget(final Xid xid) throws XAException {
221:                logger.debug("XA-FORGET for {0}", xid);
222:            }
223:
224:            /**
225:             * Obtain the current transaction timeout value set for this XAResource
226:             * instance.
227:             * @return the current transaction timeout in seconds
228:             * @throws XAException XA protocol error
229:             */
230:            public int getTransactionTimeout() throws XAException {
231:                logger.debug("getTransactionTimeout for {0}", this );
232:                return timeout;
233:            }
234:
235:            /**
236:             * Determine if the resource manager instance represented by the target
237:             * object is the same as the resource manager instance represented by the
238:             * parameter xares.
239:             * @param xares An XAResource object
240:             * @return True if same RM instance, otherwise false.
241:             * @throws XAException XA protocol error
242:             */
243:            public boolean isSameRM(final XAResource xares) throws XAException {
244:
245:                // In this pseudo-driver, we must return true only if
246:                // both objects refer to the same XAResource, and not
247:                // the same Resource Manager, because actually, we must
248:                // send commit/rollback on each XAResource involved in
249:                // the transaction.
250:                if (xares.equals(this )) {
251:                    logger.debug("isSameRM = true {0}", this );
252:                    return true;
253:                }
254:                logger.debug("isSameRM = false {0}", this );
255:                return false;
256:            }
257:
258:            /**
259:             * Ask the resource manager to prepare for a transaction commit of the
260:             * transaction specified in xid.
261:             * @param xid transaction xid
262:             * @throws XAException XA protocol error
263:             * @return always OK
264:             */
265:            public int prepare(final Xid xid) throws XAException {
266:                logger.debug("XA-PREPARE for {0}", xid);
267:                // No 2PC on standard JDBC drivers
268:                return XA_OK;
269:            }
270:
271:            /**
272:             * Obtain a list of prepared transaction branches from a resource manager.
273:             * @param flag unused parameter.
274:             * @return an array of transaction Xids
275:             * @throws XAException XA protocol error
276:             */
277:            public Xid[] recover(final int flag) throws XAException {
278:                logger.debug("XA-RECOVER for {0}", this );
279:                // Not implemented
280:                return null;
281:            }
282:
283:            /**
284:             * Inform the resource manager to roll back work done on behalf of a
285:             * transaction branch.
286:             * @param xid transaction xid
287:             * @throws XAException XA protocol error
288:             */
289:            public void rollback(final Xid xid) throws XAException {
290:                logger.debug("XA-ROLLBACK for {0}", xid);
291:
292:                // Make sure that we are not in AutoCommit mode
293:                try {
294:                    if (physicalConnection.getAutoCommit()) {
295:                        logger
296:                                .error("Rollback called on XAResource with AutoCommit set");
297:                        throw (new XAException(XAException.XA_HEURCOM));
298:                    }
299:                } catch (SQLException e) {
300:                    logger.error("Cannot getAutoCommit", e);
301:                    notifyError(e);
302:                    throw (new XAException("Error on getAutoCommit"));
303:                }
304:
305:                // Rollback the transaction
306:                try {
307:                    physicalConnection.rollback();
308:                } catch (SQLException e) {
309:                    logger.error("Cannot rollback transaction", e);
310:                    notifyError(e);
311:                    throw (new XAException("Error on rollback"));
312:                }
313:            }
314:
315:            /**
316:             * Set the current transaction timeout value for this XAResource instance.
317:             * @param seconds timeout value, in seconds.
318:             * @return always true
319:             * @throws XAException XA protocol error
320:             */
321:            @SuppressWarnings("boxing")
322:            public boolean setTransactionTimeout(final int seconds)
323:                    throws XAException {
324:                logger.debug("setTransactionTimeout to {0} for {1}", seconds,
325:                        this );
326:                timeout = seconds;
327:                return true;
328:            }
329:
330:            /**
331:             * Start work on behalf of a transaction branch specified in xid.
332:             * @param xid transaction xid
333:             * @param flags unused parameter
334:             * @throws XAException XA protocol error
335:             */
336:            public void start(final Xid xid, final int flags)
337:                    throws XAException {
338:                logger.debug("XA-START for {0}", xid);
339:            }
340:
341:            /**
342:             * Return an XA resource to the caller.
343:             * @return The XAResource
344:             * @exception SQLException - if a database-access error occurs
345:             */
346:            public XAResource getXAResource() throws SQLException {
347:                return this ;
348:            }
349:
350:            /**
351:             * Compares this object with another specified object.
352:             * @param o the object to compare
353:             * @return a value detecting if these objects are matching or not.
354:             */
355:            public int compareTo(final Object o) {
356:                JManagedConnection other = (JManagedConnection) o;
357:                int diff = getReUsedPreparedStatements()
358:                        - other.getReUsedPreparedStatements();
359:                if (diff == 0) {
360:                    return getIdentifier() - other.getIdentifier();
361:                }
362:                return diff;
363:            }
364:
365:            /**
366:             * @return value of reused prepared statement.
367:             */
368:            public int getReUsedPreparedStatements() {
369:                return reUsedPreparedStatements;
370:            }
371:
372:            /**
373:             * Create an object handle for a database connection.
374:             * @exception SQLException - if a database-access error occurs
375:             * @return connection used by this managed connection
376:             */
377:            public Connection getConnection() throws SQLException {
378:                // Just return the already created object.
379:                return implConn;
380:            }
381:
382:            /**
383:             * Close the database connection.
384:             * @exception SQLException - if a database-access error occurs
385:             */
386:            public void close() throws SQLException {
387:
388:                // Close the actual Connection here.
389:                if (physicalConnection != null) {
390:                    physicalConnection.close();
391:                } else {
392:                    logger
393:                            .error(
394:                                    "Connection already closed. Stack of this new close()",
395:                                    new Exception());
396:                }
397:                physicalConnection = null;
398:                implConn = null;
399:            }
400:
401:            /**
402:             * Add an event listener.
403:             * @param listener event listener
404:             */
405:            public void addConnectionEventListener(
406:                    final ConnectionEventListener listener) {
407:                eventListeners.addElement(listener);
408:            }
409:
410:            /**
411:             * Remove an event listener.
412:             * @param listener event listener
413:             */
414:            public void removeConnectionEventListener(
415:                    final ConnectionEventListener listener) {
416:                eventListeners.removeElement(listener);
417:            }
418:
419:            /**
420:             * synchronization implementation. {@inheritDoc}
421:             */
422:            public void beforeCompletion() {
423:                // nothing to do
424:            }
425:
426:            /**
427:             * synchronization implementation. {@inheritDoc}
428:             */
429:            public void afterCompletion(final int status) {
430:                if (tx != null) {
431:                    ds.freeConnections(tx);
432:                } else {
433:                    logger.error("NO TX!");
434:                }
435:            }
436:
437:            /**
438:             * @return true if connection max age has expired
439:             */
440:            public boolean isAged() {
441:                return (deathTime < System.currentTimeMillis());
442:            }
443:
444:            /**
445:             * @return true if connection is still open
446:             */
447:            public boolean isOpen() {
448:                return (open > 0);
449:            }
450:
451:            /**
452:             * @return open count
453:             */
454:            public int getOpenCount() {
455:                return open;
456:            }
457:
458:            /**
459:             * Check if the connection has been unused for too long time. This occurs
460:             * usually when the caller forgot to call close().
461:             * @return true if open time has been reached, and not involved in a tx.
462:             */
463:            public boolean inactive() {
464:                return (open > 0 && tx == null && closeTime < System
465:                        .currentTimeMillis());
466:            }
467:
468:            /**
469:             * @return true if connection is closed
470:             */
471:            public boolean isClosed() {
472:                return (open <= 0);
473:            }
474:
475:            /**
476:             * Notify as opened.
477:             */
478:            public void hold() {
479:                open++;
480:                closeTime = System.currentTimeMillis()
481:                        + ds.getMaxOpenTimeMilli();
482:            }
483:
484:            /**
485:             * notify as closed.
486:             * @return true if normal close.
487:             */
488:            public boolean release() {
489:                open--;
490:                if (open < 0) {
491:                    logger.warn("connection was already closed");
492:                    open = 0;
493:                    return false;
494:                }
495:                if (tx == null && open > 0) {
496:                    logger.error("connection-open counter overflow");
497:                    open = 0;
498:                }
499:                return true;
500:            }
501:
502:            /**
503:             * Set the associated transaction.
504:             * @param tx Transaction
505:             */
506:            public void setTx(final Transaction tx) {
507:                this .tx = tx;
508:            }
509:
510:            /**
511:             * @return the Transaction
512:             */
513:            public Transaction getTx() {
514:                return tx;
515:            }
516:
517:            /**
518:             * remove this item, ignoring exception on close.
519:             */
520:            public void remove() {
521:                // Close the physical connection
522:                try {
523:                    close();
524:                } catch (java.sql.SQLException ign) {
525:                    logger.error("Could not close Connection: ", ign);
526:                }
527:
528:                // remove all references (for GC)
529:                tx = null;
530:
531:            }
532:
533:            // -----------------------------------------------------------------
534:            // Other methods
535:            // -----------------------------------------------------------------
536:
537:            /**
538:             * Try to find a PreparedStatement in the pool for the given options.
539:             * @param sql the sql of the prepared statement
540:             * @param resultSetType the type of resultset
541:             * @param resultSetConcurrency the concurrency of this resultset
542:             * @return a preparestatement object
543:             * @throws SQLException if an errors occurs on the database.
544:             */
545:            public PreparedStatement prepareStatement(final String sql,
546:                    final int resultSetType, final int resultSetConcurrency)
547:                    throws SQLException {
548:
549:                logger.debug("sql = {0}", sql);
550:                if (pstmtmax == 0) {
551:                    return physicalConnection.prepareStatement(sql,
552:                            resultSetType, resultSetConcurrency);
553:                }
554:                JStatement ps = null;
555:                synchronized (psList) {
556:                    ps = psList.get(sql);
557:                    if (ps != null) {
558:                        if (!ps.isClosed()) {
559:                            logger.warn("reuse an open pstmt");
560:                        }
561:                        ps.reuse();
562:                        reUsedPreparedStatements++;
563:                    } else {
564:                        // Not found in cache. Create a new one.
565:                        PreparedStatement aps = physicalConnection
566:                                .prepareStatement(sql, resultSetType,
567:                                        resultSetConcurrency);
568:                        ps = new JStatement(aps, this , sql);
569:                        psList.put(sql, ps);
570:                    }
571:                    psOpenNb++;
572:                }
573:                return ps;
574:            }
575:
576:            /**
577:             * Try to find a PreparedStatement in the pool.
578:             * @param sql the given sql query.
579:             * @throws SQLException if an error in the database occurs.
580:             * @return a given prepared statement.
581:             */
582:            public PreparedStatement prepareStatement(final String sql)
583:                    throws SQLException {
584:                return prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY,
585:                        ResultSet.CONCUR_READ_ONLY);
586:            }
587:
588:            /**
589:             * A PreparedStatement has been logically closed.
590:             * @param ps a prepared statement.
591:             */
592:            public void notifyPsClose(final JStatement ps) {
593:                logger.debug(ps.getSql());
594:                synchronized (psList) {
595:                    psOpenNb--;
596:                    if (psList.size() >= pstmtmax) {
597:                        // Choose a closed element to remove.
598:                        JStatement lru = null;
599:                        Iterator i = psList.values().iterator();
600:                        while (i.hasNext()) {
601:                            lru = (JStatement) i.next();
602:                            if (lru.isClosed()) {
603:                                // actually, remove the first closed element.
604:                                i.remove();
605:                                lru.forget();
606:                                break;
607:                            }
608:                        }
609:                    }
610:                }
611:            }
612:
613:            /**
614:             * Notify a Close event on Connection.
615:             */
616:            @SuppressWarnings("boxing")
617:            public void notifyClose() {
618:
619:                // Close all PreparedStatement not already closed
620:                // When a Connection has been closed, no PreparedStatement should
621:                // remain open. This can avoids lack of cursor on some databases.
622:                synchronized (psList) {
623:                    if (psOpenNb > 0) {
624:                        JStatement jst = null;
625:                        Iterator i = psList.values().iterator();
626:                        while (i.hasNext()) {
627:                            jst = (JStatement) i.next();
628:                            if (jst.forceClose()) {
629:                                psOpenNb--;
630:                            }
631:                        }
632:                        if (psOpenNb != 0) {
633:                            logger.warn("Bad psOpenNb value = {0}", psOpenNb);
634:                            psOpenNb = 0;
635:                        }
636:                    }
637:                }
638:
639:                // Notify event to listeners
640:                for (int i = 0; i < eventListeners.size(); i++) {
641:                    ConnectionEventListener l = eventListeners.elementAt(i);
642:                    l.connectionClosed(new ConnectionEvent(this ));
643:                }
644:            }
645:
646:            /**
647:             * Notify an Error event on Connection.
648:             * @param ex the given exception
649:             */
650:            public void notifyError(final SQLException ex) {
651:                // Notify event to listeners
652:                for (int i = 0; i < eventListeners.size(); i++) {
653:                    ConnectionEventListener l = eventListeners.elementAt(i);
654:                    l.connectionErrorOccurred(new ConnectionEvent(this, ex));
655:                }
656:            }
657:
658:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.