FileDocCategorySizeDatePackage
DBTag.javaAPI DocExample7183Thu Jun 28 16:14:16 BST 2001com.ora.jsp.tags.sql

DBTag.java

package com.ora.jsp.tags.sql;

import java.util.*;
import java.sql.*;
import javax.sql.*;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
import com.ora.jsp.sql.*;
import com.ora.jsp.sql.value.*;

/**
 * This class is a custom action for executing a SQL SELECT statement.
 * The statement must be defined in the body of the action. It can
 * contain ? place holders, replaced by the value of <ora:sqlValue>
 * elements before execution. The number and order of place holders must
 * match the number and order of <ora:sqlValue> elements in the body.
 *
 * @author Hans Bergsten, Gefion software <hans@gefionsoftware.com>
 * @version 1.0
 */
public abstract class DBTag extends BodyTagSupport implements ValueTagParent {
    private SQLCommandBean sqlCommandBean = new SQLCommandBean();
    private String dataSourceName;
    private String id;
    private int scope = PageContext.PAGE_SCOPE;
    private String sqlValue;
    private Vector values;
    private boolean isExceptionThrown = false;
    private boolean isPartOfTransaction = false;


    /**
     * Sets the dataSource attribute.
     *
     * @param dataSource the name of the DataSource object available
     *   in the application scope
     */
    public void setDataSource(String dataSourceName) {
        this.dataSourceName = dataSourceName;
    }

    /**
     * Sets the id attribute.
     *
     * @param id the name for the result variable
     */
    public void setId(String id) {
        this.id = id;
    }

    /**
     * Sets the scope attribute.
     *
     * @param scope the scope for the result variable
     */
    public void setScope(String scopeName) {
        if ("page".equals(scopeName)) {
            scope = PageContext.PAGE_SCOPE;
        }
        else if ("request".equals(scopeName)) {
            scope = PageContext.REQUEST_SCOPE;
        }
        else if ("session".equals(scopeName)) {
            scope = PageContext.SESSION_SCOPE;
        }
        else if ("application".equals(scopeName)) {
            scope = PageContext.APPLICATION_SCOPE;
        }
    }

    /**
     * Adds a value. This method is called by value tags in the
     * action body.
     *
     * @param value a ValueHolder with a value for the PreparedStatement
     */
    public void addValue(Value value) {
        if (values == null) {
            values = new Vector();
        }
        values.addElement(value);
    }

    /**
     * Override the default implementation to reset the
     * per-use state set by nested elements.
     */
    public int doStartTag() {
	values = null;
        isExceptionThrown = false;
        isPartOfTransaction = false;

        return EVAL_BODY_TAG;
    }
    
    /**
     * Sets the SQL statement to the contents of the element's
     * body.
     */
    public int doAfterBody() throws JspException {
        sqlValue = bodyContent.getString();
    	return SKIP_BODY;
    }

    /**
     * If the action is included in the body of a <ora:transaction> tag,
     * gets the connection from the <ora:transaction> tag. If not,
     * gets the DataSource from the application scope and asks for a Connection.
     * Executes the SQL query defined in the action element's body, and saves the
     * result as a Vector with Row objects in the specified scope under the
     * specified name.
     *
     */
    public int doEndTag() throws JspException {
        Connection conn = getConnection();
        sqlCommandBean.setConnection(conn);
        sqlCommandBean.setSqlValue(sqlValue);
        sqlCommandBean.setValues(values);
        Object result = null;
        try {
            result = execute(sqlCommandBean);
        }
        catch (SQLException e) {
            try {
                isExceptionThrown = true;
                conn.rollback();
            }
            catch (SQLException se) {} // Ignore, probably a result of the main exception
            throw new JspException("SQL error: " + e.getMessage());
        }
        catch (UnsupportedTypeException e) {
            try {
                isExceptionThrown = true;
                conn.rollback();
            }
            catch (SQLException se) {} // Ignore, probably caused by the main exception
            throw new JspException("Query result error: " + e.getMessage());
        }
        finally {
            try {
                if (isPartOfTransaction && isExceptionThrown) {
                    // Reset auto commit in case the connection is pooled
                    // before it's returned to the pool by close
                    conn.setAutoCommit(true);
                    conn.close();
                }
                else if (!isPartOfTransaction) {
                    // If we're not part of a transaction, the connection
                    // is in auto commit mode so we only close it
                    conn.close();
                }
            }
            catch (SQLException e) {
                e.printStackTrace(System.err);
            }
        }
        // Save the result with the specified id in the specified scope
        if (id != null) {
            pageContext.setAttribute(id, result, scope);
        }
        return EVAL_PAGE;
    }
    
    /**
     * Releases all instance variables.
     */
    public void release() {
        dataSourceName = null;
        id = null;
        scope = PageContext.PAGE_SCOPE;
        sqlValue = null;
        values = null;
        isExceptionThrown = false;
        isPartOfTransaction = false;
        super.release();
    }

    /**
     * Must be implemented by subclass to perform the appropriate
     * processing.
     */
    protected abstract Object execute(SQLCommandBean sqlCommandBean)
        throws SQLException, UnsupportedTypeException;

    /**
     * Gets the Connection either from a transaction parent or from
     * the DataSource specified for the action.
     */
    private Connection getConnection() throws JspException {
        Connection conn = null;
        TransactionTag transactionTag = (TransactionTag)
            findAncestorWithClass(this, TransactionTag.class);
        if (transactionTag != null) {
            conn = transactionTag.getConnection();
            isPartOfTransaction = true;
            if (dataSourceName != null) {
                throw new JspException("A dataSource must not be specified " +
                    "when the action is part of a transaction");
            }
        }
        else {
            DataSource dataSource = (DataSource)
                pageContext.getAttribute(dataSourceName, PageContext.APPLICATION_SCOPE);
            if (dataSource == null) {
                throw new JspException("dataSource " + dataSourceName + " not found");
            }
            try {
                conn = dataSource.getConnection();
            }
            catch (SQLException e) {
                throw new JspException("SQL error: " + e.getMessage());
            }
        }
        return conn;
    }
}