[cvs] expresso/expresso-web/WEB-INF/src/com/jcorporate/expresso/core/db DBTransaction.java

JCorporate Ltd jcorp at jcorp2.servlets.net
Fri Sep 17 17:03:03 PDT 2004


Update of /home/javacorp/.cvs/expresso/expresso/expresso-web/WEB-INF/src/com/jcorporate/expresso/core/db
In directory jcorp2.servlets.net:/tmp/cvs-serv11927

Added Files:
	DBTransaction.java 
Log Message:
Yves Henri AMAIZO's contributions.
Commited by Raul Davidovich on 20040918


--- NEW FILE: DBTransaction.java ---
/* ====================================================================
 * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
 *
 * Copyright (c) 1995-2002 Jcorporate Ltd. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by Jcorporate Ltd.
 *        (http://www.jcorporate.com/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. "Jcorporate" and product names such as "Expresso" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written permission,
 *    please contact info at jcorporate.com.
 *
 * 5. Products derived from this software may not be called "Expresso",
 *    or other Jcorporate product names; nor may "Expresso" or other
 *    Jcorporate product names appear in their name, without prior
 *    written permission of Jcorporate Ltd.
 *
 * 6. No product derived from this software may compete in the same
 *    market space, i.e. framework, without prior written permission
 *    of Jcorporate Ltd. For written permission, please contact
 *    partners at jcorporate.com.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Jcorporate Ltd. Contributions back
 * to the project(s) are encouraged when you make modifications.
 * Please send them to support at jcorporate.com. For more information
 * on Jcorporate Ltd. and its products, please see
 * <http://www.jcorporate.com/>.
 *
 * Portions of this software are based upon other open source
 * products and are subject to their respective licenses.
 */

package com.jcorporate.expresso.core.db;

import com.jcorporate.expresso.core.db.DBConnection;
import com.jcorporate.expresso.core.db.DBConnectionPool;
import com.jcorporate.expresso.core.db.DBException;
import com.jcorporate.expresso.core.misc.StringUtil;
import com.jcorporate.expresso.kernel.util.ClassLocator;
import org.apache.log4j.Logger;

import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Vector;


/**
 * Generic database transaction object - hides the implementation
 * details of using jdbc and allows for JDBC message and exceptions to be
 * handled better than by default.
 * DBTransaction are also designed to be used in conjunction with connection
 * pooling, and have special methods to support this.
 *
 * @version        $Revision: 1.1 $  $Date: 2004/09/18 00:03:01 $
 * @author        Yves Henri AMAIZO
 */
public class DBTransaction {

    /** Constant name for the 'Default' database context */
    public static final String DEFAULT_DB_CONTEXT_NAME = "default";

    /** Every connection handled by the pool gets an ID number assigned */
    private int transactionId = 0;

    /** last operation */
    private int lastCommited = 0;

    /** Description of this connection */
    private String myDescription = "no description";

	/**
	 * The current data context
	 */
	private String dbName = DEFAULT_DB_CONTEXT_NAME;

    /** Is this connection object actually connected to the database yet? */
    private boolean isConnected = false;

	/** DB connection pool object */
	private DBConnectionPool myPool;

    /** DB connection object */
    private DBConnection myConnection;

    /** constant name to help with debugging */
    private static final String THIS_CLASS = DBTransaction.class.getName() + ".";

    /**
     * Time that the DBConnection was created.
     */
    private long createdTime = System.currentTimeMillis();

    /**
     * The main Transaction Log
     */
    private static Logger transLog = Logger.getLogger("com.jcorporate.expresso.core.db.TRANSACTION");

    /**
     * The SQL Log  Set this category to debug
     * to see a trace of all sql statements
     * issued against the main database
     */
    private static Logger log = Logger.getLogger(DBTransaction.class);

	/**
	 * Constructor
	 * Create a new connection object
	 *
	 * @param    pool    The identified transaction pool
	 *                        connection
	 * @throws    DBException If the information provided cannot be used to
	 *                        create a new connection
	 */
	public DBTransaction() throws DBException {
		transactionSetup(DEFAULT_DB_CONTEXT_NAME);
	}


    /**
     * Constructor
     * Create a new connection object
     *
     * @param    pool    The identified transaction pool
     *                        connection
     * @throws    DBException If the information provided cannot be used to
     *                        create a new connection
     */
    public DBTransaction(DBConnectionPool pool) throws DBException {
    	myPool = pool;
    	dbName = myPool.getDataContext();
    }


    /**
     * Constructor
     * Create a new connection object
     *
     * @param    transactionDataContext    The transaction data context
     *                        connection
     * @throws    DBException If the information provided cannot be used to
     *                        create a new connection
     */
    public DBTransaction(String transactionDataContext) throws DBException {
		transactionSetup(transactionDataContext);
    }


    /**
     * Sets up the transaction operation on an identitied DBConnectionPool 
     * @param transactionDataContext The transaction data context name
     * for more information on what this paramter means.
     * @throws DBException
     */
    private void transactionSetup(String transactionDataContext) throws DBException {
		String myName = (THIS_CLASS + "transactionSetup()");
		try {
			myPool = DBConnectionPool.getInstance(transactionDataContext);
			dbName = transactionDataContext;
		} catch (DBException e) {
			myPool = null;
			log.error(myName + "DBException : initialize pool for transaction failed!", e);
		}
    } /* transactionSetup(String) */


	/**
	 * Sets up the transaction operation on an identitied DBConnectionPool 
	 * @param transactionDataContext The transaction data context name
	 * for more information on what this paramter means.
	 * @throws DBException
	 */
	public  void startTransaction() throws DBException {
		startTransaction(true);
	}
	
	/**
	 * Sets up the transaction operation on an identitied DBConnectionPool 
	 * @param transactionDataContext The transaction data context name
	 * for more information on what this paramter means.
	 * @throws DBException
	 */
	public  void startTransaction(boolean immortal) throws DBException {
		String myName = (THIS_CLASS + "startTransaction()");

		try {
			if (!isConnected) {
				if (myPool != null) {
					myConnection = myPool.getConnection(getDataContext());
					myConnection.setImmortal(immortal);
					myConnection.setAutoCommit(false);
					isConnected = true;
					setId (myConnection.getId());
					lastCommited = 0;
				} else return;
			}
			lastCommited++;
			if (transLog.isDebugEnabled()) {
				transLog.debug(myName + " Transaction " + myConnection.getId() + " Starting:'" + 
						"' on db '" + getDataContext() + "'");
			}
		  } catch (DBException e) {
				log.error(myName + "DBException : initialize transaction failed!", e);
			if (myConnection != null)
			  close();
			}
	} /* transactionSetup(String) */

    /**
     * Clear all result sets and statements associated with this connection
     *
     * @throws DBException
     */
    public void clear() throws DBException {
    	if (myConnection != null) {    		
			rollback();
    	}
    } /* clear() */


    /**
     * Send a COMMIT to the database, closing the current transaction  If the
     * database driver claims it doesn't support transactions, then we skip
     * this.
     *
     * @throws    DBException If the commit does not succeed
     */
    public void commit() throws DBException {
		String myName = (THIS_CLASS + "commit()");
      try {
//      	  if (lastCommited == 1) {
			if (!myConnection.isClosed()) {
				myConnection.commit();
				if (log.isDebugEnabled()) {
					log.debug(myName + " Transaction " + myConnection.getId() + " Commited:'" + 
							"' on db '" + getDataContext() + "'");
				}
				close();
			}
//      	  } else {
//      	  	lastCommited--;
//      	  }
          
        } catch (DBException se) {
			close();
            throw new DBException(myName + ":Could not commit  (" +
                   myDescription + ")", se.getMessage());
	      }
    } /* commit() */

	/**
	 * Clear all result sets and statements associated with this connection
	 *
	 * @throws DBException
	 */
	private  void close() throws DBException {
		String myName = (THIS_CLASS + "close()");
		myConnection.setImmortal(false);
		if (log.isDebugEnabled()) {
			log.debug(myName + " Transaction " + myConnection.getId() + " Closed:'" + 
						"' on db '" + getDataContext() + "'");
			}
		myPool.release(myConnection);
		myConnection = null;
		myPool = null;
		setId (0);
		dbName = "";
		isConnected = false;
		lastCommited = -1;
	} /* close() */


    /**
     * <p>
     * Low level function that allows you to retrieve the JDBC connection associated
     * with this DBConnection.  This allows you to do several fancy things that would
     * not normally happen within Expresso itself such as prepared statements, and
     * other low level entities.  </p>
     * <p>
     * <b>NOTE:</b>  Once you grab the connection yourself, you are on your own
     * as far as the framework is concerned.  It doesn't help you to get your
     * connection back in place.  So, for example, if you close the connection manually,
     * it will mess up the connection pool.  Or if you fail to free a prepared statement,
     * it will register as a resource leak.  Be sure to restore your connection to
     * pristine order before releasing this DBConnection back into the pool.
     * </p>
     * @return a java.sql.Connection JDBC connection.
     */
    public DBConnection getTransactionConnection() {
        if (myConnection == null) {
            return null;
        }
        return myConnection;
    }

    /**
     * Returns the text description of this connection. When the connection
     * is put in use by a client program a description is set, this method
     * retrieves the description.
     *
     * @return    String A text description of this database connection's purpose
     */
    public String getDescription() {
        return myDescription;
    } /* getDescription() */

    /**
     * When this connection has lost its connection to the server,
     * tell whether or not it is available to be re-allocated
     *
     * @return boolean True if the connection has been lost,
     *    false if it is still usable
     * @throws DBException
     */
    public boolean isClosed()
            throws DBException {
				String myName = (THIS_CLASS + "isClosed()");

        try {
            return myConnection.isClosed();
        } catch (DBException se) {
            throw new DBException(myName + "isClosed()" + ":Cannot access connection to " +
                    "database via (driver or JNDI) '" + myConnection.getDBDriver() +
                    "' and URL '" + myConnection.getDBURL() + "' (" +
                    myDescription + ")", se.getMessage());
        }
    } /* isClosed() */


	/**
	 * When this connection has lost its connection to the server,
	 * tell whether or not it is available to be re-allocated
	 *
	 * @return boolean True if the connection has been lost,
	 *    false if it is still usable
	 * @throws DBException
	 */
	public boolean isConnected() {
			return isConnected;
	} /* boolean() */


    /**
     * Roll back the current transaction, as if it were never requested.  If
     * the JDBC driver claims it doesn't support transactions, then this
     * method is a NOOP except for touching the connection
     *
     * @throws    DBException If the rollback encounters an error
     */
    public void rollback() throws DBException {
		String myName = (THIS_CLASS + "rollback()");
      try {
      	  if (!myConnection.isClosed()) {
			myConnection.rollback();
			if (log.isDebugEnabled()) {
				log.debug(myName + " Transaction " + myConnection.getId() + " Rollback:'" + 
						"' on db '" + getDataContext() + "'");
			}
     	  	close();
      	  }
      } catch (DBException se) {
      		close();
          throw new DBException(myName + " Transaction" + ":Could not rollback" + " (" +
                   myDescription + ")", se.getMessage());
        }
    } /* rollback() */



    /**
     * Set a description for this database connection. When status is requested
     * from the connection pool, this is used to describe the connection.
     * Any client requesting a connection from the pool should set the
     * description of the connection as soon as it's returned
     *
     * @param    newDescription Description of this connection
     */
    public void setDescription(String newDescription) {
        if (newDescription != null) {
            myDescription = newDescription;
        }

    } /* setDescription(String) */

    /**
     * Sets the data context for the connection.
     * @param newDBName the datacontext name to use
     */
    public void setDataContext(String newDBName) {
        if (StringUtil.notNull(newDBName).length() == 0) {
            dbName = DEFAULT_DB_CONTEXT_NAME;
        } else {
            dbName = newDBName;
        }
    }

    /**
     * Retrieve the data context name we're associated with
     * @return java.lang.String of the current data Context
     */
    public String getDataContext() {
        return dbName;
    }

    /**
     * <p>Releases the DBConnection back into the parent DBConnectionPool.  Allows
     * for syntax like:</p>
     * <code>
     * <p>
     * DBConnection connection = DBConnectionPool.getInstance("default").getConnection(); <br/>
     * [do stuff]<br />
     * connection.release(); <br />
     * </code>
     * </p>
     */
    public void release() throws DBException {
		String myName = (THIS_CLASS + "release()");
        if (myConnection != null) {
			myConnection.setImmortal(false);
			if (log.isDebugEnabled()) {
				log.debug(myName + " Transaction " + myConnection.getId() + " Released:'" + 
						"' on db '" + getDataContext() + "'");
			}
			myPool.release(myConnection);
			myConnection = null;
			myPool = null;
        } else {
			log.warn(myName + "No parent connection pool defined for this DBConnection");
        }

        return;
    } /* release () */

	/**
	 * @return
	 */
	public DBConnectionPool getPool() {
		return myPool;
	}

	/**
	 * @param pool
	 */
	public void setPool(DBConnectionPool pool) {
		myPool = pool;
	}

	/**
	 * Set EXPRESSO transaction mode for the current DBConnection.
	 * 
	 * author Yves Henri AMAIZO, Mon Dec 22 10:30:59 2003
	 * @since Expresso 5.3
	 *
	 * @throws DBException
	 */
	public void setTransactionReadOnlyMode() throws DBException {
		String myName = (THIS_CLASS + "setTransactionReadOnlyMode()");

		try {
			myConnection.setTransactionCommittedMode();
		} catch (DBException se) {
			throw new DBException(myName + "Transaction " + myDescription + "." + myConnection.getId() + " Transaction Committed Mode :'" + 
			"' on db '" + getDataContext() + "'" + se);
		}
	}

	/**
	 * Set EXPRESSO transaction mode for the current DBConnection.
	 * 
	 * author Yves Henri AMAIZO, Mon Dec 22 10:30:59 2003
	 * @since Expresso 5.3
	 *
	 * @throws DBException
	 */
	public void setTransactionDirtyMode() throws DBException {
		String myName = (THIS_CLASS + "setTransactionDirtyMode()");

		try {
			myConnection.setTransactionUncommittedMode();
		} catch (DBException se) {
			throw new DBException(myName + "Transaction " + myDescription + "." + myConnection.getId() + " Transaction Uncommitted Mode :'" + 
			"' on db '" + getDataContext() + "'" +  se);
		}
	}

	/**
	 * Set EXPRESSO transaction mode for the current DBConnection.
	 * 
	 * author Yves Henri AMAIZO, Mon Dec 22 10:30:59 2003
	 * @since Expresso 5.3
	 *
	 * @throws DBException
	 */
	public void setTransactionRestrictiveMode() throws DBException {
		String myName = (THIS_CLASS + "setTransactionExclusiveMode()");

		try {
			myConnection.setTransactionRepeatableMode();
		} catch (DBException se) {
			throw new DBException(myName + "Transaction " + myDescription + "." + myConnection.getId() + " Transaction Repeatable Mode :'" + 
			"' on db '" + getDataContext() + "'" +  se);
		}
	}

	/**
	 * Set EXPRESSO transaction mode for the current DBConnection.
	 * 
	 * author Yves Henri AMAIZO, Mon Dec 22 10:30:59 2003
	 * @since Expresso 5.3
	 *
	 * @throws DBException
	 */
	public void setTransactionExclusiveMode() throws DBException {
		String myName = (THIS_CLASS + "setTransactionExclusiveMode()");

		try {
			myConnection.setTransactionSerializableMode();
		} catch (DBException se) {
			throw new DBException(myName + " Transaction " + myDescription + "." + myConnection.getId() + " Transaction Serialisable Mode :'" + 
			"' on db '" + getDataContext() + "'" +  se);
		}
	}

	/**
	 * Get transaction id
	 * @return int
	 * 
	 * author Yves Henri AMAIZO, Mon Dec 22 10:30:59 2003
	 * @since Expresso 5.3
	 */
	public int getId() {
		return transactionId;
	}

	/**
	 * Set transaction id
	 * 
	 * @param newTransactionID
	 */
	private void setId(int newTransactionID) {
		transactionId = newTransactionID;
	}

	/**
	 * Get transaction identifier which is myDescription + transactionId
	 * 
	 * @return String
	 *
	 * author Yves Henri AMAIZO, Mon Dec 22 10:30:59 2003
	 * @since Expresso 5.3
	 */
	public String getTransactionIdentifier() {
		return myDescription + "." + Integer.toString(transactionId);
	}


}

/* DBTransaction */


More information about the cvs mailing list