|
From: backer <eb...@us...> - 2004-10-14 12:39:57
|
Update of /cvsroot/dynxform/dynxform/src/java/net/sf/dynxform/db In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6850/db Added Files: BindParameters.java DatabaseConnection.java Query.java StoredProcedure.java Log Message: moved all database depencies to db package --- NEW FILE: Query.java --- /* * Created by IntelliJ IDEA. * User: yurib * Date: Feb 18, 2004 * Time: 11:39:14 AM */ package net.sf.dynxform.db; import net.sf.dynxform.exception.business.SQLStatementException; import net.sf.dynxform.report.schema.*; import net.sf.dynxform.report.schema.types.ParamOperand; import net.sf.dynxform.util.ValueUtil; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.text.ParseException; import java.util.*; public class Query { private static final Log log = LogFactory.getLog(Query.class); protected Report report; protected net.sf.dynxform.form.types.Report outputReport; protected HashMap outputParams; private boolean isClosedAfterExecute = true; /** * SQL configuration information * */ protected HashMap parameters; /** * The connection, once opened * */ protected Connection conn; /** * And the statements * */ protected PreparedStatement pst; /** * The results, of course * */ protected java.sql.ResultSet rs = null; protected final String name = null; /** * If it is an update/etc, the return value (num rows modified) * */ protected int rv = -1; /** * Mapping out parameters - objectModel * */ protected String query; protected String getParameterValue(final String paramName) throws SQLStatementException { String paramValue; paramValue = (String) parameters.get(paramName.toLowerCase()); if (paramValue == null) paramValue = (String) parameters.get(paramName.toUpperCase()); if (paramValue == null) throw new SQLStatementException("Cannot find value for query parameter \"" + paramName + '\"'); return paramValue; } public Query(final Report report, final Map parameters) throws SQLStatementException { this.report = report; this.parameters = new HashMap(parameters); this.bindQueryParameters(this.processfilters()); } /** * Required for child classes */ protected Query() { } private void bindQueryParameters(final String queryString) throws SQLStatementException { query = queryString; if (query != null) { final ArrayList queryParams = BindParameters.getQueryParameterNames(query); final Iterator it = queryParams.iterator(); while (it.hasNext()) { final String paramName = (String) it.next(); final String paramValue = getParameterValue(paramName); query = BindParameters.bind(query, paramName, paramValue); } query = StringUtils.replace(query.trim(), "\r", " ", -1); } } public final void setConnection(final Connection conn) { this.conn = conn; } public final void execute() throws SQLStatementException { if (conn == null) { throw new SQLStatementException("A connection must be set before executing a query"); } if (query == null) { throw new SQLStatementException("A query must be not null"); } if (log.isDebugEnabled()) log.debug("EXECUTING " + query); try { prepare(); final boolean result = pst.execute(); if (result) { rs = pst.getResultSet(); } else { rv = pst.getUpdateCount(); } serialize(); } catch (ParseException e) { throw new SQLStatementException("Failed to prepare statement", e); } catch (Exception e) { throw new SQLStatementException("Failed to execute statement", e); } finally { try { if (isClosedAfterExecute) close(); } catch (SQLException e) { throw new SQLStatementException("Failed to close connection", e); } } } protected void prepare() throws SQLException, ParseException { pst = conn.prepareStatement(query, java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE, java.sql.ResultSet.CONCUR_READ_ONLY); } public void close() throws SQLException { try { if (rs != null) try { //getTheLogger().debug("Trying to close resultset "+rs.toString()); rs.close(); rs = null; // This prevents us from using the resultset again. //250getTheLogger().debug("Really closed the resultset now."); } catch (NullPointerException e) { log.debug("NullPointer while closing the resultset.", e); } if (pst != null) pst.close(); pst = null; // Prevent using pst again. } finally { conn.close(); } } protected void serialize() throws SQLStatementException { try { outputReport = ValueUtil.getReport(rs); } catch (SQLException ex) { throw new SQLStatementException("Cannot create report", ex); } } private String processfilters() { String filterValue; String sql = report.getSqlQueryChoice().getSqlQuery(); final Filters filters = report.getSqlQueryChoice().getFilters(); if (filters == null) return sql; final Enumeration fenu = filters.enumerateFilter(); while (fenu.hasMoreElements()) { final Filter filter = (Filter) fenu.nextElement(); if (filter == null) continue; final String filterName = '{' + filter.getName() + '}'; filterValue = " "; if (!StringUtils.contains(sql, filterName)) continue; Enumeration cenu = filter.enumerateCondition(); boolean breakFlag = false; if (filter.getConditionCount() == 0) { cenu = filter.getChoice().enumerateCondition(); breakFlag = true; } while (cenu.hasMoreElements()) { final Condition condition = (Condition) cenu.nextElement(); if (condition == null) continue; if (!checkCondition(condition, parameters)) continue; // throw new UnsupportedOperationException("condition.getSqlOperand()"); if (condition.getSqlOperand() != null) { filterValue += condition.getSqlOperand().toString() + '(' + condition.getValue() + ')'; } else { filterValue += condition.getValue(); } if (breakFlag) { break; } } sql = StringUtils.replace(sql, filterName, filterValue); } return sql; } private boolean checkCondition(final Condition condition, final HashMap parameters) { final Enumeration penu = condition.enumerateParam(); final ParamOperand po = condition.getParamOperand(); switch (po.getType()) { case ParamOperand.ALL_TYPE: return checkParamsValid(penu, parameters, true); case ParamOperand.NO_ONE_TYPE: return checkParamsValid(penu, parameters, false); case ParamOperand.EXIST_ONE_TYPE: return howManyParamsValid(penu, parameters) > 0; case ParamOperand.ONLY_ONE_TYPE: return howManyParamsValid(penu, parameters) == 1; } return false; } private boolean checkParamsValid(final Enumeration penu, final HashMap parameters, final boolean paramsPresent) { if (penu != null && parameters != null) { String paramName; String value; Param prm; while (penu.hasMoreElements()) { prm = (Param) penu.nextElement(); if (prm == null) { continue; } paramName = prm.getName().toUpperCase(); value = (String) parameters.get(paramName); if (paramsPresent) { if (value == null || value.length() == 0 || (prm.getCheckvalue() != null && !prm.getCheckvalue().equals(value))) { return false; } } else { if (value != null && value.length() != 0 && (prm.getCheckvalue() == null || (prm.getCheckvalue() != null && prm.getCheckvalue().equals(value)))) { return false; } } } } return true; } private int howManyParamsValid(final Enumeration penu, final HashMap parameters) { int result = 0; if (penu != null && parameters != null) { String paramName; String value; Param prm; while (penu.hasMoreElements()) { prm = (Param) penu.nextElement(); if (prm == null) { continue; } paramName = prm.getName().toUpperCase(); value = (String) parameters.get(paramName); if (value != null && value.length() != 0 && (prm.getCheckvalue() == null || (prm.getCheckvalue() != null && prm.getCheckvalue().equals(value)))) { result++; } } } return result; } public final net.sf.dynxform.form.types.Report getReport() { return outputReport; } public HashMap getOutParams() { return outputParams; } protected abstract static class ParameterValue { protected abstract String getStringValue(); } public final boolean isClosedAfterExecute() { return isClosedAfterExecute; } public final void setClosedAfterExecute(final boolean closedAfterExecute) { isClosedAfterExecute = closedAfterExecute; } } --- NEW FILE: DatabaseConnection.java --- package net.sf.dynxform.db; import net.sf.dynxform.exception.system.ConfigurationException; import net.sf.dynxform.exception.system.DataStoreException; import net.sf.dynxform.exception.system.SystemException; import net.sf.dynxform.util.Constants; import net.sf.dynxform.util.CurrentClassloader; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.sql.DataSource; import java.io.IOException; import java.sql.Connection; import java.sql.Driver; import java.sql.DriverManager; import java.sql.SQLException; import java.util.PropertyResourceBundle; /** * Returns database connections. * <p/> * <P><em>Design Note</em>: this class hides the design decision regarding * how connections are obtained by this application. If that decision changes, * then the ripple effects will be contained in this class. */ public final class DatabaseConnection { private static DatabaseConnection databaseConnection; private static String database_driver; private static String database_url; private static String database_username; private static String database_password; private static String database_jndi; private static String database_use_direct = "true"; private static boolean isPoolingEnabled; private static Driver driver; private boolean isInitialized; private DatabaseConnection() { } /** * Return a <code>Connection</code> for performing operations on a database. * <p/> * <P>When the database operations have finished, the <code>Connection.close</code> * method <em>must be called on the return value</em>. * <p/> * <P>Use the returned <code>Connection</code> for performing either a single * database operation, or a set of closely related operations; it is highly * recommended that the returned <code>Connection</code> NOT be retained for * an extended time, and that it be used only for a single user request. */ public synchronized Connection get() throws SystemException { if (!isInitialized) init(); return isPoolingEnabled ? getPooledConnection() : getSimpleConnection(); } private void init() throws SystemException { try { final PropertyResourceBundle properties = CurrentClassloader.getPropertyResourceBundle("db.properties"); database_driver = properties.getString("database.driver"); database_url = properties.getString("database.url"); database_username = properties.getString("database.username"); database_password = properties.getString("database.password"); database_jndi = properties.getString("database.jndi"); database_use_direct = properties.getString("database.use.direct"); isPoolingEnabled = "false".equalsIgnoreCase(database_use_direct); isInitialized = true; } catch (IOException ex) { throw new SystemException("Fail to load db.properties file", ex); } } /** * Conventional prefix for all JNDI names. */ private static final String STANDARD_ENVIRONMENT = "java:comp/env/"; private static void loadDbDriver() { try { driver = (Driver) Class.forName(database_driver).newInstance(); DriverManager.registerDriver(driver); } catch (Exception ex) { throw new RuntimeException("Cannot load/register jdbc driver: " + database_driver, ex); } } private Connection getPooledConnection() throws SystemException { Connection result; Context envContext = null; try { final Context initialContext = new InitialContext(); envContext = (Context) initialContext.lookup(STANDARD_ENVIRONMENT); final DataSource datasource = (DataSource) envContext.lookup(database_jndi); result = datasource.getConnection(); } catch (NamingException ex) { try { net.sf.dynxform.util.JNDITree.showTree("/", envContext, 0, Integer.MAX_VALUE); } catch (NamingException nex) { //nothing to do, just print out JNDI tree } throw new ConfigurationException("Config error with JNDI and datasource.", ex); } catch (SQLException ex) { throw new DataStoreException("Cannot get JNDI connection from datasource.", ex); } return result; } private Connection getSimpleConnection() throws SystemException { Connection result; try { if (driver == null) loadDbDriver(); result = DriverManager.getConnection(database_url, database_username, database_password); } catch (Exception ex) { final StringBuffer message = new StringBuffer(); message.append("*** CANNOT CONNECT to database named: "); message.append(database_url + Constants.NEW_LINE); message.append(" User name: " + database_username + Constants.NEW_LINE); message.append(" Password: " + database_password + Constants.NEW_LINE); message.append(" Reason: " + ex + Constants.NEW_LINE); throw new SystemException(message.toString(), ex); } return result; } public static synchronized DatabaseConnection create() { if (databaseConnection == null) databaseConnection = new DatabaseConnection(); return databaseConnection; } } --- NEW FILE: BindParameters.java --- package net.sf.dynxform.db; import org.apache.regexp.RE; import org.apache.regexp.RESyntaxException; import java.util.ArrayList; public final class BindParameters { public static String bind(String query, final String paramName, final Object paramValue) throws RESyntaxException { query = query + ' '; final boolean isNull = (paramValue == null); RE re = new RE("\\s*=\\s*(:" + paramName + ")([\\s^\\w]|[^\\w]|[\n])", RE.MATCH_CASEINDEPENDENT); String replaceValue = (isNull) ? " is null" : " =" + paramValue; replaceValue += "$2"; String result; result = re.subst(query , replaceValue, RE.REPLACE_ALL | RE.REPLACE_BACKREFERENCES); if (result != null) query = result; replaceValue = (isNull) ? " null" : " " + paramValue; replaceValue += "$2"; re = new RE("(:" + paramName + ")([\\s^\\w]|[^\\w])", RE.MATCH_CASEINDEPENDENT); result = re.subst(query , replaceValue, RE.REPLACE_ALL | RE.REPLACE_BACKREFERENCES); if (result != null) query = result; result = result.substring(0, result.length() - 1); return result; } public static ArrayList getQueryParameterNames(String query) { final ArrayList result = new ArrayList(); query = query + ' '; final RE re = new RE("([\\s^\\w]|[^\\w]):(\\w*)([\\s^\\w]|[^\\w])", RE.MATCH_CASEINDEPENDENT); int matchIndex = 0; String parameterName; while (re.match(query, matchIndex)) { parameterName = re.getParen(2); matchIndex = re.getParenEnd(2); result.add(parameterName.toUpperCase()); } return result; } } --- NEW FILE: StoredProcedure.java --- /* * Created by IntelliJ IDEA. * User: yurib * Date: Feb 18, 2004 * Time: 11:39:14 AM */ package net.sf.dynxform.db; import net.sf.dynxform.exception.business.BusinessException; import net.sf.dynxform.exception.business.SQLStatementException; import net.sf.dynxform.report.schema.Parameter; import net.sf.dynxform.report.schema.Procedure; import net.sf.dynxform.report.schema.types.ParameterTypesEnumeration; import net.sf.dynxform.util.Constants; import net.sf.dynxform.util.ValueUtil; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.lang.reflect.Field; import java.sql.*; import java.text.ParseException; import java.util.*; public final class StoredProcedure extends Query { private static Log log = LogFactory.getLog(StoredProcedure.class); private Procedure procedure; private List inParameters; private List outParameters; private List outResultSets; public StoredProcedure(final Procedure procedure, final Map parameters) throws BusinessException { try { this.setProcedure(procedure); this.parameters = new HashMap(parameters); this.query = procedure.getSqlJdbcCall(); this.setInOutParameters(); } catch (Exception e) { throw new BusinessException("Failed to create stored procedure " + this.getProcedure().getName(), e); } } private void setInOutParameters() throws BusinessException, SQLException, IllegalAccessException, NoSuchFieldException, ClassNotFoundException { final net.sf.dynxform.report.schema.ParameterList paramlist = getProcedure().getParameterList(); if (paramlist == null) return; final Enumeration enu = paramlist.enumerateParameter(); while (enu.hasMoreElements()) { createSpParameter((Parameter) enu.nextElement()); } } private void setInParameter(final SpParameter queryParameter) { if (getInParameters() == null) { setInParameters(new ArrayList()); } getInParameters().add(queryParameter); } private void setOutParameter(final SpParameter queryParameter) { if (getOutParameters() == null) { setOutParameters(new ArrayList()); } getOutParameters().add(queryParameter); } private void registerInParameters(final PreparedStatement pst) throws SQLException, ParseException { if (getInParameters() == null) return; final Iterator itInKeys = getInParameters().iterator(); while (itInKeys.hasNext()) { final SpParameter queryParameter = (SpParameter) itInKeys.next(); queryParameter.register(pst); } } private void registerOutParameters(final PreparedStatement pst) throws SQLException, ParseException { if (getOutParameters() == null) return; final Iterator itOutKeys = getOutParameters().iterator(); while (itOutKeys.hasNext()) { final SpParameter queryParameter = (SpParameter) itOutKeys.next(); queryParameter.register(pst); } } protected final void prepare() throws SQLException, ParseException { pst = conn.prepareCall(query, java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE, java.sql.ResultSet.CONCUR_READ_ONLY); registerOutParameters(pst); registerInParameters(pst); } protected final void serialize() throws SQLStatementException { if (getOutParameters() == null || pst == null) return; // throw new SQLStatementException("Cannot serialize procedure call because statement or query parameter is null!"); outputParams = new HashMap(); //make sure output follows order as parameter order in stored procedure final Iterator itOutKeys = getOutParameters().iterator(); SpParameter queryParameter; while (itOutKeys.hasNext()) { queryParameter = (SpParameter) itOutKeys.next(); try { final Object obj = ((CallableStatement) pst).getObject(queryParameter.getOrder()); if (obj == null) throw new SQLStatementException("Cannot find value for storage procedure output parameter: \"" + queryParameter.getCleanValue() + "\" parameter order: " + queryParameter.getOrder()); if (!(obj instanceof ResultSet)) { outputParams.put(queryParameter.getCleanValue(), obj.toString()); } else { rs = (ResultSet) obj; if (getOutResultSets() == null) setOutResultSets(new ArrayList()); getOutResultSets().add(rs); outputReport = ValueUtil.getReport(rs); outputParams.put(queryParameter.getCleanValue(), outputReport); } } catch (SQLException e) { throw new SQLStatementException("Cannot serialize procedure call result set", e); } } if (outputReport == null) outputReport = ValueUtil.getReport(outputParams); } public final void close() throws SQLException { if (outputReport != null && getOutResultSets() != null) { final Iterator it = getOutResultSets().iterator(); while (it.hasNext()) { final Object obj = it.next(); try { java.sql.ResultSet rs = ((java.sql.ResultSet) obj); rs.close(); rs = null; } catch (NullPointerException e) { getLog().warn("Failed to close SP:" + name + " output result set."); } } } super.close(); } protected final String getParameterValue(String paramName) { String paramValue = null; if (paramName.startsWith("parameter:")) { paramName = StringUtils.substringAfter(paramName, "parameter:"); paramValue = (String) parameters.get(paramName.toLowerCase()); if (paramValue == null) paramValue = (String) parameters.get(paramName.toUpperCase()); } else if (paramName.startsWith("output:")) { paramName = StringUtils.substringAfter(paramName, "output:"); final HashMap outParams = (HashMap) parameters.get("output"); if (outParams != null) { paramValue = (String) outParams.get(paramName.toLowerCase()); if (paramValue == null) paramValue = (String) outParams.get(paramName.toUpperCase()); } } else if (paramName.startsWith("default:")) paramValue = StringUtils.substringAfter(paramName, "default:"); return paramValue; } private void createSpParameter(final net.sf.dynxform.report.schema.Parameter parameter) throws IllegalAccessException, SQLException, NoSuchFieldException, BusinessException, ClassNotFoundException { if (parameter.getType().equals(ParameterTypesEnumeration.IN)) { setInParameter(new SpInParameter(parameter)); } else if (parameter.getType().equals(ParameterTypesEnumeration.OUT)) { setOutParameter(new SpOutParameter(parameter)); } } public final HashMap getOutParams() { return outputParams; } public static Log getLog() { return log; } public static void setLog(final Log log) { StoredProcedure.log = log; } public Procedure getProcedure() { return procedure; } public void setProcedure(final Procedure procedure) { this.procedure = procedure; } public List getInParameters() { return inParameters; } public void setInParameters(final List inParameters) { this.inParameters = inParameters; } public List getOutParameters() { return outParameters; } public void setOutParameters(final List outParameters) { this.outParameters = outParameters; } public List getOutResultSets() { return outResultSets; } public void setOutResultSets(final List outResultSets) { this.outResultSets = outResultSets; } abstract static class SpParameter { private String className; private String fieldName; private Class clss; private Field fld; private int jdbcType; private final int order; private final String name; private String value; private Object objectValue; private final String type; private final boolean isNull; protected SpParameter(final net.sf.dynxform.report.schema.Parameter parameter) throws SQLStatementException { this.type = parameter.getJdbcType(); this.order = parameter.getOrder(); this.name = parameter.getName(); this.setValue(parameter.getValue()); this.isNull = parameter.getIsNull(); init(); } public final int getOrder() { return order; } public final String getCleanValue() { return StringUtils.substringAfter(getValue(), ":"); } final void init() throws SQLStatementException { final int index = getType().lastIndexOf("."); if (index > -1) { setClassName(getType().substring(0, index)); setFieldName(getType().substring(index + 1, getType().length())); } else { getLog().error("Invalid SQLType: " + getType(), null); throw new SQLStatementException("Invalid SQLType: " + getType()); } try { setClss(Class.forName(getClassName())); setFld(getClss().getField(getFieldName())); setJdbcType(getFld().getInt(getFieldName())); } catch (Exception ex) { throw new SQLStatementException("Cannot init stored procedure parameter \"" + getName() + '\"', ex); } } protected abstract void register(PreparedStatement pst) throws SQLException, ParseException; public final boolean isNull() { return isNull; } public final String getClassName() { return className; } public final void setClassName(final String className) { this.className = className; } public final String getFieldName() { return fieldName; } public final void setFieldName(final String fieldName) { this.fieldName = fieldName; } public final Class getClss() { return clss; } public final void setClss(final Class clss) { this.clss = clss; } public final Field getFld() { return fld; } public final void setFld(final Field fld) { this.fld = fld; } public final int getJdbcType() { return jdbcType; } public final void setJdbcType(final int jdbcType) { this.jdbcType = jdbcType; } public final String getName() { return name; } public final String getValue() { return value; } public final void setValue(final String value) { this.value = value; } public final Object getObjectValue() { return objectValue; } public final void setObjectValue(final Object objectValue) { this.objectValue = objectValue; } public final String getType() { return type; } } final class SpInParameter extends SpParameter { SpInParameter(final net.sf.dynxform.report.schema.Parameter parameter) throws SQLStatementException { super(parameter); this.setValue(getParameterValue(parameter.getValue())); if (this.getValue() == null) if (parameter.hasIsNull() && !parameter.getIsNull()) throw new SQLStatementException("Parameter \"" + parameter.getValue() + "\"(" + parameter.getName() + ") cannot be null!"); } protected final void register(final PreparedStatement pst) throws SQLException, ParseException { if (getLog().isDebugEnabled()) getLog().debug("Register IN parameter: '" + getName() + "', with value " + getValue() + " with class: " + getJdbcType()); if ((getJdbcType() == Types.DATE) || (getJdbcType() == Types.TIME) || (getJdbcType() == Types.FLOAT) || (getJdbcType() == Types.DOUBLE)) setObjectValue(convertToSQLObjectValue(getValue(), getJdbcType())); if (((getJdbcType() == Types.VARCHAR) || (getJdbcType() == Types.CHAR)) && (getValue() != null) && ((String) getValue()).length() == 0) setValue(" "); if (getObjectValue() == null) setObjectValue(getValue()); if (getObjectValue() != null) { pst.setObject(getOrder(), getObjectValue()); } else { if (!isNull()) throw new SQLException("Parameter " + getName() + " cannot be null"); else pst.setNull(getOrder(), getJdbcType()); } } } static final class SpOutParameter extends SpParameter { SpOutParameter(final Parameter parameter) throws BusinessException { super(parameter); } protected final void register(final PreparedStatement pst) throws SQLException { if (pst instanceof CallableStatement) { ((CallableStatement) pst).registerOutParameter(getOrder(), getJdbcType()); } } } private static Object convertToSQLObjectValue(final String paramValue, final int jdbcType) throws ParseException { Object returnValue = null; if (paramValue != null) { if ("".equals(paramValue)) return null; if (jdbcType == Types.DATE) { returnValue = new java.sql.Date(Constants.dateDateFormat.parse(paramValue).getTime()); } if (jdbcType == Types.TIME) { returnValue = new java.sql.Time(Constants.timeDateFormat.parse(paramValue).getTime()); } if (jdbcType == Types.FLOAT) { returnValue = new Float(paramValue); } if (jdbcType == Types.DOUBLE) { returnValue = new Double(paramValue); } } return returnValue; } } |