ConnectionManager.java

00001 
00027 package org.objectweb.jonas.dbm;
00028 
00029 import java.io.Serializable;
00030 import java.sql.Connection;
00031 import java.sql.SQLException;
00032 import java.util.HashMap;
00033 import java.util.Map;
00034 
00035 import javax.naming.NamingException;
00036 import javax.naming.Reference;
00037 import javax.naming.Referenceable;
00038 import javax.naming.StringRefAddr;
00039 import javax.sql.ConnectionEvent;
00040 import javax.sql.ConnectionEventListener;
00041 import javax.sql.DataSource;
00042 import javax.sql.XAConnection;
00043 import javax.transaction.RollbackException;
00044 import javax.transaction.SystemException;
00045 import javax.transaction.Transaction;
00046 import javax.transaction.xa.XAResource;
00047 
00048 import org.objectweb.jonas.common.Log;
00049 import org.objectweb.jonas.jdbc_xa.XADataSourceImpl;
00050 import org.objectweb.jonas.jtm.TransactionService;
00051 import org.objectweb.jonas.service.ServiceManager;
00052 import org.objectweb.transaction.jta.ResourceManagerEventListener;
00053 import org.objectweb.transaction.jta.TransactionManager;
00054 import org.objectweb.util.monolog.api.BasicLevel;
00055 import org.objectweb.util.monolog.api.Logger;
00056 
00086 public class ConnectionManager
00087     implements DataSource,
00088                Referenceable,
00089                Serializable,
00090                ConnectionEventListener {
00091 
00092     private static Logger logger = null;
00093 
00094     // The static table of all the ConnectionManager objects
00095     // Each ResourceManager has its own ConnectionManager (i.e. DataSource)
00096     private static Map cmList = new HashMap();
00097 
00102     private TransactionManager tm = null;
00103 
00108     private XADataSourceImpl xads = null;
00109 
00114     private Pool pool = null;
00115 
00119     public Pool getPool() {
00120         return pool;
00121     }
00122 
00123     // ----------------------------------------------------------
00124     // properties
00125     // ----------------------------------------------------------
00126 
00130     private String dSName = null;
00131 
00135     private String datasourceName;
00136 
00140     private String url = null;
00144     private String className = null;
00148     private String userName = null;
00152     private String password = null;
00153 
00157     private int isolationLevel = -1;
00158     private String isolationStr = null;
00159 
00163     private String currentMapperName = null;
00164 
00169     private boolean isClient = false;
00170 
00174     private String xaName = null;
00175     private String dsDescription = null;
00176 
00177     private static ResourceManagerEventListener rmListener = null;
00178 
00179     // -----------------------------------------------------------------
00180     // Constructors
00181     // -----------------------------------------------------------------
00182 
00186     public ConnectionManager() throws Exception {
00187         logger = Log.getLogger(Log.JONAS_DBM_PREFIX);
00188 
00189         // Set the TransactionManager
00190         try {
00191             // Modified for use with the gcj compiler
00192             ServiceManager sm = ServiceManager.getInstance();
00193             TransactionService ts = (TransactionService) sm.getTransactionService();
00194             tm = ts.getTransactionManager();
00195         } catch (Exception e) {
00196             throw e;
00197         }
00198 
00199         // set the Transaction Manager as being the listener for this RM
00200         setRMEListener(tm);       
00201 
00202         // Create the underlaying JDBC-XA driver
00203         // We do not use JNDI here. (should we do ?)
00204         // AD : do this before the Pool creation in order to allow the Pool constructor to access xads
00205         xads = new XADataSourceImpl();
00206         pool = new Pool(this, xads);
00207     }
00208 
00214     public ConnectionManager(boolean isClient) throws Exception { 
00215         logger = Log.getLogger(Log.JONAS_DBM_PREFIX);
00216         this.isClient = isClient;
00217         xads = new XADataSourceImpl();
00218     }
00219 
00225     public boolean isClientCase() {
00226         return isClient;
00227     }
00228 
00229     // -----------------------------------------------------------------
00230     // Properties
00231     // -----------------------------------------------------------------
00232 
00233     public void setRMEListener(ResourceManagerEventListener rmel) {
00234         rmListener = rmel;
00235     }
00236 
00240     public String getDSName() {
00241         return dSName;
00242     }
00243 
00247     public void setDSName(String s) {
00248         dSName = s;
00249         xads.setDataSourceName(s); // for getRMID!
00250         // Add it to the list
00251         cmList.put(s, this);
00252     }
00253 
00254     public String getUrl() {
00255         return url;
00256     }
00257     public void setUrl(String s) {
00258         url = s;
00259         // Forward it to JDBC-XA driver
00260         xads.setUrl(s);
00261     }
00262 
00263     public String getClassName() {
00264         return className;
00265     }
00266     public void setClassName(String s) throws ClassNotFoundException {
00267         className = s;
00268         // Forward it to JDBC-XA driver
00269         xads.setClassName(s);
00270     }
00271 
00272     public String getUserName() {
00273         return userName;
00274     }
00275     public void setUserName(String s) {
00276         userName = s;
00277         // Forward it to JDBC-XA driver
00278         xads.setUserName(s);
00279     }
00280 
00281     public String getPassword() {
00282         return password;
00283     }
00284     public void setPassword(String s) {
00285         password = s;
00286         // Forward it to JDBC-XA driver
00287         xads.setPassword(s);
00288     }
00289 
00290     public void setTransactionIsolation(String level) {
00291         logger.log(BasicLevel.DEBUG, level);
00292         if (level.equals("serializable")) {
00293             isolationLevel = Connection.TRANSACTION_SERIALIZABLE;
00294         } else if (level.equals("none")) {
00295             isolationLevel = Connection.TRANSACTION_NONE;
00296         } else if (level.equals("read_committed")) {
00297             isolationLevel = Connection.TRANSACTION_READ_COMMITTED;
00298         } else if (level.equals("read_uncommitted")) {
00299             isolationLevel = Connection.TRANSACTION_READ_UNCOMMITTED;
00300         } else if (level.equals("repeatable_read")) {
00301             isolationLevel = Connection.TRANSACTION_REPEATABLE_READ;
00302         } else {
00303             isolationStr = "default";
00304             return;
00305         }
00306         // Forward it to JDBC-XA driver
00307         isolationStr = level;
00308         xads.setTransactionIsolation(isolationLevel);
00309     }
00310 
00311     public String getTransactionIsolation() {
00312         logger.log(BasicLevel.DEBUG, isolationStr);
00313         return isolationStr;
00314     }
00315 
00316     public void setMapperName(String mappername) {
00317         currentMapperName = mappername;
00318     }
00319 
00320     public String getMapperName() {
00321         return currentMapperName;
00322     }
00323 
00338     public void poolConfigure(String connchecklevel,
00339                               String connmaxage,
00340                               String maxopentime,
00341                               String connteststmt,
00342                               String minconpool,
00343                               String maxconpool,
00344                               String maxwaittime,
00345                               String maxwaiters,
00346                               String samplingperiod) {
00347 
00348         // Configure pool
00349         pool.setCheckLevel((new Integer(connchecklevel)).intValue());
00350         // set con max age BEFORE min/max pool size.
00351         pool.setMaxAge((new Integer(connmaxage)).intValue());
00352         pool.setMaxOpenTime((new Integer(maxopentime)).intValue());
00353         pool.setTestStatement(connteststmt);
00354         pool.setPoolMin((new Integer(minconpool)).intValue());
00355         pool.setPoolMax((new Integer(maxconpool)).intValue());
00356         pool.setMaxWaitTime((new Integer(maxwaittime)).intValue());
00357         pool.setMaxWaiters((new Integer(maxwaiters)).intValue());
00358         pool.setSamplingPeriod((new Integer(samplingperiod)).intValue());
00359         if (logger.isLoggable(BasicLevel.DEBUG)) {
00360             logger.log(BasicLevel.DEBUG, "ConnectionManager configured with:");
00361             logger.log(BasicLevel.DEBUG, "   jdbcConnCheckLevel  = " + connchecklevel);
00362             logger.log(BasicLevel.DEBUG, "   jdbcConnMaxAge      = " + connmaxage);
00363             logger.log(BasicLevel.DEBUG, "   jdbcMaxOpenTime     = " + maxopentime);
00364             logger.log(BasicLevel.DEBUG, "   jdbcTestStmt        = " + connteststmt);
00365             logger.log(BasicLevel.DEBUG, "   minConPool          = " + pool.getPoolMin());
00366             logger.log(BasicLevel.DEBUG, "   maxConPool          = " + pool.getPoolMax());
00367             logger.log(BasicLevel.DEBUG, "   maxWaitTime         = " + pool.getMaxWaitTime());
00368             logger.log(BasicLevel.DEBUG, "   maxWaiters          = " + pool.getMaxWaiters());
00369             logger.log(BasicLevel.DEBUG, "   samplingPeriod      = " + pool.getSamplingPeriod());
00370         }
00371     }
00372 
00373     // -----------------------------------------------------------------
00374     // DataSource implementation
00375     // -----------------------------------------------------------------
00376 
00384     public Connection getConnection() throws SQLException {
00385         return getConnection(userName, password);
00386     }
00387 
00398     public Connection getConnection(String username, String password) throws SQLException {
00399         XAConnection xac = null;
00400         Transaction tx = null;
00401         try {
00402             tx = tm.getTransaction();
00403         } catch (NullPointerException n) {
00404             // current is null: we are not in a JOnAS Server.
00405             logger.log(BasicLevel.ERROR, "ConnectionManager: should not be used outside a JOnAS Server");
00406         } catch (SystemException e) {
00407             logger.log(BasicLevel.ERROR, "ConnectionManager: getTransaction failed:" + e);
00408         }
00409         if (logger.isLoggable(BasicLevel.DEBUG)) {
00410             logger.log(BasicLevel.DEBUG, "Tx = " + tx);
00411         }
00412 
00413         // Check if available XAConnection in the pool for this user
00414         PoolItem pi = pool.openConnection(username, (Transaction) tx);
00415         // get the xac associated to the new PoolItem
00416         xac = pi.getXACon();
00417 
00418         Connection ret = xac.getConnection();
00419         // Enlist XAResource if we are actually in a transaction
00420         if (tx != null) {
00421             if (pi.getOpenCount() == 1) { // Only if first/only thread
00422                 try {
00423                     if (logger.isLoggable(BasicLevel.DEBUG)) {
00424                         logger.log(BasicLevel.DEBUG, "enlist XAResource on " + tx);
00425                     }
00426                     tx.enlistResource(xac.getXAResource());
00427                     // We are inside a transaction: no autocommit!
00428                     ret.setAutoCommit(false);
00429                 } catch (RollbackException e) {
00430                     // Although tx has been marked to be rolled back,
00431                     // XAResource has been correctly enlisted.
00432                     logger.log(BasicLevel.WARN, "XAResource enlisted, but tx is marked rollback");
00433                 } catch (IllegalStateException e) {
00434                     // In case tx is committed, no need to register resource!
00435                     ret.setAutoCommit(true);
00436                 } catch (Exception e) {
00437                     logger.log(BasicLevel.ERROR, "Cannot enlist XAResource:" + e);
00438                     logger.log(BasicLevel.ERROR, "Connection will not be enlisted in a transaction");
00439                     // should return connection in the pool XXX
00440                     throw new SQLException("Cannot enlist XAResource");
00441                 }
00442             }
00443         } else {
00444             ret.setAutoCommit(true);    // in case we do not start a Tx
00445         }
00446         // We are not in a transaction yet: we just make a pre-registration.
00447         // We are in a stateful bean, put it in the list too.
00448         if (!pi.isRME()) {
00449             logger.log(BasicLevel.DEBUG, "register this connection to the TM.");
00450             pi.setRME(true);
00451             rmListener.connectionOpened(pi);
00452         }
00453         // return a Connection object
00454         return ret;
00455     }
00456 
00473     public java.io.PrintWriter getLogWriter() throws SQLException {
00474         return xads.getLogWriter();
00475     }
00476 
00477 
00494     public void setLogWriter(java.io.PrintWriter out) throws SQLException {
00495         xads.setLogWriter(out);
00496     }
00497 
00498 
00511     public void setLoginTimeout(int seconds) throws SQLException {
00512         xads.setLoginTimeout(seconds);
00513     }
00514 
00526     public int getLoginTimeout() throws SQLException {
00527         return xads.getLoginTimeout();
00528     }
00529 
00530     // -----------------------------------------------------------------
00531     // ConnectionEventListener implementation
00532     // -----------------------------------------------------------------
00533 
00539     public void connectionClosed(ConnectionEvent event) {
00540         logger.log(BasicLevel.DEBUG, " ");
00541 
00542         XAConnection xac = (XAConnection) event.getSource();
00543         PoolItem pi = pool.closeConnection(xac, XAResource.TMSUCCESS);
00544 
00545         // remove it from the list of open connections for this thread
00546         // only if it was opened outside a tx.
00547         if (pi != null && pi.isRME()) {
00548             logger.log(BasicLevel.DEBUG, "unregister this connection to the TM.");
00549             pi.setRME(false);
00550             rmListener.connectionClosed(pi);
00551         }
00552     }
00553 
00559     public void connectionErrorOccurred(ConnectionEvent event) {
00560         logger.log(BasicLevel.DEBUG, "");
00561 
00562         XAConnection xac = (XAConnection) event.getSource();
00563         PoolItem pi = pool.closeConnection(xac, XAResource.TMFAIL);
00564 
00565         // remove it from the list of open connections for this thread
00566         // only if it was opened outside a tx.
00567         if (pi != null && pi.isRME()) {
00568             logger.log(BasicLevel.DEBUG, "unregister this connection to the TM.");
00569             pi.setRME(false);
00570             rmListener.connectionErrorOccured(pi);
00571         }
00572     }
00573 
00574     // -----------------------------------------------------------------
00575     // Referenceable implementation
00576     // -----------------------------------------------------------------
00577 
00586     public Reference getReference() throws NamingException {
00587 
00588         Reference ref = new Reference (this.getClass().getName(), 
00589                                        "org.objectweb.jonas.dbm.DataSourceFactory",
00590                                        null);
00591         // These values are used by ObjectFactory (see DataSourceFactory.java)
00592         ref.add(new StringRefAddr("datasource.name", getDSName()));
00593         ref.add(new StringRefAddr("datasource.url", getUrl()));
00594         ref.add(new StringRefAddr("datasource.classname", getClassName()));
00595         ref.add(new StringRefAddr("datasource.username", getUserName()));
00596         ref.add(new StringRefAddr("datasource.password", getPassword()));
00597         ref.add(new StringRefAddr("datasource.isolationlevel", getTransactionIsolation()));
00598         ref.add(new StringRefAddr("datasource.mapper", getMapperName()));
00599         Integer checklevel = new Integer(pool.getCheckLevel());
00600         ref.add(new StringRefAddr("connchecklevel", checklevel.toString()));
00601         Integer maxage = new Integer(pool.getMaxAge());
00602         ref.add(new StringRefAddr("connmaxage", maxage.toString()));
00603         Integer maxopentime = new Integer(pool.getMaxOpenTime());
00604         ref.add(new StringRefAddr("maxopentime", maxopentime.toString()));
00605         ref.add(new StringRefAddr("connteststmt", pool.getTestStatement()));
00606         Integer minpool = new Integer(pool.getPoolMin());
00607         ref.add(new StringRefAddr("minconpool", minpool.toString()));
00608         Integer maxpool = new Integer(pool.getPoolMax());
00609         ref.add(new StringRefAddr("maxconpool", maxpool.toString()));
00610         Integer maxwaittime = new Integer(pool.getMaxWaitTime());
00611         ref.add(new StringRefAddr("maxwaittime", maxwaittime.toString()));
00612         Integer maxwaiters = new Integer(pool.getMaxWaiters());
00613         ref.add(new StringRefAddr("maxwaiters", maxwaiters.toString()));
00614         Integer samplingperiod = new Integer(pool.getSamplingPeriod());
00615         ref.add(new StringRefAddr("samplingperiod", samplingperiod.toString()));
00616         return ref;
00617     }
00618 
00622     public static ConnectionManager getConnectionManager(String dsname) {
00623        
00624         ConnectionManager cm = (ConnectionManager) cmList.get(dsname);
00625         return cm;
00626     }
00627 
00628     public void closeAllConnection() {
00629         logger.log(BasicLevel.DEBUG, "");
00630         pool.closeAllConnections();
00631     }
00632 
00633     public static ResourceManagerEventListener getResourceManagerEventListener() {
00634         return rmListener;
00635     }
00636 
00640     public String getDatasourceName() {
00641         return datasourceName;
00642     }
00643 
00647     public void setDatasourceName(String s) {
00648         datasourceName = s;
00649     }
00650 
00654     public String getDataSourceDescription() {
00655         return dsDescription;
00656     }
00657 
00661     public void setDataSourceDescription(String dsDesc) {
00662         dsDescription = dsDesc;
00663     }
00668     public Integer getCurrentOpened() {
00669         return new Integer(pool.getCurrentOpened());
00670     }
00671 }

Generated on Tue Feb 15 15:05:15 2005 for JOnAS by  doxygen 1.3.9.1