/* * Copyright(c) 2005 Center for E-Commerce Infrastructure Development, The * University of Hong Kong (HKU). All Rights Reserved. * * This software is licensed under the GNU GENERAL PUBLIC LICENSE Version 2.0 [1] * * [1] http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt */ package hk.hku.cecid.piazza.commons.dao.ds; import hk.hku.cecid.piazza.commons.dao.DAOException; import java.io.InputStream; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * DataSourceProcess represents a data source transaction process. Subclasses are * required to implement the doTransaction() method for the transaction process. * <p> * This process will only manage, for example commit or rollback, the transaction * encapsulated if its DataSourceDAO is not under a transaction and it is not * explicitly instructed, in construction, to use a specified transaction. * * @author Hugo Y. K. Lam * */ public abstract class DataSourceProcess { private DataSourceDAO dao; private DataSourceTransaction transaction; private boolean isStarted = false; private boolean isCommitted = false; private boolean isRolledBack = false; private Object result; /** * Creates a new instance of DataSourceProcess. * * @param dao the DAO to which this process correspond. */ public DataSourceProcess(DataSourceDAO dao) { this(dao, null); } /** * Creates a new instance of DataSourceProcess. * * @param dao the DAO to which this process correspond. * @param transaction the transaction in which this process should execute. */ public DataSourceProcess(DataSourceDAO dao, DataSourceTransaction transaction) { this.dao = dao; this.transaction = transaction; } /** * Starts executing this process. A process can only be started if it * has not yet been started. * * @throws DAOException if there is any error in the execution or the * process has already been started. */ public synchronized void start() throws DAOException { if (isStarted) { throw new DAOException("Process already started."); } else { isStarted = true; } boolean isTransactionManaged = true; if (transaction == null) { transaction = dao.getTransaction(true); if (!dao.isUnderTransaction()) { isTransactionManaged = false; transaction.begin(); } } try { doTransaction(transaction); if (!isTransactionManaged) { transaction.commit(); isCommitted = true; } } catch (Throwable e) { DAOException de = new DAOException("Error in executing "+this, e); if (!isTransactionManaged) { try { transaction.rollback(); isRolledBack = true; } catch (Exception ex) { throw new DAOException("Error in rolling back ("+ex+")", de); } } throw de; } } /** * Executes the transaction process. * * @param tx the DataSourceTransaction object in which this process executes. * @throws DAOException if any error occurred in the execution. */ protected abstract void doTransaction(DataSourceTransaction tx) throws DAOException; /** * Sets a parameter to the prepared statement. * * @param pStmt the prepared statement. * @param pos the position of the parameter. * @param param the parameter. * @throws SQLException if unable to set the parameter. */ protected void setParameter(PreparedStatement pStmt, int pos, Object param) throws SQLException { if (param == null) { int type; try { type = pStmt.getParameterMetaData().getParameterType(pos); } catch (Throwable e) { type = java.sql.Types.VARCHAR; } pStmt.setNull(pos, type); } else if (param instanceof NullableObject) { NullableObject no = (NullableObject) param; if (no.isNull()) { pStmt.setNull(pos, no.getType()); } else { pStmt.setObject(pos, no.getObject()); } } else if (param instanceof InputStream){ InputStream ins = (InputStream)param; int len; try { len = ins.available(); } catch (Exception e) { len = 0; } pStmt.setBinaryStream(pos, ins, len); } else { pStmt.setObject(pos, param); } } /** * Counts the number of parameters required by the prepared statement. * If a parameter meta data is not available, it counts the occurrences of * '?' in the given SQL statement. * * @param pStmt the prepared statement. * @param sql the SQL statement. * @return the numbder of parameters. */ protected int getParameterCount(PreparedStatement pStmt, String sql) { try { return pStmt.getParameterMetaData().getParameterCount(); } catch (Throwable e) { Pattern p = Pattern.compile("\\?(?=(?:[^']*'[^']*')*(?![^']*'))"); Matcher m = p.matcher(sql); int noOfParas = 0; while (m.find()) { noOfParas++; } return noOfParas; } } /** * Gets the DAO to which this process correspond. * * @return the DAO to which this process correspond. */ protected DataSourceDAO getDAO() { return dao; } /** * Checks if this process has committed the transaction. * * @return true if this process has committed the transaction. */ public boolean isCommitted() { return isCommitted; } /** * Checks if this process has rolled back the transaction. * * @return true if this process has rolled back the transaction. */ public boolean isRolledBack() { return isRolledBack; } /** * Checks if this process has already been started. * * @return true if the this process has already been started. */ public boolean isStarted() { return isStarted; } /** * Sets the result of this process. * * @param result the result of this process. */ protected void setResult(Object result) { this.result = result; } /** * Gets the result of this process. * * @return the result of this process. */ public Object getResult() { return result; } /** * Returns a string representation of this process. * * @return a string representation of this process. * @see java.lang.Object#toString() */ public String toString() { return dao.getClass().getName()+"::Process@"+Integer.toHexString(hashCode()); } }