You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@beehive.apache.org by cs...@apache.org on 2007/04/09 19:02:31 UTC
svn commit: r526830 - in /beehive/trunk/system-controls:
src/jdbc/org/apache/beehive/controls/system/jdbc/parser/
test/jdbc/controls/org/apache/beehive/controls/system/jdbc/test/results/
test/jdbc/junitTests/org/apache/beehive/controls/system/jdbc/unit...
Author: cschoett
Date: Mon Apr 9 10:02:29 2007
New Revision: 526830
URL: http://svn.apache.org/viewvc?view=rev&rev=526830
Log:
Fix for BEEHIVE-1189, JDBC system control batch updates not supporting bean parameters.
Added the ability to correctly process bean array parameter types on JDBC control methods which include the batchUpdate setting in their SQL annotation. This turned out to be more of an enhancement than a bug fix since this functionality did not previously exist.
In addition, added new JDBC control DRTs to test this fix.
DRTs: JDBC System control, controls core
Modified:
beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/parser/JdbcFragment.java
beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/parser/ParameterChecker.java
beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/parser/ReflectionFragment.java
beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/parser/SqlFragment.java
beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/parser/SqlStatement.java
beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/parser/SqlSubstitutionFragment.java
beehive/trunk/system-controls/test/jdbc/controls/org/apache/beehive/controls/system/jdbc/test/results/ResultsTestCtrl.jcx
beehive/trunk/system-controls/test/jdbc/junitTests/org/apache/beehive/controls/system/jdbc/units/results/DBSingleRowResultsTest.java
Modified: beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/parser/JdbcFragment.java
URL: http://svn.apache.org/viewvc/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/parser/JdbcFragment.java?view=diff&rev=526830&r1=526829&r2=526830
==============================================================================
--- beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/parser/JdbcFragment.java (original)
+++ beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/parser/JdbcFragment.java Mon Apr 9 10:02:29 2007
@@ -71,4 +71,30 @@
}
return values.toArray();
}
+
+ /**
+ * Get the prepared statement parameter values contained within this fragment. This
+ * method is for the special case of array type parameters (part of a JDBC control method's
+ * argument list) and must include an index as to which value to get from the array. Parameter
+ * values which are of type array are typically only ever used for batch update calls.
+ *
+ * @param context A ControlBeanContext instance
+ * @param method The annotated method
+ * @param args The method's parameters
+ * @param paramArrayIndex Index of the param array value to get.
+ * @return null if this fragment doesn't contain a parameter value or if the args are not of array type.
+ */
+ Object[] getArrayParameterValues(ControlBeanContext context, Method method, Object[] args, int paramArrayIndex) {
+
+ ArrayList<Object> values = new ArrayList<Object>();
+ for (SqlFragment sf : _children) {
+ if (sf.hasParamValue()) {
+ Object[] moreValues = sf.getArrayParameterValues(context, method, args, paramArrayIndex);
+ for (Object o : moreValues) {
+ values.add(o);
+ }
+ }
+ }
+ return values.toArray();
+ }
}
Modified: beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/parser/ParameterChecker.java
URL: http://svn.apache.org/viewvc/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/parser/ParameterChecker.java?view=diff&rev=526830&r1=526829&r2=526830
==============================================================================
--- beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/parser/ParameterChecker.java (original)
+++ beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/parser/ParameterChecker.java Mon Apr 9 10:02:29 2007
@@ -25,6 +25,7 @@
import com.sun.mirror.declaration.TypeDeclaration;
import com.sun.mirror.type.DeclaredType;
import com.sun.mirror.type.TypeMirror;
+import com.sun.mirror.type.ArrayType;
import com.sun.mirror.util.DeclarationFilter;
import org.apache.beehive.controls.api.ControlException;
@@ -111,6 +112,12 @@
ParameterDeclaration tpd = paramMap.get(paramNameQualifiers[0]);
TypeMirror type = tpd.getType();
+
+ // check to see if the parameter is an array type, if so
+ // get its component type for the checks in this method.
+ if (type instanceof ArrayType) {
+ type = ((ArrayType)type).getComponentType();
+ }
MethodDeclaration getterMethod = null;
FieldDeclaration field = null;
Modified: beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/parser/ReflectionFragment.java
URL: http://svn.apache.org/viewvc/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/parser/ReflectionFragment.java?view=diff&rev=526830&r1=526829&r2=526830
==============================================================================
--- beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/parser/ReflectionFragment.java (original)
+++ beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/parser/ReflectionFragment.java Mon Apr 9 10:02:29 2007
@@ -164,11 +164,75 @@
return new Object[]{value};
}
+ /**
+ * Get the prepared statement parameter values contained within this fragment. This
+ * method is for the special case of array type parameters (part of a JDBC control method's
+ * argument list) and must include an index as to which value to get from the array. Parameter
+ * values which are of type array are typically only ever used for batch update calls.
+ *
+ * @param context A ControlBeanContext instance
+ * @param method The annotated method
+ * @param args The method's parameters
+ * @param paramArrayIndex Index of the param array value to get.
+ * @return null if this fragment doesn't contain a parameter value or if the args are not of array type.
+ */
+ protected Object[] getArrayParameterValues(ControlBeanContext context, Method method,
+ Object[] args, int paramArrayIndex)
+ {
+ Object value = getArrayParameterValue(context, method, args, paramArrayIndex);
+ if (value instanceof JdbcControl.ComplexSqlFragment) {
+ JdbcControl.SQLParameter[] params = ((JdbcControl.ComplexSqlFragment)value).getParameters();
+ Object[] values = new Object[params.length];
+ for (int i = 0; i < params.length; i++) {
+ values[i] = params[i].value;
+ }
+ return values;
+ }
+ return new Object[]{value};
+ }
+
//
// /////////////////////////////////////////////// PRIVATE METHODS /////////////////////////////////////////////
//
/**
+ * Get a pararmeter value from an array type parameter. This method is only used for
+ * batch update statements, where each JDBC control method parameter is an array type.
+ *
+ * @param context ControlBeanContext instance.
+ * @param method JDBC control method.
+ * @param args Parameters to the method.
+ * @param paramArrayIndex index of the value in the array parameter to get.
+ * @return Value of the reflected parameter.
+ */
+ private Object getArrayParameterValue(ControlBeanContext context, Method method,
+ Object[] args, int paramArrayIndex)
+ {
+ Object value;
+
+ try {
+ value = context.getParameterValue(method, _nameQualifiers[0], args);
+ } catch (IllegalArgumentException iae) {
+ throw new ControlException("Invalid argument name in SQL statement: " + _nameQualifiers[0], iae);
+ }
+
+ if (!value.getClass().isArray()) {
+ throw new ControlException("Parameter value must be an array type: " + _nameQualifiers[0]);
+ }
+
+ if (_nameQualifiers.length == 1 && value.getClass().isArray()) {
+ Object[] varr = TypeMappingsFactory.toObjectArray(value);
+ return varr[paramArrayIndex];
+ }
+
+ for (int i = 1; i < _nameQualifiers.length; i++) {
+ // handle maps, properties, and fields...
+ value = extractValue(((Object[])value)[paramArrayIndex], _nameQualifiers[i - 1], _nameQualifiers[i]);
+ }
+ return value;
+ }
+
+ /**
* Get the value from the method param.
* @param method
* @param args
@@ -182,6 +246,11 @@
throw new ControlException("Invalid argument name in SQL statement: " + _nameQualifiers[0], iae);
}
+ // if the parameter is an array type just return null -- nothing else can be done with it here
+ if (value.getClass().isArray()) {
+ return null;
+ }
+
for (int i = 1; i < _nameQualifiers.length; i++) {
// handle maps, properties, and fields...
value = extractValue(value, _nameQualifiers[i - 1], _nameQualifiers[i]);
Modified: beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/parser/SqlFragment.java
URL: http://svn.apache.org/viewvc/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/parser/SqlFragment.java?view=diff&rev=526830&r1=526829&r2=526830
==============================================================================
--- beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/parser/SqlFragment.java (original)
+++ beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/parser/SqlFragment.java Mon Apr 9 10:02:29 2007
@@ -79,6 +79,22 @@
}
/**
+ * Get the prepared statement parameter values contained within this fragment. This
+ * method is for the special case of array type parameters (part of a JDBC control method's
+ * argument list) and must include an index as to which value to get from the array. Parameter
+ * values which are of type array are typically only ever used for batch update calls.
+ *
+ * @param context A ControlBeanContext instance
+ * @param method The annotated method
+ * @param args The method's parameters
+ * @param paramArrayIndex Index of the param array value to get.
+ * @return null if this fragment doesn't contain a parameter value or if the args are not of array type.
+ */
+ Object[] getArrayParameterValues(ControlBeanContext context, Method method, Object[] args, int paramArrayIndex) {
+ return null;
+ }
+
+ /**
* Get the text for a prepared statement generated by this fragment.
* @param context A ControlBeanContext instance
* @param method The annotated method
Modified: beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/parser/SqlStatement.java
URL: http://svn.apache.org/viewvc/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/parser/SqlStatement.java?view=diff&rev=526830&r1=526829&r2=526830
==============================================================================
--- beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/parser/SqlStatement.java (original)
+++ beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/parser/SqlStatement.java Mon Apr 9 10:02:29 2007
@@ -197,7 +197,7 @@
// special handling for batch updates
//
} else if (_batchUpdate) {
- doBatchUpdate(preparedStatement, arguments, calendar);
+ doBatchUpdate(preparedStatement, context, method, arguments, calendar);
//
@@ -250,7 +250,7 @@
sqlString.append(" Params: {");
for (int i = 0; i < params.length; i++) {
if (i > 0) {
- sqlString.append(params[i].value == null ? "null" : params[i].value.toString());
+ sqlString.append(params[i].value == null ? "null" : params[i].value.toString());
}
}
sqlString.append("}");
@@ -317,25 +317,7 @@
case Types.TIMESTAMP:
if (value instanceof java.util.Calendar) {
Calendar calValue = (Calendar) value;
-
-// @todo: validate it is correct to comment out call to deprectated method
-// if (cal == null) {
-// /* NOTE: drivers are inconsistent in their handling of setTimestamp(i,date,cal)
-// * so we won't use that, unless the user calls setCalendar().
-// * I'm going with the theory that it makes sense to store
-// * the time relative to the Calendar's timezone rather than
-// * the system timezone otherwise, using a Calendar would be a no-op.
-// */
-// value = new java._sql.Timestamp(calValue.get(Calendar.YEAR) - 1900,
-// calValue.get(Calendar.MONTH),
-// calValue.get(Calendar.DATE),
-// calValue.get(Calendar.HOUR_OF_DAY),
-// calValue.get(Calendar.MINUTE),
-// calValue.get(Calendar.SECOND),
-// calValue.get(Calendar.MILLISECOND));
-// } else {
value = new java.sql.Timestamp(calValue.getTimeInMillis());
-// }
} else if (java.util.Date.class.equals(value.getClass())) {
// some drivers don't like java.util.Date
value = new java.sql.Timestamp(((java.util.Date) value).getTime());
@@ -352,22 +334,8 @@
case Types.DATE:
if (value instanceof java.util.Calendar) {
- /* NOTE: see note above
- Calendar cal = (Calendar)value;
- value = new java._sql.Date(cal.getTimeInMillis());
- ps.setDate(i, (java._sql.Date)value, cal);
- return;
- */
Calendar calValue = (Calendar) value;
-
- // @todo: validate that commenting out deprected method is correct behavior
-// if (cal == null) {
-// value = new java._sql.Date(calValue.get(Calendar.YEAR - 1900),
-// calValue.get(Calendar.MONTH),
-// calValue.get(Calendar.DATE));
-// } else {
value = new java.sql.Date(calValue.getTimeInMillis());
-// }
} else if (value.getClass() == java.util.Date.class) {
// some drivers don't like java.util.Date
value = new java.sql.Date(((java.util.Date) value).getTime());
@@ -428,21 +396,21 @@
* @param cal A Calendar instance used to resolve date/time values.
* @throws SQLException If a batch update cannot be performed.
*/
- private void doBatchUpdate(PreparedStatement ps, Object[] args, Calendar cal) throws SQLException {
-
- final int[] sqlTypes = new int[args.length];
- final Object[] objArrays = new Object[args.length];
-
- // build an array of type values and object arrays
- for (int i = 0; i < args.length; i++) {
- sqlTypes[i] = _tmf.getSqlType(args[i].getClass().getComponentType());
- objArrays[i] = TypeMappingsFactory.toObjectArray(args[i]);
- }
+ private void doBatchUpdate(PreparedStatement ps, ControlBeanContext context, Method method,
+ Object[] args, Calendar cal) throws SQLException
+ {
+ Object[] paramArray = TypeMappingsFactory.toObjectArray(args[0]);
+ final int rowCount = paramArray.length;
- final int rowCount = ((Object[]) objArrays[0]).length;
- for (int i = 0; i < rowCount; i++) {
- for (int j = 0; j < args.length; j++) {
- setPreparedStatementParameter(ps, j + 1, ((Object[]) objArrays[j])[i], sqlTypes[j], cal);
+ for (int row = 0; row < rowCount; row++) {
+ int pIndex = 1;
+ for (SqlFragment sf : _children) {
+ if (sf.hasParamValue()) {
+ Object values[] = sf.getArrayParameterValues(context, method, args, row);
+ for (Object value : values) {
+ setPreparedStatementParameter(ps, pIndex++, value, sf.getParamSqlDataType(), cal);
+ }
+ }
}
ps.addBatch();
}
Modified: beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/parser/SqlSubstitutionFragment.java
URL: http://svn.apache.org/viewvc/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/parser/SqlSubstitutionFragment.java?view=diff&rev=526830&r1=526829&r2=526830
==============================================================================
--- beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/parser/SqlSubstitutionFragment.java (original)
+++ beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/parser/SqlSubstitutionFragment.java Mon Apr 9 10:02:29 2007
@@ -105,6 +105,30 @@
}
/**
+ * Get the prepared statement parameter values contained within this fragment. This
+ * method is for the special case of array type parameters (part of a JDBC control method's
+ * argument list) and must include an index as to which value to get from the array. Parameter
+ * values which are of type array are typically only ever used for batch update calls.
+ *
+ * @param context A ControlBeanContext instance
+ * @param m The annotated method
+ * @param args The method's parameters
+ * @param paramArrayIndex Index of the param array value to get.
+ * @return null if this fragment doesn't contain a parameter value or if the args are not of array type.
+ */
+ protected Object[] getArrayParameterValues(ControlBeanContext context, Method m,
+ Object[] args, int paramArrayIndex)
+ {
+ ArrayList<Object> paramValues = new ArrayList<Object>();
+ for (SqlFragment frag : _children) {
+ if (frag.hasComplexValue(context, m, args)) {
+ paramValues.addAll(Arrays.asList(frag.getArrayParameterValues(context, m, args, paramArrayIndex)));
+ }
+ }
+ return paramValues.toArray();
+ }
+
+ /**
* Return the text for a PreparedStatement from this fragment. This type of fragment
* typically evaluates any reflection parameters at this point. The exception
* is if the reflected result is a ComplexSqlFragment, it that case the sql text
Modified: beehive/trunk/system-controls/test/jdbc/controls/org/apache/beehive/controls/system/jdbc/test/results/ResultsTestCtrl.jcx
URL: http://svn.apache.org/viewvc/beehive/trunk/system-controls/test/jdbc/controls/org/apache/beehive/controls/system/jdbc/test/results/ResultsTestCtrl.jcx?view=diff&rev=526830&r1=526829&r2=526830
==============================================================================
--- beehive/trunk/system-controls/test/jdbc/controls/org/apache/beehive/controls/system/jdbc/test/results/ResultsTestCtrl.jcx (original)
+++ beehive/trunk/system-controls/test/jdbc/controls/org/apache/beehive/controls/system/jdbc/test/results/ResultsTestCtrl.jcx Mon Apr 9 10:02:29 2007
@@ -535,6 +535,20 @@
public int[] doABatchUpdate(String[] fname, int[] userid);
/**
+ * Batch updates.
+ *
+ * @return int[]
+ */
+ @SQL(statement = "INSERT INTO users VALUES ({cust.fname}, {cust.userid})", batchUpdate = true)
+ public int[] doABatchUpdate2(Customer[] cust);
+
+ /**
+ * get results from batch update.
+ */
+ @SQL(statement="SELECT * FROM users WHERE userid = {uid}")
+ public Customer getBatchResult(int uid);
+
+ /**
* A basic usage of the getGeneratedKeys annotation member.
*
* @param aValue
Modified: beehive/trunk/system-controls/test/jdbc/junitTests/org/apache/beehive/controls/system/jdbc/units/results/DBSingleRowResultsTest.java
URL: http://svn.apache.org/viewvc/beehive/trunk/system-controls/test/jdbc/junitTests/org/apache/beehive/controls/system/jdbc/units/results/DBSingleRowResultsTest.java?view=diff&rev=526830&r1=526829&r2=526830
==============================================================================
--- beehive/trunk/system-controls/test/jdbc/junitTests/org/apache/beehive/controls/system/jdbc/units/results/DBSingleRowResultsTest.java (original)
+++ beehive/trunk/system-controls/test/jdbc/junitTests/org/apache/beehive/controls/system/jdbc/units/results/DBSingleRowResultsTest.java Mon Apr 9 10:02:29 2007
@@ -254,14 +254,56 @@
}
/**
- * add some new users to the table using batch update
- * @throws Exception
+ * Add some new users to the table using batch update, parameters to the
+ * JDBC control method are Java primitive array types.
*/
public void testBatchUpdate() throws Exception {
int[] results = testCtrl.doABatchUpdate(new String[]{"tester44", "tester55", "tester66"}, new int[]{44, 55, 66});
assertEquals(1, results[0]);
assertEquals(1, results[1]);
assertEquals(1, results[2]);
+
+ // verify the correct values were stored in the db
+ ResultsTestCtrl.Customer cust = testCtrl.getBatchResult(44);
+ assertEquals("tester44", cust.getFname());
+
+ cust = testCtrl.getBatchResult(55);
+ assertEquals("tester55", cust.getFname());
+
+ cust = testCtrl.getBatchResult(66);
+ assertEquals("tester66", cust.getFname());
+ }
+
+ /**
+ * Another test of batch update this time using bean arrays as method parameters
+ * instead of java primitive types.
+ */
+ public void testBatchUpate2() throws Exception {
+
+ ResultsTestCtrl.Customer[] customers = new ResultsTestCtrl.Customer[3];
+ customers[0] = new ResultsTestCtrl.Customer();
+ customers[0].setFname("tester44");
+ customers[0].userid = 44;
+ customers[1] = new ResultsTestCtrl.Customer();
+ customers[1].setFname("tester55");
+ customers[1].userid = 55;
+ customers[2] = new ResultsTestCtrl.Customer();
+ customers[2].setFname("tester66");
+ customers[2].userid = 66;
+ int[] results = testCtrl.doABatchUpdate2(customers);
+ assertEquals(1, results[0]);
+ assertEquals(1, results[1]);
+ assertEquals(1, results[2]);
+
+ // verify the correct values were stored in the db
+ ResultsTestCtrl.Customer cust = testCtrl.getBatchResult(44);
+ assertEquals("tester44", cust.getFname());
+
+ cust = testCtrl.getBatchResult(55);
+ assertEquals("tester55", cust.getFname());
+
+ cust = testCtrl.getBatchResult(66);
+ assertEquals("tester66", cust.getFname());
}
/**