com.devwebsphere.jdbc.loader.JDBCTxCallback.java Source code

Java tutorial

Introduction

Here is the source code for com.devwebsphere.jdbc.loader.JDBCTxCallback.java

Source

package com.devwebsphere.jdbc.loader;

//
//This sample program is provided AS IS and may be used, executed, copied and
//modified without royalty payment by customer (a) for its own instruction and
//study, (b) in order to develop applications designed to run with an IBM
//WebSphere product, either for customer's own internal use or for redistribution
//by customer, as part of such an application, in customer's own products. "
//
//5724-J34 (C) COPYRIGHT International Business Machines Corp. 2009
//All Rights Reserved * Licensed Materials - Property of IBM
//

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSource;

import com.ibm.websphere.objectgrid.ObjectGrid;
import com.ibm.websphere.objectgrid.Session;
import com.ibm.websphere.objectgrid.TxID;
import com.ibm.websphere.objectgrid.plugins.TransactionCallback;
import com.ibm.websphere.objectgrid.plugins.TransactionCallbackException;
import com.mysql.jdbc.Driver;

/**
 * This is the JDBC transaction callback. This allocates a slot that is used to store the reference to
 * the Connection instance for a given transaction. It initializes a DataSource for database connections
 * and then provides a Connection instance for transactions that need one using the getConnection
 * method. No Connection instance is created per transaction unless one is needed.
 * @author bnewport
 *
 */
public class JDBCTxCallback implements TransactionCallback {
    public String getConnecturi() {
        return connecturi;
    }

    public void setConnecturi(String connecturi) {
        this.connecturi = connecturi;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    /**
     * Property which must be set for the JDBC connection URL
     */
    String connecturi;
    /**
     * The username for the database
     */
    String username;
    /**
     * The password for the database
     */
    String password;

    /**
     * Use the classname for the slot name. Needs to be unique
     */
    public static String DATASLOT = JDBCTxCallback.class.getName();

    /**
     * The DataSource for the database
     */
    DataSource ds;

    /**
     * The index of the slot that will store the Data instance for a given transaction
     */
    int dataSlot;

    /**
     * Make sure the DB2 database driver is loaded.
     */
    static {
        try {
            //         DB2Driver driver = new DB2Driver();
            //         DriverManager.registerDriver(driver);
            Driver d = new Driver();
            DriverManager.registerDriver(d);
        } catch (Exception e) {
            throw new RuntimeException("Unable to load the driver. Message " + e.getMessage());
        }
    }

    /**
     * This is called on every shard when its initialized within a JVM. We should really have a single DataSource per JVM,
     * not per shard
     */
    public void initialize(ObjectGrid og) throws TransactionCallbackException {
        if (og.getObjectGridType() == ObjectGrid.SERVER) {
            /**
             * Reserve a slot in the TxID to store the Data instance reference in.
             */
            dataSlot = og.reserveSlot(TxID.SLOT_NAME);
            /**
             * Connect to the database. We share a single data source between all primary shards within
             * a single JVM.
             */
            ds = setupDataSource(connecturi, username, password);
            try {
                // check we can connect
                Connection conn = ds.getConnection();
                if (conn == null)
                    throw new RuntimeException("Cannot open driver");
                conn.close();
            } catch (SQLException e) {
                throw new RuntimeException("Cannot open driver", e);
            }
        }
    }

    /**
     * Do nothing here, we don't want to slow down transactions creating or grabbing a Data instance
     * unless we have to.
     */
    public void begin(TxID tx) throws TransactionCallbackException {
    }

    /**
     * This is called when a WXS transaction commits. If a Data instance was created for the transaction then
     * commit it and clean up.
     */
    public void commit(TxID tx) throws TransactionCallbackException {
        if (tx.getSession().getObjectGrid().getObjectGridType() == ObjectGrid.SERVER) {
            try {
                Connection c = (Connection) tx.getSlot(dataSlot);
                if (c != null) {
                    c.commit();
                    c.close();
                    tx.putSlot(dataSlot, null);
                }
            } catch (SQLException e) {
                throw new TransactionCallbackException(e);
            }
        }
    }

    /**
     * This is called when a WXS transaction needs to rollback. If a Data instance was created for the transaction
     * then roll it back and clean up
     */
    public void rollback(TxID tx) throws TransactionCallbackException {
        if (tx.getSession().getObjectGrid().getObjectGridType() == ObjectGrid.SERVER) {
            try {
                Connection c = (Connection) tx.getSlot(dataSlot);
                if (c != null) {
                    c.rollback();
                    c.close();
                    tx.putSlot(dataSlot, null);
                }
            } catch (SQLException e) {
                throw new TransactionCallbackException(e);
            }
        }
    }

    public DataSource getDataSource() {
        return ds;
    }

    /**
     * Create a DataSource using the tomcat OCDP pool. Only make one per JVM. There is a PQTxCallback
     * instance for each primary shard placed in a JVM. This shares a single DataSource instance
     * between all of the PQTxCallback instances. We keep a Map of DataSources with an entry
     * per connectURI. This allows this generic class to be used for multiple grids
     * within the same JVM.
     * @param connectURI
     * @param user
     * @param password
     * @return
     */

    static Map<String, BasicDataSource> dataSourceList = new HashMap<String, BasicDataSource>();

    public synchronized static DataSource setupDataSource(String connectURI, String user, String password) {
        String key = connectURI + ":" + user + ":" + password;
        DataSource rc = dataSourceList.get(key);
        if (rc == null) {
            //
            // First, we'll need a ObjectPool that serves as the
            // actual pool of connections.
            //
            // We'll use a GenericObjectPool instance, although
            // any ObjectPool implementation will suffice.
            //

            BasicDataSource bds = new BasicDataSource();
            bds.setInitialSize(5);
            bds.setUrl(connectURI);
            bds.setUsername(user);
            bds.setPassword(password);
            bds.setPoolPreparedStatements(true);

            rc = bds;

            dataSourceList.put(key, bds);
        }
        return rc;
    }

    public boolean isExternalTransactionActive(Session arg0) {
        // TODO Auto-generated method stub
        return false;
    }

    /**
     * This returns the index of the slot where the Data instance is stored
     * @return
     * @see TxID#putSlot(int, Object)
     * @see TxID#getSlot(int)
     * @see ObjectGrid#reserveSlot(String)
     */
    public int getDataslot() {
        return dataSlot;
    }

    /**
     * This is called by Loaders to get a Data instance when they need it. The TxCallbacks job is to make one and store a reference
     * to it in the slot for all Loaders used in this transaction to share.
     * @param tx
     * @return
     */
    public Connection getConnection(TxID tx) throws SQLException {
        // is there already a JDBC Connection for this transaction?
        Connection c = (Connection) tx.getSlot(dataSlot);
        if (c == null) {
            // create one if needed
            c = getDataSource().getConnection();
            c.setAutoCommit(false);
            // store in the Tx slot for the Loaders to reuse for this transaction in the future
            tx.putSlot(dataSlot, c);
        }
        return c;
    }
}