0001: /**
0002: * JOnAS: Java(TM) Open Application Server
0003: * Copyright (C) 1999 Bull S.A.
0004: * Contact: jonas-team@objectweb.org
0005: *
0006: * This library is free software; you can redistribute it and/or
0007: * modify it under the terms of the GNU Lesser General Public
0008: * License as published by the Free Software Foundation; either
0009: * version 2.1 of the License, or any later version.
0010: *
0011: * This library is distributed in the hope that it will be useful,
0012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * Lesser General Public License for more details.
0015: *
0016: * You should have received a copy of the GNU Lesser General Public
0017: * License along with this library; if not, write to the Free Software
0018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
0019: * USA
0020: *
0021: * --------------------------------------------------------------------------
0022: * $Id: ConnectionManagerImpl.java 9932 2007-01-18 00:03:16Z ehardesty $
0023: * --------------------------------------------------------------------------
0024: */package org.objectweb.jonas.resource;
0025:
0026: import java.io.PrintWriter;
0027: import java.sql.Connection;
0028: import java.sql.PreparedStatement;
0029: import java.sql.ResultSet;
0030: import java.sql.SQLException;
0031: import java.util.Enumeration;
0032: import java.util.HashSet;
0033: import java.util.Hashtable;
0034: import java.util.Iterator;
0035: import java.util.Properties;
0036: import java.util.Set;
0037: import java.util.Vector;
0038:
0039: import javax.naming.Context;
0040: import javax.naming.NamingException;
0041: import javax.resource.NotSupportedException;
0042: import javax.resource.ResourceException;
0043: import javax.resource.spi.ConnectionEvent;
0044: import javax.resource.spi.ConnectionEventListener;
0045: import javax.resource.spi.ConnectionManager;
0046: import javax.resource.spi.ConnectionRequestInfo;
0047: import javax.resource.spi.ManagedConnection;
0048: import javax.resource.spi.ManagedConnectionFactory;
0049: import javax.resource.spi.ResourceAllocationException;
0050: import javax.resource.spi.ValidatingManagedConnectionFactory;
0051: import javax.security.auth.Subject;
0052: import javax.transaction.RollbackException;
0053: import javax.transaction.Transaction;
0054: import javax.transaction.xa.XAResource;
0055:
0056: import org.objectweb.jonas.common.Log;
0057: import org.objectweb.jonas.resource.pool.api.Pool;
0058: import org.objectweb.jonas.resource.pool.api.PoolMatchFactory;
0059: import org.objectweb.jonas.resource.pool.lib.HArrayPool;
0060: import org.objectweb.jotm.Current;
0061: import org.objectweb.jotm.TransactionResourceManager;
0062: import org.objectweb.transaction.jta.ResourceManagerEventListener;
0063: import org.objectweb.transaction.jta.TransactionManager;
0064: import org.objectweb.util.monolog.api.BasicLevel;
0065: import org.objectweb.util.monolog.api.Logger;
0066: import org.objectweb.util.monolog.api.LoggerFactory;
0067: import org.objectweb.util.monolog.wrapper.printwriter.LoggerImpl;
0068:
0069: /**
0070: * Description of the ConnectionManagerImpl
0071: *
0072: *@author chassand
0073: *created 15 novembre 2001
0074: */
0075: public class ConnectionManagerImpl implements ConnectionEventListener,
0076: ConnectionManager, PoolMatchFactory, SQLManager,
0077: TransactionResourceManager {
0078:
0079: /**
0080: * Main logger
0081: */
0082: protected static Logger trace = null;
0083: /**
0084: * Connection Management logger
0085: */
0086: protected static Logger conTrace = null;
0087: /**
0088: * Pool infomation logger
0089: */
0090: protected static Logger poolTrace = null;
0091:
0092: /**
0093: * Used by the server to register connections when no
0094: * transactionnal context exists
0095: */
0096: protected ResourceManagerEventListener rmel = null;
0097:
0098: /**
0099: * Holds the resource bundle name
0100: */
0101: private String resourceBundleName = null;
0102:
0103: /**
0104: * The transaction manager in server
0105: */
0106: protected TransactionManager tm;
0107:
0108: /**
0109: * This hashtable allows to find the list of connection handle associated to a
0110: * ManagedConnection
0111: */
0112: protected Hashtable mc2mci = null;
0113:
0114: /**
0115: * The jndiname of the associated factory
0116: */
0117: protected String jndiname = null;
0118:
0119: /**
0120: * The max pool size of ManagedConnection. The default value is -1.
0121: */
0122: private int mcMaxPoolSize = -1;
0123:
0124: /**
0125: * The min pool size of ManagedConnection. The default value is 0
0126: */
0127: private int mcMinPoolSize = 0;
0128:
0129: /**
0130: * The ManagedConnectionFactory instance which represents the resource
0131: * adapter.
0132: */
0133: private ManagedConnectionFactory mcf;
0134: /**
0135: * The ValidatingManagedConnectionFactory instance which represents the resource
0136: * adapter.
0137: */
0138: private ValidatingManagedConnectionFactory vmcf = null;
0139:
0140: /**
0141: * The pool of ManagedConnections associated to a ManagedConnectionFactory
0142: * There's one instance of pool by instance for one instance of this class (ConnectionManagerImpl).
0143: * The synchronization of the methods of this are ensured through synchronized
0144: * blocks on the poolMCs instance. Thus, the lock are shared between the two objects and that
0145: * avoids deadlock issues when the poolMCs.getRessource() is waiting for a connection releasing
0146: * (max nb of instances is reached in the pool).
0147: */
0148: protected Pool poolMCs = null;
0149:
0150: /**
0151: * The list of used ManagedConnections key = transaction reference value =
0152: * MCInfo
0153: */
0154: protected Hashtable usedMCs = null;
0155:
0156: /**
0157: * The default max pool size of pstmts per ManagedConnection.
0158: */
0159: static final int MAX_PSTMT_SIZE = 20;
0160:
0161: /**
0162: * PrepareStatement cache max pool size
0163: */
0164: private int maxPstmtPoolSize = MAX_PSTMT_SIZE;
0165:
0166: /**
0167: * JDBC connection level value
0168: */
0169: private int jdbcConnLevel = 0;
0170: /**
0171: * JDBC connection level value
0172: */
0173: private String jdbcConnTestStmt = "";
0174:
0175: /**
0176: * The list of managedConnection used without transaction
0177: */
0178: protected Vector mcs = new Vector();
0179:
0180: /**
0181: * The list of Synchronisation instance managed in this ConnectionManager
0182: */
0183: protected Vector synchros = new Vector();
0184:
0185: /**
0186: * This is a cache to the last instance of ResourceSpec used by the
0187: * ConnectionManager. Indeed this instance is always the same.
0188: */
0189: private ResourceSpec rs = null;
0190:
0191: /**
0192: * The holds the transaction support level for the associated RAR file
0193: */
0194: private String transSupport = null;
0195:
0196: /**
0197: * This constant is used in the by the init method
0198: */
0199: public final static String RESOURCE_BUNDLE_NAME = "resourceBundleName";
0200: /**
0201: * This constant is used in the by the init method
0202: */
0203: public final static String LOGGER = "org.objectweb.util.monolog.logger";
0204: /**
0205: * This constant is used in the by the init method
0206: */
0207: public final static String POOL_LOGGER = "org.objectweb.util.monolog.logger_pool";
0208: /**
0209: * This constant is used in the by the init method
0210: */
0211: public final static String JNDINAME = "jndiname";
0212: /**
0213: * This constant is used in the by the init method
0214: */
0215: public final static String LOGGER_FACTORY = "org.objectweb.util.monolog.loggerFactory";
0216: /**
0217: * This constant is used in the by the init method
0218: */
0219: public final static String TRANSACTION_MANAGER = "transactionManager";
0220: /**
0221: * This constant is used in the by the init method
0222: */
0223: public final static String RESOURCE_MANAGER_EVENT_LISTENER = "resourceManagerEventListener";
0224: /**
0225: * This constant is used in the by the init method
0226: */
0227: public final static String RESOURCE_ADAPTER = "resourceAdapter";
0228: /**
0229: * This constant is used in the by the init method
0230: */
0231: public final static String PRINT_WRITER = "printWriter";
0232:
0233: /*
0234: * These constants define the different transaction support values
0235: */
0236: /**
0237: * Rar doesn't support transactions
0238: */
0239: public final static String NO_TRANS_SUPPORT = "NoTransaction";
0240: /**
0241: * Rar supports local transactions
0242: */
0243: public final static String LOCAL_TRANS_SUPPORT = "LocalTransaction";
0244: /**
0245: * Rar supports XA transactions
0246: */
0247: public final static String XA_TRANS_SUPPORT = "XATransaction";
0248:
0249: /**
0250: * Constants to determine which PreparedStatement types to call
0251: *
0252: */
0253: public final static int PSWRAP_1 = 1;
0254: public final static int PSWRAP_2 = 2;
0255: public final static int PSWRAP_3 = 3;
0256: public final static int PSWRAP_4 = 4;
0257: public final static int PSWRAP_5 = 5;
0258:
0259: /**
0260: * Constants for use with JDBC connection level
0261: */
0262: public final static int JDBC_NO_TEST = 0;
0263: public final static int JDBC_CHECK_CONNECTION = 1;
0264: public final static int JDBC_SEND_STATEMENT = 2;
0265: public final static int JDBC_KEEP_ALIVE = 3;
0266:
0267: // JOTM variables
0268: /**
0269: * ManagedConnection used with JOTM recovery
0270: */
0271: private ManagedConnection jotmMc = null;
0272: /**
0273: * XAResource used with JOTM recovery
0274: */
0275: private XAResource jotmXar = null;
0276: /**
0277: * XA Name used with JOTM recovery
0278: */
0279: private String xaName = null;
0280:
0281: /**
0282: * Debug is enabled ?
0283: */
0284: private boolean isEnabledDebug = false;
0285:
0286: /**
0287: * ConnectionManagerImpl constructor
0288: * @param transSupport String defining level of support needed
0289: */
0290: public ConnectionManagerImpl(String transSupport) {
0291: if (transSupport.length() == 0) {
0292: transSupport = NO_TRANS_SUPPORT;
0293: } else {
0294: this .transSupport = transSupport;
0295: }
0296: }
0297:
0298: /**
0299: * Setters method to initialize the ConnectionManager The logger instance
0300: * where events are logged
0301: *
0302: *@param l The new Logger value
0303: */
0304: public void setLogger(Logger l) {
0305: trace = l;
0306: isEnabledDebug = trace.isLoggable(BasicLevel.DEBUG);
0307: }
0308:
0309: /**
0310: * Setters method to initialize the ConnectionManager A logger factory to
0311: * obtain a logger
0312: *
0313: *@param lf The new LoggerFactory value
0314: */
0315: public void setLoggerFactory(LoggerFactory lf) {
0316: trace = lf.getLogger("org.objectweb.resource.server");
0317: isEnabledDebug = trace.isLoggable(BasicLevel.DEBUG);
0318: }
0319:
0320: /**
0321: * Setters method to initialize the ConnectionManager The printwriter where
0322: * event are logged
0323: *
0324: *@param pw The new PrintWriter value
0325: */
0326: public void setPrintWriter(PrintWriter pw) {
0327: trace = new LoggerImpl(pw);
0328: }
0329:
0330: /**
0331: * Setters method to initialize the ConnectionManager The logger instance
0332: * where events are logged
0333: *
0334: *@param rmel The new ResourceManagerEventListener value
0335: */
0336: public void setResourceManagerEventListener(
0337: ResourceManagerEventListener rmel) {
0338: this .rmel = rmel;
0339: }
0340:
0341: /**
0342: * Setters method to initialize the ConnectionManager The Transaction manager
0343: * linked to this resource managed
0344: *
0345: *@param tm TransactionManager value
0346: */
0347: public void setTransactionManager(TransactionManager tm) {
0348: this .tm = tm;
0349: }
0350:
0351: /**
0352: * Setters method to initialize the ConnectionManager The
0353: * managedConnectionFactory instance of the resource which must be managed by
0354: * this connectionManager
0355: *
0356: *@param tmcf The new ResourceAdapter value
0357: *@exception Exception Description of Exception
0358: */
0359: public void setResourceAdapter(ManagedConnectionFactory tmcf)
0360: throws Exception {
0361: setResourceAdapter(tmcf, new ConnectionManagerPoolParams());
0362: }
0363:
0364: /**
0365: * Setters method to initialize the ConnectionManager The
0366: * managedConnectionFactory instance of the resource which must be maneged by
0367: * this connectionManager
0368: *
0369: *@param tmcf The ManagedConnectionFactory object
0370: *@param cmpp The pool parameters
0371: *@exception Exception Description of Exception
0372: */
0373: public void setResourceAdapter(ManagedConnectionFactory tmcf,
0374: ConnectionManagerPoolParams cmpp) throws Exception {
0375:
0376: // set the max/min pool values
0377: if (cmpp.getPoolMax() != 0) {
0378: mcMaxPoolSize = cmpp.getPoolMax();
0379: }
0380: if (cmpp.getPoolMin() > 0) {
0381: mcMinPoolSize = cmpp.getPoolMin();
0382: }
0383:
0384: // set the jdbc connection info
0385: jdbcConnLevel = cmpp.getJdbcConnLevel();
0386: jdbcConnTestStmt = cmpp.getJdbcConnTestStmt();
0387:
0388: mcf = tmcf;
0389: if (mcf instanceof ValidatingManagedConnectionFactory) {
0390: vmcf = (ValidatingManagedConnectionFactory) mcf;
0391: }
0392:
0393: poolMCs = new HArrayPool(poolTrace, jndiname);
0394: poolMCs.setMatchFactory(this );
0395:
0396: if (cmpp.getPoolMaxAge() > 0) {
0397: int min = (int) (cmpp.getPoolMaxAge() / 60);
0398: poolMCs.setMaxAge(min);
0399: } else {
0400: poolMCs.setMaxAge(cmpp.getPoolMaxAgeMinutes());
0401: }
0402:
0403: if (cmpp.getPoolMaxOpentime() > 0) {
0404: poolMCs.setMaxOpentime(cmpp.getPoolMaxOpentime());
0405: }
0406: poolMCs.setMaxWaiters(cmpp.getPoolMaxWaiters());
0407: if (cmpp.getPoolMaxWaittime() > 0) {
0408: poolMCs.setMaxWaitTime(cmpp.getPoolMaxWaittime());
0409: }
0410:
0411: poolMCs.setMaxSize(mcMaxPoolSize);
0412: poolMCs.setInitSize(cmpp.getPoolInit());
0413: poolMCs.setMinSize(mcMinPoolSize);
0414: poolMCs.setJdbcConnLevel(jdbcConnLevel);
0415: poolMCs.setJdbcTestStatement(jdbcConnTestStmt);
0416:
0417: poolMCs.startMonitor();
0418: poolMCs.setSamplingPeriod(cmpp.getPoolSamplingPeriod());
0419: maxPstmtPoolSize = cmpp.getPstmtMax();
0420:
0421: usedMCs = new Hashtable();
0422: rs = new ResourceSpec(null, null);
0423:
0424: if (isEnabledDebug) {
0425: trace.log(BasicLevel.DEBUG, "");
0426: }
0427: }
0428:
0429: /**
0430: * This method permits to initialize the ConnectionManager with the following
0431: * parameter: RESOURCE_BUNDLE_NAME: The name of the resource bundle in order
0432: * to internationalize the logging LOGGER: The logger instance where events
0433: * are logged LOGGER_FACTORY: A logger factory to obtain a logger
0434: * PRINT_WRITER: The printwriter where event are logged TRANSACTION_MANAGER:
0435: * The Transaction manager linked to this resource manager
0436: * RESOURCE_MANAGER_EVENT_LISTENER: The resource manage event listener which
0437: * subscribed to later connection enlistement. RESOURCE_ADAPTER: The
0438: * managedConnectionFactory instance of the resource which must be maneged by
0439: * this connectionManager
0440: * JNDINAME: JndiName from the factory associated with this ConnectionManager
0441: *
0442: *@param ctx Description of Parameter
0443: *@exception Exception Description of Exception
0444: */
0445: public void init(Context ctx) throws Exception {
0446: mc2mci = new Hashtable();
0447:
0448: // Get the resource bundle name to internationalise the log
0449: // Optional
0450: String resourceBundleName = null;
0451: try {
0452: resourceBundleName = (String) ctx
0453: .lookup(RESOURCE_BUNDLE_NAME);
0454: } catch (NamingException e) {
0455: }
0456:
0457: // Get the logger or the logger factory or the printwriter
0458: try {
0459: trace = (Logger) ctx.lookup(LOGGER);
0460: poolTrace = (Logger) ctx.lookup(POOL_LOGGER);
0461: } catch (NamingException e) {
0462: }
0463:
0464: conTrace = Log.getLogger(Log.JONAS_JCA_PREFIX + ".connection");
0465: if (trace == null) {
0466: try {
0467: setLoggerFactory((LoggerFactory) ctx
0468: .lookup(LOGGER_FACTORY));
0469: } catch (NamingException e2) {
0470: }
0471: }
0472: if (trace == null) {
0473: PrintWriter pw = null;
0474: try {
0475: pw = (PrintWriter) ctx.lookup(PRINT_WRITER);
0476: } catch (NamingException e3) {
0477: }
0478: setPrintWriter(pw);
0479: }
0480: if (trace != null) {
0481: isEnabledDebug = trace.isLoggable(BasicLevel.DEBUG);
0482: }
0483:
0484: if (!transSupport.equalsIgnoreCase(NO_TRANS_SUPPORT)) {
0485: // Get the transaction manager
0486: tm = (TransactionManager) ctx.lookup(TRANSACTION_MANAGER);
0487: }
0488:
0489: // Get the set of connection
0490: try {
0491: rmel = (ResourceManagerEventListener) ctx
0492: .lookup(RESOURCE_MANAGER_EVENT_LISTENER);
0493: } catch (NamingException ne) {
0494: }
0495:
0496: // Get the managedConnectionFactory instance which represents the resource
0497: // adapter
0498: try {
0499: setResourceAdapter((ManagedConnectionFactory) ctx
0500: .lookup(RESOURCE_ADAPTER));
0501: } catch (NamingException ne) {
0502: }
0503:
0504: // Get the jndiname
0505: try {
0506: jndiname = (String) ctx.lookup(JNDINAME);
0507: } catch (NamingException ne) {
0508: }
0509:
0510: }
0511:
0512: /**
0513: * Description of the Method
0514: *
0515: *@exception ResourceException Description of Exception
0516: */
0517: public void cleanResourceAdapter() throws ResourceException {
0518:
0519: synchronized (poolMCs) {
0520:
0521: // Delete the PreparedStatements
0522: PreparedStatementWrapper pw = null;
0523: while (mcs != null && mcs.size() > 0) {
0524: MCInfo mci = (MCInfo) mcs.remove(0);
0525: mci.usedCs.clear();
0526: synchronized (mci.pStmts) {
0527: // Remove the PreparedStatements on the MC
0528: while (mci.pStmts != null && mci.pStmts.size() > 0) {
0529: pw = (PreparedStatementWrapper) mci.pStmts
0530: .remove(0);
0531: try {
0532: pw.destroy();
0533: } catch (Exception ex) {
0534: }
0535: }
0536: }
0537: try {
0538: mc2mci.remove(mci.mc);
0539: // mci.mc.destroy();
0540: } catch (Exception ex) {
0541: }
0542: }
0543: if (usedMCs != null) {
0544: for (Enumeration en = usedMCs.keys(); en
0545: .hasMoreElements();) {
0546: Transaction tx = (Transaction) en.nextElement();
0547: MCInfo mci = (MCInfo) usedMCs.get(tx);
0548: if (mci == null) {
0549: continue;
0550: }
0551: if (mci.rmeCalled) {
0552: mci.rme.isValid = false;
0553: rmel.connectionClosed(mci.rme);
0554: mci.rmeCalled = false;
0555: }
0556: mci.usedCs.clear();
0557: // Remove the PreparedStatements on the MC
0558: synchronized (mci.pStmts) {
0559: while (mci.pStmts != null
0560: && mci.pStmts.size() > 0) {
0561: pw = (PreparedStatementWrapper) mci.pStmts
0562: .remove(0);
0563: try {
0564: pw.destroy();
0565: } catch (Exception ex) {
0566: }
0567: }
0568: }
0569: try {
0570: mc2mci.remove(mci.mc);
0571: // mci.mc.destroy();
0572: } catch (Exception ex) {
0573: }
0574: }
0575: }
0576: while (synchros != null && synchros.size() > 0) {
0577: MCInfo mci = (MCInfo) synchros.remove(0);
0578: mci.usedCs.clear();
0579: // Remove the PreparedStatements on the MC
0580: synchronized (mci.pStmts) {
0581: while (mci.pStmts != null && mci.pStmts.size() > 0) {
0582: pw = (PreparedStatementWrapper) mci.pStmts
0583: .remove(0);
0584: try {
0585: pw.destroy();
0586: } catch (Exception ex) {
0587: }
0588: }
0589: }
0590: try {
0591: mc2mci.remove(mci.mc);
0592: // mci.mc.destroy();
0593: } catch (Exception ex) {
0594: }
0595: }
0596: }
0597: poolMCs.closeAllConnections();
0598: }
0599:
0600: /**
0601: *
0602: * The method allocateConnection gets called by the resource adapter's
0603: * connection factory instance.
0604: *
0605: * @see javax.resource.cci.ConnectionManager
0606: */
0607: public Object allocateConnection(ManagedConnectionFactory pMcf,
0608: ConnectionRequestInfo cxRequestInfo)
0609: throws ResourceException {
0610:
0611: MCInfo mci = null;
0612: Transaction currentTx = null;
0613: Object connection = null;
0614: int retries = 0;
0615: Subject subject = null;
0616:
0617: trace.log(BasicLevel.DEBUG, "");
0618: while (connection == null && retries < 20) {
0619: synchronized (poolMCs) {
0620: if (mcf != pMcf && !pMcf.equals(mcf)) {
0621: throw new ResourceException(
0622: "This ConnectionManager doesn't manage this RA:"
0623: + mcf);
0624: }
0625:
0626: currentTx = null;
0627: try {
0628: if (tm != null) {
0629: currentTx = tm.getTransaction();
0630: }
0631: } catch (Exception e) {
0632: trace
0633: .log(
0634: BasicLevel.ERROR,
0635: "Impossible to get the current transaction",
0636: e, "ConnectionManagerImpl",
0637: "allocateConnection");
0638: }
0639:
0640: //if there is a transaction check if a MC is already associated
0641: mci = (currentTx == null ? null : (MCInfo) usedMCs
0642: .get(currentTx));
0643: if (mci != null) {
0644: if (mci.mc != null) {
0645: // There are connections, try to match with the
0646: // ManagedConnectionFactory
0647: if (isEnabledDebug) {
0648: trace
0649: .log(
0650: BasicLevel.DEBUG,
0651: "MC ("
0652: + mci.mc
0653: + ") associated to the current Tx ("
0654: + currentTx
0655: + ") found");
0656: }
0657: Set s = new HashSet();
0658: s.add(mci.mc);
0659: if (mci.mc != mcf.matchManagedConnections(s,
0660: null, cxRequestInfo)) {
0661: throw new ResourceException(
0662: "ConnectionManagerImpl.allocateConnection: illegal state : no mc is matched by mcf");
0663: }
0664: if (isEnabledDebug) {
0665: trace.log(BasicLevel.DEBUG, "XA Resource "
0666: + mci.getXAResource()
0667: + " is already enlisted in Tx:"
0668: + mci.ctx);
0669: }
0670: } else {
0671: // This connection occurred an error before
0672: trace.log(BasicLevel.INFO,
0673: "remnant of an old failed connection");
0674: mci.ctx = null;
0675: mci = null;
0676: usedMCs.remove(currentTx);
0677: }
0678: }
0679:
0680: if (mci == null) {
0681: // No managed connection found => get a free ManagedConnection
0682: // from the right pool
0683:
0684: //ri.rs.subject = null; // Never set => already at null
0685: rs.cxRequestInfo = cxRequestInfo;
0686: if (subject == null && cxRequestInfo != null) {
0687: // Create a subject to pass on
0688: }
0689: try {
0690: ManagedConnection mc = (ManagedConnection) poolMCs
0691: .getResource(rs);
0692: if (mc == null) {
0693: throw new ResourceException(
0694: "ConnectionManagerImpl.allocateConnection: cannot allocate a ManagedConnection");
0695: }
0696: mci = (MCInfo) mc2mci.get(mc);
0697: if (mci == null) {
0698: mci = new MCInfo(mc);
0699: mc2mci.put(mc, mci);
0700: }
0701: if (isEnabledDebug) {
0702: trace.log(BasicLevel.DEBUG,
0703: "get a MC from the ra pool, mc="
0704: + mci.mc);
0705: }
0706: conTrace.log(BasicLevel.DEBUG,
0707: " returning mc = " + mc);
0708:
0709: if (transSupport
0710: .equalsIgnoreCase(LOCAL_TRANS_SUPPORT)) {
0711: if (mci.lw == null) {
0712: mci.lw = new LocalXAWrapper(mci.mc
0713: .getLocalTransaction(), trace);
0714: }
0715: } else if (mci.lw != null) {
0716: mci.lw = null;
0717: }
0718: if (!mci.connectionEventListener) {
0719: mci.mc.addConnectionEventListener(this );
0720: mci.connectionEventListener = true;
0721: }
0722: mci.synchro = null;
0723: // If a global transaction is already started then enlist the
0724: // ManagedConnection instance
0725: if (currentTx != null) {
0726: if (isEnabledDebug) {
0727: trace
0728: .log(
0729: BasicLevel.DEBUG,
0730: "Enlist the XA Resource "
0731: + mci
0732: .getXAResource()
0733: + " in Tx:"
0734: + currentTx);
0735: }
0736: currentTx.enlistResource(mci
0737: .getXAResource());
0738: usedMCs.put(currentTx, mci);
0739: mci.ctx = currentTx;
0740: } else {
0741: // There are not Transaction at the moment but the user can
0742: // start a transaction after the getConnection call.
0743: mci.ctx = null;
0744: // must be clean
0745: mcs.add(mci);
0746: // NoTransaction is specified, so don't register the MC
0747: if (!transSupport
0748: .equalsIgnoreCase(NO_TRANS_SUPPORT)) {
0749: mci.rme = new RMEImpl(mci, trace);
0750: if (isEnabledDebug) {
0751: trace
0752: .log(BasicLevel.DEBUG,
0753: "Register the managed connection (no tx)");
0754: }
0755: // Always put in list, fix bug on connection late enlistment
0756: if (!mci.rmeCalled) {
0757: mci.rme.isValid = true;
0758: rmel.connectionOpened(mci.rme);
0759: mci.rmeCalled = true;
0760: }
0761: }
0762: }
0763: } catch (ResourceException re) {
0764: trace
0765: .log(BasicLevel.ERROR, re.getMessage(),
0766: re);
0767: throw re;
0768: } catch (Exception e) {
0769: String err = "Error related allocation of ManagedConnection";
0770: trace.log(BasicLevel.ERROR, err, e);
0771: throw new ResourceException(err, e);
0772: }
0773:
0774: }
0775:
0776: //Fetch a free Connection from the ManagedConnection
0777: connection = mci.mc.getConnection(null, cxRequestInfo);
0778: // Want to add the non-wrapped Connection object
0779: mci.usedCs.add(connection);
0780:
0781: conTrace.log(BasicLevel.DEBUG, " getting con("
0782: + connection + ") from mc(" + mci.mc
0783: + ") of factory(" + jndiname + ")");
0784: }
0785:
0786: if (connection instanceof java.sql.Connection) {
0787: try {
0788: // Need a wrapper for non JOnAS jdbc ConnectionImpl
0789: org.objectweb.jonas.jdbc.ConnectionImpl jdbcConn = null;
0790: if (connection instanceof org.objectweb.jonas.jdbc.ConnectionImpl) {
0791: jdbcConn = (org.objectweb.jonas.jdbc.ConnectionImpl) connection;
0792: jdbcConn.setJonasInfo(mci, this );
0793: // This used to be done in the ConnectionImpl constructor, but a synchronized block
0794: // is needed and we don't want any DB I/O within the block
0795: jdbcConn.setUser();
0796: // in case we do not start a Tx
0797: if (currentTx == null) {
0798: jdbcConn.setAutoCommit(true);
0799: }
0800: } else {
0801: connection = JonasSQLWrapper.createSQLWrapper(
0802: connection, mci, this , trace);
0803: }
0804: // Check the connection before reusing it
0805: if (jdbcConnLevel > JDBC_NO_TEST) {
0806: try {
0807: if (isEnabledDebug) {
0808: trace.log(BasicLevel.DEBUG,
0809: "Check the JDBC connection");
0810: }
0811: boolean isClosed = true;
0812: // Used for logical testing of connection
0813: if (connection instanceof org.objectweb.jonas.jdbc.ConnectionImpl) {
0814: isClosed = jdbcConn
0815: .isPhysicallyClosed();
0816: } else {
0817: isClosed = ((Connection) connection)
0818: .isClosed();
0819: }
0820: if (isClosed) {
0821: connectionErrorOccurred(new ConnectionEvent(
0822: mci.mc,
0823: ConnectionEvent.CONNECTION_ERROR_OCCURRED));
0824: try {
0825: mci.usedCs.remove(connection);
0826: } catch (Exception ex) {
0827: }
0828: connection = null;
0829: retries++;
0830: continue;
0831: }
0832: if (jdbcConnLevel > JDBC_CHECK_CONNECTION
0833: && jdbcConnTestStmt != null
0834: && jdbcConnTestStmt.length() > 0) {
0835: if (isEnabledDebug) {
0836: trace.log(BasicLevel.DEBUG,
0837: "retrying connection: "
0838: + jdbcConnTestStmt);
0839: }
0840: java.sql.Statement stmt = ((Connection) connection)
0841: .createStatement();
0842: stmt.execute(jdbcConnTestStmt);
0843: stmt.close();
0844: }
0845: } catch (Exception e) {
0846: trace.log(BasicLevel.ERROR,
0847: "Error on connection: removing invalid managed connection "
0848: + mci.mc + ": ", e);
0849: connectionErrorOccurred(new ConnectionEvent(
0850: mci.mc,
0851: ConnectionEvent.CONNECTION_ERROR_OCCURRED));
0852: try {
0853: mci.usedCs.remove(connection);
0854: } catch (Exception ex) {
0855: }
0856: connection = null;
0857: retries++;
0858: continue;
0859: }
0860: }
0861: } catch (Exception ex) {
0862: trace.log(BasicLevel.ERROR, ex.getMessage(), ex);
0863: throw new ResourceException(ex);
0864: }
0865: }
0866: }
0867: if (isEnabledDebug) {
0868: trace.log(BasicLevel.DEBUG,
0869: "get a logical connection on MC:" + connection);
0870: }
0871:
0872: if (connection == null) {
0873: if (retries > 0) {
0874: throw new ResourceAllocationException(
0875: "Unable to obtain a connection object. Check the validity of the jdbc-test-statement");
0876: } else {
0877: throw new ResourceAllocationException(
0878: "Unable to obtain a connection object");
0879: }
0880: }
0881:
0882: return connection;
0883: }
0884:
0885: /**
0886: * All method of the pool match to the right type of ManagedConnection because
0887: * there is one pool by ManagedConnectionFactory.
0888: *
0889: * @see org.objectweb.util.pool.api.PoolMatchFactory
0890: */
0891: public boolean matchResource(Object res, Object hints) {
0892: return true;
0893: }
0894:
0895: /**
0896: * All method of the pool match to the right type of ManagedConnection because
0897: * there is one pool by ManagedConnectionFactory.
0898: *
0899: * @see org.objectweb.util.pool.api.PoolMatchFactory
0900: */
0901: public Object matchResource(Set res, Object hints) throws Exception {
0902: ResourceSpec spec = (hints != null) ? (ResourceSpec) hints
0903: : new ResourceSpec(null, null);
0904: // If not supported, then just return null so another one will be created
0905: Object con = null;
0906: try {
0907: con = mcf.matchManagedConnections(res, null,
0908: spec.cxRequestInfo);
0909: } catch (NotSupportedException nse) {
0910: }
0911: return con;
0912: }
0913:
0914: /**
0915: * Call the ManagedConnectionFactory in order to create a new instance. of
0916: * ManagedConnection. The Object is a ManagedConnection instance. The hints is a
0917: * local structure: ResourceSpec
0918: *
0919: * @see org.objectweb.util.pool.api.PoolMatchFactory
0920: */
0921: public Object createResource(Object hints) throws Exception {
0922: ResourceSpec spec = (hints != null) ? (ResourceSpec) hints
0923: : new ResourceSpec(null, null);
0924: ManagedConnection mc = mcf.createManagedConnection(
0925: spec.subject, spec.cxRequestInfo);
0926: if (isEnabledDebug) {
0927: trace.log(BasicLevel.DEBUG, "Created MC: " + mc);
0928: }
0929: return mc;
0930: }
0931:
0932: /**
0933: * If supported, call the ManagedConnectionFactory to validate the ManagedConnections
0934: *
0935: * @see org.objectweb.util.pool.api.PoolMatchFactory
0936: */
0937: public void validateResource(Set res) throws Exception {
0938: if (vmcf == null) {
0939: return;
0940: }
0941: try {
0942: Set invMcs = vmcf.getInvalidConnections(res);
0943: Iterator it = invMcs.iterator();
0944: while (it.hasNext()) {
0945: Object obj = it.next();
0946: poolMCs.releaseResource(obj, true, true);
0947: }
0948: } catch (Exception ex) {
0949: if (isEnabledDebug) {
0950: trace.log(BasicLevel.DEBUG,
0951: "Error trying to validate Connections for "
0952: + mcf, ex);
0953: }
0954: }
0955: }
0956:
0957: /** IMPLEMENTATION OF INTERFACE SQLManager
0958: */
0959: public PreparedStatement getPStatement(MCInfo mcinfo, Object conn,
0960: String user, String sql) throws SQLException {
0961: return getPStatement(mcinfo, conn, user, sql,
0962: ResultSet.TYPE_FORWARD_ONLY,
0963: ResultSet.CONCUR_READ_ONLY, -1, -1, null, null,
0964: PSWRAP_1);
0965:
0966: }
0967:
0968: public PreparedStatement getPStatement(MCInfo mcinfo, Object conn,
0969: String user, String sql, int resultSetType,
0970: int resultSetConcurrency) throws SQLException {
0971: return getPStatement(mcinfo, conn, user, sql, resultSetType,
0972: resultSetConcurrency, -1, -1, null, null, PSWRAP_1);
0973: }
0974:
0975: // JDBC 3.0
0976: public PreparedStatement getPStatement(MCInfo mcinfo, Object conn,
0977: String user, String sql, int resultSetType,
0978: int resultSetConcurrency, int resultSetHoldability)
0979: throws SQLException {
0980: return getPStatement(mcinfo, conn, user, sql, resultSetType,
0981: resultSetConcurrency, resultSetHoldability, -1, null,
0982: null, PSWRAP_2);
0983: }
0984:
0985: // JDBC 3.0
0986: public PreparedStatement getPStatement(MCInfo mcinfo, Object conn,
0987: String user, String sql, int autoGeneratedKeys)
0988: throws SQLException {
0989: return getPStatement(mcinfo, conn, user, sql, -1, -1, -1,
0990: autoGeneratedKeys, null, null, PSWRAP_3);
0991: }
0992:
0993: // JDBC 3.0
0994: public PreparedStatement getPStatement(MCInfo mcinfo, Object conn,
0995: String user, String sql, int[] columnIndexes)
0996: throws SQLException {
0997: return getPStatement(mcinfo, conn, user, sql, -1, -1, -1, -1,
0998: columnIndexes, null, PSWRAP_4);
0999: }
1000:
1001: // JDBC 3.0
1002: public PreparedStatement getPStatement(MCInfo mcinfo, Object conn,
1003: String user, String sql, String[] columnNames)
1004: throws SQLException {
1005: return getPStatement(mcinfo, conn, user, sql, -1, -1, -1, -1,
1006: null, columnNames, PSWRAP_5);
1007: }
1008:
1009: private PreparedStatement getPStatement(MCInfo mcinfo, Object conn,
1010: String user, String sql, int resultSetType,
1011: int resultSetConcurrency, int resultSetHoldability,
1012: int autoGeneratedKeys, int[] columnIndexes,
1013: String[] columnNames, int pswrapType) throws SQLException {
1014:
1015: if (isEnabledDebug) {
1016: trace.log(BasicLevel.DEBUG, "Sql: " + sql + " User: "
1017: + user);
1018: }
1019: // Use for the equals test
1020: PreparedStatementWrapper psw = null;
1021: switch (pswrapType) {
1022: case PSWRAP_1:
1023: psw = new PreparedStatementWrapper(user, sql,
1024: resultSetType, resultSetConcurrency, trace,
1025: isEnabledDebug);
1026: break;
1027: case PSWRAP_2:
1028: psw = new PreparedStatementWrapper(user, sql,
1029: resultSetType, resultSetConcurrency,
1030: resultSetHoldability, trace, isEnabledDebug);
1031: break;
1032: case PSWRAP_3:
1033: psw = new PreparedStatementWrapper(user, sql,
1034: autoGeneratedKeys, trace, isEnabledDebug);
1035: break;
1036: case PSWRAP_4:
1037: psw = new PreparedStatementWrapper(user, sql,
1038: columnIndexes, trace, isEnabledDebug);
1039: break;
1040: case PSWRAP_5:
1041: psw = new PreparedStatementWrapper(user, sql, columnNames,
1042: trace, isEnabledDebug);
1043: break;
1044: default:
1045: break;
1046: }
1047:
1048: synchronized (mcinfo.pStmts) {
1049: if (isEnabledDebug) {
1050: trace.log(BasicLevel.DEBUG, "MC pStmts: "
1051: + mcinfo.pStmts);
1052: }
1053: //Check if statement matches ManagedConnection list & valid
1054: // use lastIndexOf as when a statement is found, it is put at the end.
1055: int indexPstmt = mcinfo.pStmts.lastIndexOf(psw);
1056: if (indexPstmt != -1) {
1057: PreparedStatementWrapper ps = (PreparedStatementWrapper) mcinfo.pStmts
1058: .remove(indexPstmt);
1059: ps.clearPstmtValues();
1060: mcinfo.pStmts.add(ps); // add last
1061: return ps;
1062: } else if (isEnabledDebug) {
1063: trace
1064: .log(BasicLevel.DEBUG,
1065: "No statement in cache, need to build a new one");
1066: }
1067:
1068: //If not in either, call con.prepareStatement, wrap the returned one
1069: // and add it to MC pool
1070: PreparedStatement ps = null;
1071: switch (pswrapType) {
1072: case PSWRAP_1:
1073: ps = ((java.sql.Connection) conn).prepareStatement(sql,
1074: resultSetType, resultSetConcurrency);
1075: break;
1076: case PSWRAP_2:
1077: ps = ((java.sql.Connection) conn).prepareStatement(sql,
1078: resultSetType, resultSetConcurrency,
1079: resultSetHoldability);
1080: break;
1081: case PSWRAP_3:
1082: ps = ((java.sql.Connection) conn).prepareStatement(sql,
1083: autoGeneratedKeys);
1084: break;
1085: case PSWRAP_4:
1086: ps = ((java.sql.Connection) conn).prepareStatement(sql,
1087: columnIndexes);
1088: break;
1089: case PSWRAP_5:
1090: ps = ((java.sql.Connection) conn).prepareStatement(sql,
1091: columnNames);
1092: break;
1093: default:
1094: break;
1095: }
1096: if (maxPstmtPoolSize < 0) {
1097: // No prepared statement pool
1098: if (isEnabledDebug) {
1099: trace.log(BasicLevel.DEBUG, "Pooling is disabled");
1100: }
1101: return ps;
1102: } else if (maxPstmtPoolSize == 0
1103: || mcinfo.pStmts.size() < maxPstmtPoolSize) {
1104: psw.setPreparedStatement(ps);
1105: mcinfo.pStmts.add(psw);
1106: if (isEnabledDebug) {
1107: trace.log(BasicLevel.DEBUG, "Adding PStmt: " + psw);
1108: }
1109: return psw;
1110: } else {
1111: int offset = mcinfo.findFreeStmt();
1112: if (offset >= 0) {
1113: // Remove that entry from the current pool
1114: PreparedStatementWrapper pw = (PreparedStatementWrapper) mcinfo.pStmts
1115: .remove(offset);
1116: pw.destroy();
1117: psw.setPreparedStatement(ps);
1118: mcinfo.pStmts.add(psw);
1119: if (isEnabledDebug) {
1120: trace.log(BasicLevel.DEBUG, "Replacing " + pw
1121: + " with " + psw);
1122: }
1123: return psw;
1124: } else {
1125: // No room for the Wrapped statement just return the PreparedStatement
1126: if (isEnabledDebug) {
1127: trace.log(BasicLevel.DEBUG, "No room in pool");
1128: }
1129: return ps;
1130: }
1131: }
1132: }
1133: }
1134:
1135: /**
1136: * Release the ManagedConnection object resource
1137: * @param rMc Object to release
1138: * @throws Exception if an Exception occurs
1139: */
1140: public void releaseResource(Object rMc) throws Exception {
1141:
1142: synchronized (poolMCs) {
1143:
1144: if (isEnabledDebug) {
1145: trace.log(BasicLevel.DEBUG, "MC: " + rMc);
1146: }
1147: if (rMc instanceof ManagedConnection) {
1148: ManagedConnection mc = (ManagedConnection) rMc;
1149: MCInfo mcinfo = (MCInfo) mc2mci.remove(mc);
1150: if (mcinfo != null) {
1151: destroyPStmts(mcinfo);
1152: }
1153: }
1154: }
1155: }
1156:
1157: /**
1158: * Destroying of the PreparedStatement objects of the Pool
1159: * @param mcinfo ManagedConnection information
1160: * @throws Exception Exception
1161: */
1162: public void destroyPStmts(MCInfo mcinfo) throws Exception {
1163: if (isEnabledDebug) {
1164: trace.log(BasicLevel.DEBUG, "MCInfo: " + mcinfo);
1165: }
1166: synchronized (mcinfo.pStmts) {
1167: if (mcinfo.pStmts.size() <= 0) {
1168: return;
1169: }
1170: int stmtSize = mcinfo.pStmts.size();
1171: try {
1172: for (int i = 0; i < stmtSize; i++) {
1173: PreparedStatementWrapper psw = (PreparedStatementWrapper) mcinfo.pStmts
1174: .remove(0);
1175: psw.closePstmt();
1176: }
1177: } catch (Exception ex) {
1178: throw ex;
1179: }
1180: }
1181: }
1182:
1183: /**
1184: * IMPLEMENTATION OF INTERFACE ConnectionEventListener *
1185: *
1186: * A ManagedConnection instance calls the connectionClosed method to notify
1187: * its registered set of listeners when an application component closes a
1188: * connection handle. The application server uses this connection close event
1189: * to make a decision on whether or not to put the ManagedConnection instance
1190: * back into the connection pool.
1191: *
1192: * @see javax.resource.spi.ConnectionEventListener
1193: */
1194: public void connectionClosed(ConnectionEvent event) {
1195:
1196: synchronized (poolMCs) {
1197:
1198: ManagedConnection mc = (ManagedConnection) event
1199: .getSource();
1200: if (mc == null) {
1201: trace.log(BasicLevel.ERROR, "no mc found in Event!");
1202: }
1203:
1204: MCInfo mci = (MCInfo) mc2mci.get(mc);
1205: if (mci == null) {
1206: trace.log(BasicLevel.ERROR, "no mci found!");
1207: return;
1208: }
1209:
1210: if (isEnabledDebug) {
1211: trace.log(BasicLevel.DEBUG, "enter\n" + getState("\t"));
1212: }
1213:
1214: mci.usedCs.remove(event.getConnectionHandle());
1215:
1216: if (mci.usedCs.isEmpty()) {
1217: if (isEnabledDebug) {
1218: trace.log(BasicLevel.DEBUG,
1219: "Last Connection has just been removed");
1220: }
1221:
1222: try {
1223: Transaction currentTx = null;
1224: if (tm != null) {
1225: currentTx = tm.getTransaction();
1226: }
1227:
1228: if (mci.localTransaction && currentTx == null) {
1229: trace
1230: .log(
1231: BasicLevel.ERROR,
1232: "The managed connection is being closed while a localtransaction is not finished");
1233: }
1234:
1235: if (currentTx != null) {
1236: mci.ctx = currentTx;
1237:
1238: if (mci.synchro == null) {
1239: try {
1240: currentTx
1241: .registerSynchronization(new MySynchro(
1242: this , mci));
1243: if (isEnabledDebug) {
1244: trace.log(BasicLevel.DEBUG,
1245: "registerSynchro mc="
1246: + mci.mc);
1247: }
1248: } catch (RollbackException e) {
1249: // The transaction has been marked as rollbackOnly
1250: // but the synchronization is registered.
1251: trace.log(BasicLevel.INFO,
1252: "registerSynchronization on transaction marked as Rollback only, mc="
1253: + mci.mc);
1254: }
1255: }
1256: } else if (mci.localTransaction) {
1257: if (isEnabledDebug) {
1258: trace
1259: .log(BasicLevel.DEBUG,
1260: "MC isn't released because local transaction is not finished");
1261: }
1262:
1263: } else {
1264: if (isEnabledDebug) {
1265: trace.log(BasicLevel.DEBUG, "no currentTx");
1266: }
1267:
1268: mcs.remove(mci);
1269:
1270: if (mci.ctx != null) {
1271: usedMCs.remove(mci.ctx);
1272: mci.ctx = null;
1273: }
1274:
1275: mci.mc.cleanup();
1276:
1277: // Free up the PreparedStatements
1278: // mci.stmtHash.clear();
1279:
1280: // Release the MC from its pool
1281: poolMCs.releaseResource(mci.mc, false, true);
1282:
1283: }
1284: if (mci.rmeCalled) {
1285: //Signal to the RessourceManagerEventListener mc is released
1286: mci.rme.isValid = false;
1287: rmel.connectionClosed(mci.rme);
1288: mci.rmeCalled = false;
1289: }
1290: } catch (Exception e) {
1291: trace
1292: .log(
1293: BasicLevel.ERROR,
1294: "an error during delisting of ManagedConection: ",
1295: e);
1296: }
1297: if (isEnabledDebug) {
1298: trace.log(BasicLevel.DEBUG, "exit\n"
1299: + getState("\t"));
1300: }
1301: }
1302: }
1303: }
1304:
1305: /**
1306: * The connectionErrorOccurred method indicates that the associated
1307: * ManagedConnection instance is now invalid and unusable. The application
1308: * server handles the connection error event notification by initiating
1309: * application server-specific cleanup (for example, removing
1310: * ManagedConnection instance from the connection pool) and then calling
1311: * ManagedConnection.destroy method to destroy the physical connection..
1312: *
1313: * @see javax.resource.spi.ConnectionEventListener
1314: */
1315: public void connectionErrorOccurred(ConnectionEvent event) {
1316:
1317: synchronized (poolMCs) {
1318:
1319: ManagedConnection mc = (ManagedConnection) event
1320: .getSource();
1321: if (mc == null) {
1322: trace.log(BasicLevel.ERROR, "no mc found in Event!");
1323: }
1324:
1325: MCInfo mci = (MCInfo) mc2mci.get(mc);
1326: if (mci == null) {
1327: trace.log(BasicLevel.ERROR, "no mci found!");
1328: return;
1329: }
1330:
1331: if (poolTrace.isLoggable(BasicLevel.DEBUG)) {
1332: poolTrace.log(BasicLevel.DEBUG, "enter\n"
1333: + getState("\t"));
1334: }
1335:
1336: mci.usedCs.clear();
1337:
1338: try {
1339: if (mci.rmeCalled) {
1340: //Signal to the RessourceManagerEventListener mc is released
1341: mci.rme.isValid = false;
1342: rmel.connectionErrorOccured(mci.rme);
1343: mci.rmeCalled = false;
1344: }
1345: // Detach the connectionManager from the mc
1346: mc.removeConnectionEventListener(this );
1347: // Remove the association (transaction ctx / mc)
1348: if (mci.ctx != null) {
1349: usedMCs.remove(mci.ctx);
1350: mci.ctx = null;
1351: } else {
1352: mcs.remove(mci);
1353: }
1354:
1355: if (isEnabledDebug) {
1356: trace.log(BasicLevel.DEBUG,
1357: "Destroying managed connection (" + mc
1358: + ")");
1359: }
1360: // Destroy the PreparedStatements
1361: destroyPStmts(mci);
1362:
1363: poolMCs.releaseResource(mc, true, false);
1364: if (poolTrace.isLoggable(BasicLevel.DEBUG)) {
1365: poolTrace.log(BasicLevel.DEBUG, "enter\n"
1366: + getState("\t"));
1367: }
1368:
1369: mc2mci.remove(mc);
1370:
1371: } catch (Exception e) {
1372: trace
1373: .log(BasicLevel.ERROR,
1374: "an error related during delisting of ManagedConection");
1375: }
1376: }
1377: }
1378:
1379: /**
1380: * Notifies that a Resource Manager Local Transaction was committed on the
1381: * ManagedConnection instance.
1382: *
1383: * @see javax.resource.spi.ConnectionEventListener
1384: */
1385: public void localTransactionCommitted(ConnectionEvent event) {
1386:
1387: synchronized (poolMCs) {
1388:
1389: ManagedConnection mc = (ManagedConnection) event
1390: .getSource();
1391: if (mc == null) {
1392: trace.log(BasicLevel.ERROR, "no mc found in Event!");
1393: }
1394:
1395: MCInfo mci = (MCInfo) mc2mci.get(mc);
1396: if (mci == null) {
1397: trace.log(BasicLevel.ERROR, "no mci found!");
1398: return;
1399: }
1400: mci.localTransaction = false;
1401:
1402: if (mci.usedCs.isEmpty()) {
1403: if (isEnabledDebug) {
1404: trace.log(BasicLevel.DEBUG,
1405: "Close the managed connection");
1406: }
1407:
1408: if (mci.rmeCalled) {
1409: //Signal to the RessourceManagerEventListener mc is released
1410: mci.rme.isValid = false;
1411: rmel.connectionClosed(mci.rme);
1412: mci.rmeCalled = false;
1413: }
1414:
1415: if (mci.synchro == null) {
1416: mcs.remove(mci);
1417: if (mci.ctx != null) {
1418: usedMCs.remove(mci.ctx);
1419: mci.ctx = null;
1420: }
1421:
1422: try {
1423: mci.mc.cleanup();
1424:
1425: // Release the MC from its pool
1426: poolMCs.releaseResource(mci.mc, false, true);
1427: } catch (Exception e) {
1428: trace
1429: .log(
1430: BasicLevel.ERROR,
1431: "an error related ManagedConection release",
1432: e, "ConnectionManagerImpl",
1433: "localTransactionCommitted");
1434: }
1435: }
1436: }
1437: }
1438:
1439: }
1440:
1441: /**
1442: * Notifies that a Resource Manager Local Transaction was rolled back on the
1443: * ManagedConnection instance.
1444: *
1445: * @see javax.resource.spi.ConnectionEventListener
1446: */
1447: public void localTransactionRolledback(ConnectionEvent event) {
1448:
1449: synchronized (poolMCs) {
1450:
1451: ManagedConnection mc = (ManagedConnection) event
1452: .getSource();
1453: if (mc == null) {
1454: trace.log(BasicLevel.ERROR, "no mc found in Event!");
1455: }
1456:
1457: MCInfo mci = (MCInfo) mc2mci.get(mc);
1458: if (mci == null) {
1459: trace.log(BasicLevel.ERROR, "no mci found!");
1460: return;
1461: }
1462: mci.localTransaction = false;
1463:
1464: if (mci.usedCs.isEmpty()) {
1465: if (isEnabledDebug) {
1466: trace.log(BasicLevel.DEBUG,
1467: "Close the managed connection");
1468: }
1469:
1470: if (mci.rmeCalled) {
1471: //Signal to the ResourceManagerEventListener mc is released
1472: mci.rme.isValid = false;
1473: rmel.connectionClosed(mci.rme);
1474: mci.rmeCalled = false;
1475: }
1476:
1477: if (mci.synchro == null) {
1478: mcs.remove(mci);
1479: if (mci.ctx != null) {
1480: usedMCs.remove(mci.ctx);
1481: mci.ctx = null;
1482: }
1483:
1484: try {
1485: mci.mc.cleanup();
1486:
1487: // Release the MC from its pool
1488: poolMCs.releaseResource(mci.mc, false, true);
1489: } catch (Exception e) {
1490: trace
1491: .log(
1492: BasicLevel.ERROR,
1493: "an error related during ManagedConection release:",
1494: e, "ConnectionManagerImpl",
1495: "localTransactionRolledback");
1496: }
1497: }
1498: }
1499: }
1500: }
1501:
1502: /**
1503: * Notifies that a Resource Manager Local Transaction was started on the
1504: * ManagedConnection instance.
1505: *
1506: * @see javax.resource.spi.ConnectionEventListener
1507: */
1508: public void localTransactionStarted(ConnectionEvent event) {
1509:
1510: synchronized (poolMCs) {
1511:
1512: ManagedConnection mc = (ManagedConnection) event
1513: .getSource();
1514: if (mc == null) {
1515: trace.log(BasicLevel.ERROR, "no mc found in Event!");
1516: }
1517:
1518: MCInfo mci = (MCInfo) mc2mci.get(mc);
1519: if (mci == null) {
1520: trace.log(BasicLevel.ERROR, "no mci found!");
1521: return;
1522: }
1523: mci.localTransaction = true;
1524:
1525: }
1526: }
1527:
1528: /**
1529: * Description of the Method
1530: *
1531: *@return Description of the Returned Value
1532: */
1533: public String toString() {
1534: String m = super .toString();
1535: // remove package name
1536: int c1 = 0;
1537: int current = m.indexOf(".");
1538: while (current != -1) {
1539: c1 = current;
1540: current = m.indexOf(".", current + 1);
1541: }
1542: return m.substring(c1 + 1, m.length());
1543: }
1544:
1545: /**
1546: * Gets the State attribute of the ConnectionManagerImpl object
1547: *
1548: *@param prefix Description of Parameter
1549: *@return The State value
1550: */
1551: protected String getState(String prefix) {
1552: String res = null;
1553: synchronized (poolMCs) {
1554: res = prefix + "mcf=" + mcf + "\n";
1555: res += prefix + "ResourceSpec=" + rs.toString() + "\n";
1556: res += prefix + "size of MC pool:" + poolMCs.getSize()
1557: + "\n";
1558: res += prefix + "size of usedMCs:" + usedMCs.size() + "\n";
1559: res += prefix + "mcs attached to a tx:\n";
1560: for (Enumeration en = usedMCs.keys(); en.hasMoreElements();) {
1561: Object tx = en.nextElement();
1562: MCInfo mci = (MCInfo) usedMCs.get(tx);
1563: res += prefix + "MCI : tx=" + tx + "\n";
1564: res += mci.getState(prefix + "\t");
1565: }
1566: res += prefix + "mcs not attached to a tx:\n";
1567: for (Enumeration en = mcs.elements(); en.hasMoreElements();) {
1568: MCInfo mci = (MCInfo) en.nextElement();
1569: res += mci.getState(prefix + "\t");
1570: }
1571: res += prefix + "mcs waiting for tx commit or rollback:\n";
1572: for (Enumeration en = synchros.elements(); en
1573: .hasMoreElements();) {
1574: MCInfo mci = (MCInfo) en.nextElement();
1575: res += mci.getState(prefix + "\t");
1576: }
1577: }
1578: return res;
1579: }
1580:
1581: /**
1582: * Set the XAName to use
1583: * @param xanm String of XA Name
1584: */
1585: public void setXAName(String xanm) {
1586: xaName = xanm;
1587: }
1588:
1589: /**
1590: * Get the XAName to use
1591: * @return String of XA Name
1592: */
1593: public String getXAName() {
1594: return (xaName);
1595: }
1596:
1597: /**
1598: * Register an XAResource with JOTM for recovery
1599: */
1600: public void registerXAResource(Properties tmProp) {
1601:
1602: synchronized (poolMCs) {
1603:
1604: // If no RM or the RAR doesn't support XA, then just return
1605: if (tm == null) {
1606: return;
1607: }
1608: if (!transSupport.equalsIgnoreCase(XA_TRANS_SUPPORT)) {
1609: return;
1610: }
1611:
1612: // Find an entry in free pool
1613: // If none, then create one
1614: MCInfo mci = null;
1615: XAResource xar = null;
1616: try {
1617: ManagedConnection mc = (ManagedConnection) poolMCs
1618: .getResource(rs);
1619: if (mc == null) {
1620: if (isEnabledDebug) {
1621: trace
1622: .log(BasicLevel.DEBUG,
1623: "Cannot allocate a ManagedConnection for registerXAResource");
1624: }
1625: return;
1626: }
1627:
1628: mci = (MCInfo) mc2mci.get(mc);
1629: if (mci == null) {
1630: mci = new MCInfo(mc);
1631: mc2mci.put(mc, mci);
1632: }
1633:
1634: xar = mc.getXAResource();
1635: if (isEnabledDebug) {
1636: trace.log(BasicLevel.DEBUG,
1637: "got a MC from the ra pool, mc=" + mci.mc
1638: + " xar=" + xar);
1639: }
1640:
1641: if (!mci.connectionEventListener) {
1642: mci.mc.addConnectionEventListener(this );
1643: mci.connectionEventListener = true;
1644: }
1645:
1646: mci.synchro = null;
1647:
1648: } catch (ResourceException re) {
1649: return;
1650: } catch (Exception e) {
1651: trace.log(BasicLevel.ERROR, e.getMessage(), e);
1652: return;
1653: }
1654:
1655: // Setup globals so it can be returned to the pool
1656: jotmMc = mci.mc;
1657: jotmXar = xar;
1658:
1659: // Call to register it
1660: try {
1661: if (isEnabledDebug) {
1662: trace.log(BasicLevel.DEBUG, "Registering name = "
1663: + xaName + " xar = " + jotmXar);
1664: }
1665: ((Current) tm).getTransactionRecovery()
1666: .registerResourceManager(xaName, jotmXar, "",
1667: tmProp, this );
1668: } catch (Exception ex) {
1669: trace.log(BasicLevel.ERROR, ex.getMessage(), ex);
1670: returnXAResource(xaName, jotmXar);
1671: }
1672: }
1673: }
1674:
1675: /**
1676: * Called from JOTM to free the XAResource and associated Managed Connection
1677: * when recovery is complete
1678: *
1679: * @param rmName The Resource Manager to be unregistered.
1680: * @param rmXares XAResource to be returned
1681: */
1682: public void returnXAResource(String rmName, XAResource rmXares) {
1683:
1684: synchronized (poolMCs) {
1685: // Get the associated MC
1686: // Clean it up and return it to the free pool
1687: if (isEnabledDebug) {
1688: trace.log(BasicLevel.DEBUG, "Removing name = " + xaName
1689: + " xar = " + jotmXar);
1690: }
1691: if (jotmXar == null) {
1692: return;
1693: }
1694: if (!rmXares.equals(jotmXar)) {
1695: trace.log(BasicLevel.ERROR, "XAResource of " + rmXares
1696: + " and " + jotmXar + " not equal!");
1697: return;
1698: }
1699:
1700: MCInfo mci = (MCInfo) mc2mci.get(jotmMc);
1701: if (mci == null) {
1702: trace.log(BasicLevel.ERROR, "no mci found for "
1703: + jotmMc);
1704: return;
1705: }
1706:
1707: try {
1708: mci.mc.cleanup();
1709:
1710: // Release the MC from its pool
1711: poolMCs.releaseResource(mci.mc, false, true);
1712: } catch (Exception ex) {
1713: trace.log(BasicLevel.ERROR, ex.getMessage(), ex);
1714: }
1715:
1716: jotmMc = null;
1717: jotmXar = null;
1718: }
1719: }
1720:
1721: // JSR 77 (JCAConnectionFactory methods)
1722:
1723: public Pool getPool() {
1724: return poolMCs;
1725: }
1726:
1727: public int getCheckLevel() {
1728: return jdbcConnLevel;
1729: }
1730:
1731: public void setCheckLevel(int level) {
1732: jdbcConnLevel = level;
1733: }
1734:
1735: public String getTestStatement() {
1736: return jdbcConnTestStmt;
1737: }
1738:
1739: public void setTestStatement(String stmt) {
1740: jdbcConnTestStmt = stmt;
1741: }
1742:
1743: public int getCurrentInTx() {
1744: return usedMCs.size();
1745: }
1746:
1747: /**
1748: * @return Returns the maxPstmtPoolSize.
1749: */
1750: public int getMaxPstmtPoolSize() {
1751: return maxPstmtPoolSize;
1752: }
1753:
1754: /**
1755: * @param maxPstmtPoolSize The maxPstmtPoolSize to set.
1756: */
1757: public void setMaxPstmtPoolSize(int maxPstmtPoolSize) {
1758: this.maxPstmtPoolSize = maxPstmtPoolSize;
1759: }
1760: }
|