Save This Page
Home » xapool-1.5.0-src » org.enhydra.jdbc » standard » [javadoc | source]
    1   /*
    2    * XAPool: Open Source XA JDBC Pool
    3    * Copyright (C) 2003 Objectweb.org
    4    * Initial Developer: Lutris Technologies Inc.
    5    * Contact: xapool-public@lists.debian-sf.objectweb.org
    6    *
    7    * This library is free software; you can redistribute it and/or
    8    * modify it under the terms of the GNU Lesser General Public
    9    * License as published by the Free Software Foundation; either
   10    * version 2.1 of the License, or any later version.
   11    *
   12    * This library is distributed in the hope that it will be useful,
   13    * but WITHOUT ANY WARRANTY; without even the implied warranty of
   14    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   15    * Lesser General Public License for more details.
   16    *
   17    * You should have received a copy of the GNU Lesser General Public
   18    * License along with this library; if not, write to the Free Software
   19    * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
   20    * USA
   21    */
   22   package org.enhydra.jdbc.standard;
   23   
   24   import java.sql.PreparedStatement;
   25   import java.sql.SQLException;
   26   import java.sql.Statement;
   27   import java.sql.CallableStatement;
   28   import java.util.Hashtable;
   29   import javax.transaction.Transaction;
   30   import javax.transaction.TransactionManager;
   31   import javax.transaction.RollbackException;
   32   import javax.transaction.SystemException;
   33   
   34   public class StandardXAConnectionHandle extends StandardConnectionHandle {
   35   
   36       boolean resetTxonResume =false;
   37   	boolean globalTransaction; // true if a global transaction is in effect
   38   	public TransactionManager transactionManager;
   39   	public Transaction tx;
   40   	public StandardXAConnection xacon;
   41   	public boolean thisAutoCommit = true;
   42   
   43   	/**
   44   	 * Constructor
   45   	 */
   46   	public StandardXAConnectionHandle(
   47   		StandardXAConnection pooledCon,
   48   		Hashtable preparedStatementCache,
   49   		int preparedStmtCacheSize,
   50   		TransactionManager tm) {
   51   		super(pooledCon, preparedStatementCache, preparedStmtCacheSize);
   52   		// setup StandardXAConnectionHandle
   53   		xacon = pooledCon;
   54   		transactionManager = tm;
   55   		log = pooledCon.dataSource.log;
   56   
   57   		// This will have set the Connection to the current Connection.
   58   		// However this might change if a global transaction gets selected.
   59   	}
   60   
   61   	public void setTransactionManager(TransactionManager tm) {
   62   		this.transactionManager = tm;
   63   	}
   64   
   65   	synchronized public void close() throws SQLException {
   66   		Transaction ttx = tx;
   67   		// note: ttx is used instead of tx because super.close(), call end()
   68   		// on StdXAConnection which call tx = null;
   69   		super.close();
   70   		log.debug("StandardXAConnectionHandle:close");
   71   		log.debug(
   72   			"StandardXAConnectionHandle:close globalTransaction='"
   73   				+ globalTransaction
   74   				+ "' con.getAutoCommit='"
   75   				+ con.getAutoCommit()
   76   				+ "' ttx='"
   77   				+ ttx
   78   				+ "'");
   79   
   80   		if ((!con.getAutoCommit()) && (ttx == null)) {
   81   			log.debug(
   82   				"StandardXAConnectionHandle:close rollback the connection");
   83   			con.rollback();
   84   			con.setAutoCommit(thisAutoCommit);
   85   		} else
   86   			log.debug("StandardXAConnectionHandle:close do nothing else");
   87   		isReallyUsed = false;
   88   		log.debug(
   89   			"StandardXAConnectionHandle:close AFTER globalTransaction='"
   90   				+ globalTransaction
   91   				+ "' con.getAutoCommit='"
   92   				+ con.getAutoCommit()
   93   				+ "' ttx='"
   94   				+ ttx
   95   				+ "'");
   96   	}
   97   
   98   	/**
   99   	 * Called by the StandardXADataSource when a global transaction
  100   	 * gets associated with this connection.
  101   	 */
  102   	void setGlobalTransaction(boolean setting) throws SQLException {
  103   		log.debug(
  104   			"StandardXAConnectionHandle:setGlobalTransaction gTransaction='"
  105   				+ setting
  106   				+ "'");
  107   		globalTransaction = setting; // set global flag
  108   		con = pooledCon.getPhysicalConnection(); // get the real connection
  109   		if (con == null)
  110   			log.warn(
  111   				"StandardXAConnectionHandle:setGlobalTransaction con is null before setupPreparedStatementCache");
  112   		else
  113   			log.debug(
  114   				"StandardXAConnectionHandle:setGlobalTransaction con is *NOT* null before setupPreparedStatementCache");
  115   		//setupPreparedStatementCache();
  116   		if(!isClosed())
  117   			super.setAutoCommit(!setting);
  118   		// commits must be done by transaction manager
  119   	}
  120   
  121   	public void setAutoCommit(boolean autoCommit) throws SQLException {
  122   		if (globalTransaction) // if taking part in a global transaction
  123   			throw new SQLException("StandardXAConnectionHandle:setAutoCommit This connection is part of a global transaction");
  124   		super.setAutoCommit(autoCommit);
  125   	}
  126   
  127   	public void commit() throws SQLException {
  128   		if (globalTransaction) // if taking part in a global transaction
  129   			throw new SQLException("StandardXAConnectionHandle:commit:This connection is part of a global transaction");
  130   		super.commit();
  131   		//tx = null;
  132   	}
  133   
  134   	public void rollback() throws SQLException {
  135   		if (globalTransaction) // if taking part in a global transaction
  136   			throw new SQLException("StandardXAConnectionHandle:rollback:This connection is part of a global transaction");
  137   		super.rollback();
  138   		//tx = null;
  139   	}
  140   
  141   	synchronized PreparedStatement checkPreparedCache(
  142   		String sql,
  143   		int type,
  144   		int concurrency,
  145   		int holdability,
  146   		Object lookupKey)
  147   		throws SQLException {
  148   		PreparedStatement ret = null; // the return value
  149   		// NOTE - We include the Connection in the lookup key. This has no
  150   		// effect here but is needed by StandardXAConnection where the the physical
  151   		// Connection used can vary over time depending on the global transaction.
  152   		if (preparedStatementCache != null) {
  153   			Object obj = preparedStatementCache.get(lookupKey);
  154   			// see if there's a PreparedStatement already
  155   			if (obj != null) { // if there is
  156   				log.debug(
  157   					"StandardXAConnectionHandle:checkPreparedCache object is found");
  158   				ret = (PreparedStatement) obj; // use as return value
  159   				try {
  160   					ret.clearParameters(); // make it look like new
  161   				} catch (SQLException e) {
  162   					// Bad statement, so we have to create a new one
  163   					ret = createPreparedStatement(sql, type, concurrency, holdability);
  164   					// create new prepared statement
  165   				}
  166   				preparedStatementCache.remove(lookupKey);
  167   				// make sure it cannot be re-used
  168   				inUse.put(lookupKey, ret);
  169   				// make sure it gets reused by later delegates
  170   			} else { // no PreparedStatement ready
  171   				log.debug(
  172   					"StandardXAConnectionHandle:checkPreparedCache object is *NOT* found");
  173   				ret = createPreparedStatement(sql, type, concurrency, holdability);
  174   				// create new prepared statement
  175   				inUse.put(lookupKey, ret);
  176   				// will get saved in prepared statement cache
  177   			}
  178   		} else {
  179   			log.debug(
  180   				"StandardXAConnectionHandle:checkPreparedCache object the cache is out");
  181   			ret = createPreparedStatement(sql, type, concurrency, holdability);
  182   			// create new prepared statement
  183   		}
  184   		// We don't actually give the application a real PreparedStatement. Instead
  185   		// they get a StandardPreparedStatement that delegates everything except
  186   		// PreparedStatement.close();
  187   		log.debug(
  188   			"StandardXAConnectionHandle:checkPreparedCache pstmt='"
  189   				+ ret.toString()
  190   				+ "'");
  191   		return ret;
  192   	}
  193   
  194   
  195   
  196   	synchronized PreparedStatement checkPreparedCache(
  197   		String sql,
  198   		int autogeneratedkeys,
  199   		Object lookupKey)
  200   		throws SQLException {
  201   		PreparedStatement ret = null; // the return value
  202   		// NOTE - We include the Connection in the lookup key. This has no
  203   		// effect here but is needed by StandardXAConnection where the the physical
  204   		// Connection used can vary over time depending on the global transaction.
  205   		if (preparedStatementCache != null) {
  206   			Object obj = preparedStatementCache.get(lookupKey);
  207   			// see if there's a PreparedStatement already
  208   			if (obj != null) { // if there is
  209   				log.debug(
  210   					"StandardXAConnectionHandle:checkPreparedCache object is found");
  211   				ret = (PreparedStatement) obj; // use as return value
  212   				try {
  213   					ret.clearParameters(); // make it look like new
  214   				} catch (SQLException e) {
  215   					// Bad statement, so we have to create a new one
  216   					ret = createPreparedStatement(sql, autogeneratedkeys);
  217   					// create new prepared statement
  218   				}
  219   				preparedStatementCache.remove(lookupKey);
  220   				// make sure it cannot be re-used
  221   				inUse.put(lookupKey, ret);
  222   				// make sure it gets reused by later delegates
  223   			} else { // no PreparedStatement ready
  224   				log.debug(
  225   					"StandardXAConnectionHandle:checkPreparedCache object is *NOT* found");
  226   				ret = createPreparedStatement(sql, autogeneratedkeys);
  227   				// create new prepared statement
  228   				inUse.put(lookupKey, ret);
  229   				// will get saved in prepared statement cache
  230   			}
  231   		} else {
  232   			log.debug(
  233   				"StandardXAConnectionHandle:checkPreparedCache object the cache is out");
  234   			ret = createPreparedStatement(sql, autogeneratedkeys);
  235   			// create new prepared statement
  236   		}
  237   		// We don't actually give the application a real PreparedStatement. Instead
  238   		// they get a StandardPreparedStatement that delegates everything except
  239   		// PreparedStatement.close();
  240   		log.debug(
  241   			"StandardXAConnectionHandle:checkPreparedCache pstmt='"
  242   				+ ret.toString()
  243   				+ "'");
  244   		return ret;
  245   	}
  246   
  247   
  248   
  249   	/**
  250   	 * Creates a PreparedStatement for the given SQL. If possible, the
  251   	 * statement is fetched from the cache.
  252   	 */
  253   	public PreparedStatement prepareStatement(String sql) throws SQLException {
  254   		return prepareStatement(sql, 0, 0, 0);
  255   	}
  256   
  257   	public PreparedStatement prepareStatement(
  258   		String sql,
  259   		int resultSetType,
  260   		int resultSetConcurrency)
  261   		throws SQLException {
  262   	    return prepareStatement(sql, resultSetType, resultSetConcurrency, 0);
  263   	}
  264   
  265   	/**
  266   	 * Creates a PreparedStatement for the given SQL, type and concurrency.
  267   	 * If possible, the statement is fetched from the cache.
  268   	 */
  269   	public PreparedStatement prepareStatement(
  270   		String sql,
  271   		int resultSetType,
  272   		int resultSetConcurrency,
  273   		int resultSetHoldability)
  274   		throws SQLException {
  275   		if (tx == null) {
  276   			log.debug("StandardXAConnectionHandle:prepareStatement tx==null");
  277   			try {
  278   				try {
  279   					Transaction ntx = this.getTransaction();
  280   					if (ntx != null) {
  281   						log.debug(
  282   							"StandardXAConnectionHandle:prepareStatement (found a transaction)");
  283   						tx = ntx;
  284   						xacon.thisAutoCommit = this.getAutoCommit();
  285   						if (this.getAutoCommit()) {
  286   							this.setAutoCommit(false);
  287   						}
  288   						try {
  289   							tx.enlistResource(xacon.getXAResource());
  290   							// enlist the xaResource in the transaction
  291   						} catch (RollbackException n) {
  292   							log.debug(
  293   								"StandardXAConnectionHandle:prepareStatemnet enlistResource exception : "
  294   									+ n.toString());
  295   						}
  296   					} else {
  297   						log.debug(
  298   							"StandardXAConnectionHandle:prepareStatement (no transaction found)");
  299   					}
  300   				} catch (SystemException n) {
  301   					n.printStackTrace();
  302   					throw new SQLException(
  303   						"StandardXAConnectionHandle:prepareStatement getTransaction exception: "
  304   							+ n.toString());
  305   				}
  306   			} catch (NullPointerException n) {
  307   				// current is null: we are not in EJBServer.
  308   				n.printStackTrace();
  309   				throw new SQLException("StandardXAConnectionHandle:prepareStatement should not be used outside an EJBServer");
  310   			}
  311   		} else
  312   			log.debug("StandardXAConnectionHandle:prepareStatement tx!=null");
  313   
  314   		// if you want to use a REAL PrepareStatement object, please
  315   		// uncomment the 2 following lines and comment the last ones.
  316   		//PreparedStatement ops = con.prepareStatement(sql, resultSetType, resultSetConcurrency);
  317   		//return ops;
  318   
  319   		isReallyUsed = true;
  320   		return new StandardXAPreparedStatement(
  321   			this,
  322   			sql,
  323   			resultSetType,
  324   			resultSetConcurrency,
  325   			resultSetHoldability);
  326   	}
  327   
  328           public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) 
  329   	    throws SQLException {
  330   	    if (tx == null) {
  331   		log.debug("StandardXAConnectionHandle:prepareStatement tx==null");
  332   		try {
  333   		    try {
  334   			Transaction ntx = this.getTransaction();
  335   			if (ntx != null) {
  336   			    log.debug(
  337   				      "StandardXAConnectionHandle:prepareStatement (found a transaction)");
  338   			    tx = ntx;
  339   			    xacon.thisAutoCommit = this.getAutoCommit();
  340   			    if (this.getAutoCommit()) {
  341   				this.setAutoCommit(false);
  342   			    }
  343   			    try {
  344   				tx.enlistResource(xacon.getXAResource());
  345   				// enlist the xaResource in the transaction
  346   			    } catch (RollbackException n) {
  347   				log.debug(
  348   					  "StandardXAConnectionHandle:prepareStatemnet enlistResource exception : "
  349   					  + n.toString());
  350   			    }
  351   			} else {
  352   			    log.debug(
  353   				      "StandardXAConnectionHandle:prepareStatement (no transaction found)");
  354   			}
  355   		    } catch (SystemException n) {
  356   			n.printStackTrace();
  357   			throw new SQLException(
  358   					       "StandardXAConnectionHandle:prepareStatement getTransaction exception: "
  359   					       + n.toString());
  360   		    }
  361   		} catch (NullPointerException n) {
  362   		    // current is null: we are not in EJBServer.
  363   		    n.printStackTrace();
  364   		    throw new SQLException("StandardXAConnectionHandle:prepareStatement should not be used outside an EJBServer");
  365   		}
  366   	    } else
  367   		log.debug("StandardXAConnectionHandle:prepareStatement tx!=null");
  368   	    
  369   	    isReallyUsed = true;
  370   	    return new StandardXAPreparedStatement(
  371   						   this,
  372   						   sql,
  373   						   autoGeneratedKeys);
  374   	}
  375       
  376          /**
  377   	* not yet implemented
  378   	*/
  379           public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
  380   	    throw new UnsupportedOperationException();
  381   	}
  382   
  383          /**
  384   	* not yet implemented
  385   	*/
  386           public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
  387   	    throw new UnsupportedOperationException();
  388   	}
  389   
  390   
  391   	/**
  392   	 * Creates a CallableStatement for the given SQL, result set type and concurency
  393   	 */
  394   	public CallableStatement prepareCall(
  395   		String sql,
  396   		int resultSetType,
  397   		int resultSetConcurrency)
  398   		throws SQLException {
  399   		return new StandardXACallableStatement(
  400   			this,
  401   			sql,
  402   			resultSetType,
  403   			resultSetConcurrency, 0);
  404   	}
  405   
  406   	/**
  407   	 * Creates a CallableStatement for the given SQL
  408   	 */
  409   	public CallableStatement prepareCall(String sql) throws SQLException {
  410   		return new StandardXACallableStatement(this, sql, 0, 0, 0);
  411   	}
  412   
  413           public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) 
  414   		throws SQLException {
  415   		return new StandardXACallableStatement(
  416   			this,
  417   			sql,
  418   			resultSetType,
  419   			resultSetConcurrency,
  420   			resultSetHoldability);
  421   	}
  422   
  423   
  424   	public Statement createStatement() throws SQLException {
  425   	    return createStatement(0,0,0);
  426   	}
  427   
  428   	public Statement createStatement(
  429   		int resultSetType,
  430   		int resultSetConcurrency)
  431   		throws SQLException {
  432   	    return createStatement(resultSetType, resultSetConcurrency, 0);
  433   	}
  434   
  435   	public Statement createStatement(
  436   		int resultSetType,
  437   		int resultSetConcurrency,
  438   		int resultSetHoldability)
  439   		throws SQLException {
  440   
  441   		if (tx == null) {
  442   			log.debug("StandardXAConnectionHandle:createStatement tx==null");
  443   			try {
  444   				try {
  445   					Transaction ntx = this.getTransaction();
  446   					if (ntx != null) {
  447   						log.debug(
  448   							"StandardXAConnectionHandle:createStatement (found a transaction)");
  449   						tx = ntx;
  450   						xacon.thisAutoCommit = this.getAutoCommit();
  451   						if (this.getAutoCommit()) {
  452   							this.setAutoCommit(false);
  453   						}
  454   						try {
  455   							tx.enlistResource(xacon.getXAResource());
  456   							// enlist the xaResource in the transaction
  457   						} catch (RollbackException n) {
  458   							log.debug(
  459   								"StandardXAConnectionHandle:createStatement enlistResource exception: "
  460   									+ n.toString());
  461   						}
  462   					} else {
  463   						log.debug(
  464   							"StandardXAConnectionHandle:createStatement (no transaction found)");
  465   					}
  466   
  467   				} catch (SystemException n) {
  468   					throw new SQLException(
  469   						"StandardXAConnectionHandle:createStatement getTransaction exception: "
  470   							+ n.toString());
  471   				}
  472   			} catch (NullPointerException n) {
  473   				// current is null: we are not in EJBServer.
  474   				throw new SQLException(
  475   					"StandardXAConnectionHandle:createStatement should not be used outside an EJBServer: "
  476   						+ n.toString());
  477   			}
  478   		}
  479   		isReallyUsed = true;
  480   		return new StandardXAStatement(this, resultSetType, resultSetConcurrency, resultSetHoldability);
  481   	}
  482   
  483   	private Transaction getTransaction() throws SystemException {
  484   		Transaction ntx = null;
  485   		if (transactionManager != null) {
  486   			ntx = transactionManager.getTransaction();
  487   		} else {
  488   			log.debug(
  489   				"StandardXAConnectionHandle:getTransaction (null transaction manager)");
  490   		}
  491   
  492   		return ntx;
  493   	}
  494   	
  495   	public String toString() {
  496   		StringBuffer sb = new StringBuffer();
  497   		sb.append("StandardXAConnectionHandle:\n");
  498   		sb.append("     global transaction =<"+this.globalTransaction+ ">\n");
  499   		sb.append("     is really used =<"+this.isReallyUsed+ ">\n");
  500   		sb.append("     this autoCommit =<"+this.thisAutoCommit+ ">\n");
  501   		sb.append("     in use size =<"+this.inUse.size()+ ">\n");
  502   		sb.append("     master prepared stmt cache size =<"+this.masterPrepStmtCache.size()+ ">\n");
  503   		sb.append("     transaction =<"+this.tx+ ">\n");
  504   		sb.append("     connection =<"+this.con.toString()+ ">\n");		
  505   		
  506   		return sb.toString();
  507   	}
  508   }

Save This Page
Home » xapool-1.5.0-src » org.enhydra.jdbc » standard » [javadoc | source]