You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@beehive.apache.org by ke...@apache.org on 2004/10/18 18:26:40 UTC

svn commit: rev 55020 - in incubator/beehive/trunk/controls/test/src: controls/org/apache/beehive/controls/test/controls/database controls/org/apache/beehive/controls/test/controls/database/test drivers/org/apache/beehive/controls/test/driver/database units/org/apache/beehive/controls/test/java/database

Author: kentam
Date: Mon Oct 18 09:26:39 2004
New Revision: 55020

Modified:
   incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/DatabaseControlImpl.jcs
   incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/SQLParameter.java
   incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/SQLStatement.java
   incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/test/TestDBControl.jcx
   incubator/beehive/trunk/controls/test/src/drivers/org/apache/beehive/controls/test/driver/database/DriveDatabaseControl.java
   incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/database/ParserTest.java
   incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/database/SQLStatementTest.java
Log:
Database control now supports parameter substitution by name.  Parameter substitution 
by position is no longer supported, as substitution by name is a much better approach.

Contributor:
Hoi Lam





Modified: incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/DatabaseControlImpl.jcs
==============================================================================
--- incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/DatabaseControlImpl.jcs	(original)
+++ incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/DatabaseControlImpl.jcs	Mon Oct 18 09:26:39 2004
@@ -31,6 +31,8 @@
     private static final String ERROR_MISSING_STATEMENT_MEMBER = "Statement member not defined in SQL attribute";
     private static final String ERROR_ITERATOR_ELEMENT_TYPE_NOT_SPECIFIED = "Iterator element type is not specified.";
     private static final String ERROR_RESULT_NOT_MATCH_RETURN_TYPE = "The results of the SQL provided does not match return type of method";
+    private static final String ERROR_INVALID_ARGUMENT_NAME = "Invalid argument name in SQL statement";
+    private static final String ERROR_PARAMETER_SUBSTITUTION_FAILED = "Failed to substitute parameter by name";
 
     @org.apache.beehive.controls.api.context.Context ControlBeanContext context;
     @org.apache.beehive.controls.api.context.Context ResourceContext resourceContext;
@@ -130,7 +132,9 @@
         SQLParser parser = new SQLParser(statement);
         SQLStatement sql = parser.parse();
         //Set the parameters of the SQL statement based on the method arguments
-        sql.setParameterValues(args);
+        //sql.setParameterValuesByPosition(args);
+        this.setParameterValues(sql.getParameters(), method, args);
+
         PreparedStatement ps = sql.getPreparedStatement(this.getConnection());
 
         //Set the max. rows returned
@@ -209,4 +213,26 @@
         return returnObject;
     }
 
+	private void setParameterValues(SQLParameter[] params, Method method, Object[] args)
+	{
+		for (int i = 0; i < params.length; i++)
+		{
+			SQLParameter param = params[i];
+			String firstNameComponent = param.getFirstNameComponent();
+
+			try
+			{
+				Object value = context.getParameterValue(method, firstNameComponent, args);
+				param.setValue(value);
+			}
+			catch (IllegalArgumentException iae)
+			{
+				throw new ControlException(ERROR_INVALID_ARGUMENT_NAME);
+			}
+			catch (Exception e)
+			{
+				throw new ControlException(ERROR_PARAMETER_SUBSTITUTION_FAILED, e);
+			}
+		}
+	}
 }

Modified: incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/SQLParameter.java
==============================================================================
--- incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/SQLParameter.java	(original)
+++ incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/SQLParameter.java	Mon Oct 18 09:26:39 2004
@@ -1,21 +1,27 @@
 package org.apache.beehive.controls.test.controls.database;
 
 import java.sql.Types;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Map;
 
 /**
  * A parameter in the SQLStatment.
  */
 public class SQLParameter
 {
+	private static final String ERROR_INVOKING_GETTER_METHOD = "Failed to invoke a getter method while setting parameter value";
+	private static final String ERROR_SET_PARAMETER_VALUE_FAILED = "Failed to set parameter value";
+
     /**
      * Parameter name
      */
-    public String name;
-    
+    private String name;
+
     /**
      * Parameter value
      */
-    public Object value;
+    private Object value;
 
     /**
      * Constructor
@@ -34,11 +40,176 @@
     public SQLParameter(String name, Object value)
     {
         this.name  = name;
-        this.value = value;
+        try
+        {
+	        this.setValue(value);
+		}
+		catch (Exception e)
+		{
+			//TODO log exception
+		}
     }
 
+	/**
+	 * @return a copy of this parameter
+	 */
     public Object clone()
     {
         return new SQLParameter(name, value);
     }
+
+	/**
+	 * Sets the name of this parameter
+	 *
+	 * @param name name of the parameter
+	 */
+    public void setName(String name)
+    {
+		this.name = name;
+	}
+
+	/**
+	 * Gets the name of this parameter
+	 *
+	 * @return name of the parameter
+	 */
+	public String getName()
+	{
+		return this.name;
+	}
+
+	/**
+	 * The parameter name can be made up of multiple components.
+	 *   e.g. "employee.address.street"
+	 * This method returns each component in a String array.
+	 *   e.g. {"employee", "address", "street"}
+	 *
+	 * @return components of the parameter name
+	 */
+	public String[] getNameComponents()
+	{
+		return this.name.split("\\.");
+	}
+
+	/**
+	 * This method returns the first component in the parameter name.
+	 *   e.g. It returns "employee" when the name is "employee.address.street"
+	 *
+	 * @return the first component in the parameter name
+	 */
+	public String getFirstNameComponent()
+	{
+		String[] nameComponents = this.getNameComponents();
+		return nameComponents[0];
+	}
+
+	/**
+	 * Returns the value of this parameter.
+	 *
+	 * @return the value of this parameter
+	 */
+	public Object getValue()
+	{
+		return this.value;
+	}
+
+	/**
+	 * Sets the value of this parameter
+	 *
+	 * @param aValue value of this parameter
+	 */
+    public void setValue(Object aValue) throws Exception
+    {
+		String[] nameComponents = this.getNameComponents();
+		this.value = aValue;
+		for (int i = 1; i < nameComponents.length; i++)
+		{
+			this.value = extractValue(this.value, nameComponents[i]);
+		}
+	}
+
+	/**
+	 * Returns the value of a field in object where the name of the field matches fieldName.
+	 */
+	private Object extractValue(Object object, String fieldName) throws Exception
+	{
+		Class objectClass = object.getClass();
+		Object value = null;
+
+		String fieldNameCapped = Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
+		Method getMethod = null;
+		Method[] methods = objectClass.getMethods();
+
+		//Check if a is<fieldName>() method is available in object.
+		String methodName = "is" + fieldNameCapped;
+		for (int i = 0; i < methods.length; i++)
+		{
+			if (methods[i].getName().equals(methodName) &&
+				methods[i].getParameterTypes().length == 0 &&
+				(methods[i].getReturnType().equals(Boolean.class) ||
+				 methods[i].getReturnType().equals(Boolean.TYPE)))
+			{
+				getMethod = methods[i];
+				break;
+			}
+		}
+
+		if (getMethod == null)
+		{
+			//Check if a get<fieldName>() method is available in object.
+			methodName = "get" + fieldNameCapped;
+			for (int i = 0; i < methods.length; i++)
+			{
+				if (methods[i].getName().equals(methodName) &&
+					methods[i].getParameterTypes().length == 0)
+				{
+					getMethod = methods[i];
+					break;
+				}
+			}
+		}
+
+		//If object contains a getter method for fieldName, invoke the method
+		//to get the value of fieldName.
+		if (getMethod != null)
+		{
+			try
+			{
+				value = getMethod.invoke(object, (Object[])null);
+			}
+			catch (Exception e)
+			{
+				throw new Exception(ERROR_INVOKING_GETTER_METHOD, e);
+			}
+			return value;
+		}
+
+		//If a field named fieldName exists, return the value of this field.
+		Field[] fields = objectClass.getFields();
+		for (int i = 0; i < fields.length; i++)
+		{
+			if (fields[i].getName().equals(fieldName))
+			{
+				try
+				{
+					return fields[i].get(object);
+				}
+				catch (Exception e)
+				{
+					throw new Exception(ERROR_INVOKING_GETTER_METHOD, e);
+				}
+			}
+		}
+
+		//If object is a Map and it contains a key equals fieldName, then return the value
+		//mapped to key.
+		if (object instanceof Map && ((Map)object).containsKey(fieldName))
+		{
+			return ((Map)object).get(fieldName);
+		}
+
+		//Failed to get the value of fieldName from object.
+		throw new Exception(ERROR_SET_PARAMETER_VALUE_FAILED);
+	}
+
 }

Modified: incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/SQLStatement.java
==============================================================================
--- incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/SQLStatement.java	(original)
+++ incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/SQLStatement.java	Mon Oct 18 09:26:39 2004
@@ -158,27 +158,33 @@
         return this;
     }
 
-    /**
+    /*
      * Assigns values to the parameters in the SQL parameter by order
      * @param values values to be assigned to the SQL statement's parameters.
      * @throws ControlException
-     */
-    public void setParameterValues(Object[] values) throws Exception{
-        for (SQLParameter param : parameters) {
+
+    public void setParameterValuesByPosition(Object[] values) throws Exception{
+        for (SQLParameter param : parameters)
+        {
             int pos;
-            try {
+            try
+            {
                 pos = Integer.parseInt(param.name);
                 //offset for zero base values array.
                 pos -= 1;
-            } catch (NumberFormatException nfe) {
+            }
+            catch (NumberFormatException nfe)
+            {
                 throw new Exception("Parameter name is not an integer.", nfe);
             }
-            if (pos < 0 || pos >= values.length) {
+            if (pos < 0 || pos >= values.length)
+            {
                 throw new Exception("No argument provided for parameter: " + pos);
             }
             param.value = values[pos];
         }
     }
+	*/
 
     /**
      * This method returns a prepared statement constructed based on the
@@ -188,11 +194,12 @@
     public PreparedStatement getPreparedStatement(Connection connection) throws SQLException
     {
         PreparedStatement ps = connection.prepareStatement(getSQL());
-        for (int i = 0; i < this.parameters.size(); i++) {
+        for (int i = 0; i < this.parameters.size(); i++)
+        {
             //prepared statement index is 1-based not zero-based as the parameters list.
             int pos = i + 1;
             SQLParameter param = this.parameters.get(i);
-            PreparedStatementHelper.setPreparedStatementParameter(ps, pos, param.value, calendar);
+            PreparedStatementHelper.setPreparedStatementParameter(ps, pos, param.getValue(), calendar);
         }
         return ps;
     }

Modified: incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/test/TestDBControl.jcx
==============================================================================
--- incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/test/TestDBControl.jcx	(original)
+++ incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/test/TestDBControl.jcx	Mon Oct 18 09:26:39 2004
@@ -22,12 +22,11 @@
 
     @SQL(statement="INSERT INTO EMPLOYEE " +
                    "(id, fName, lName, title) " +
-                   "VALUES ({1}, {2}, {3}, {4})")
-    public void insertEmployee(int p_id, String p_fName, String p_lName,
-                               String p_title) throws SQLException;
+                   "VALUES ({emp.id}, {emp.fName}, {emp.lName}, {emp.title})")
+    public void insertEmployee(Employee emp) throws SQLException;
 
-    @SQL(statement="SELECT * FROM EMPLOYEE WHERE id={1}")
-    public Employee selectEmployee(int p_id) throws SQLException;
+    @SQL(statement="SELECT * FROM EMPLOYEE WHERE id={id}")
+    public Employee selectEmployee(int id) throws SQLException;
 
     @SQL(statement="SELECT * FROM EMPLOYEE ORDER BY id")
     public Employee[] selectEmployees() throws SQLException;
@@ -41,9 +40,9 @@
     @SQL(statement="SELECT * FROM EMPLOYEE ORDER BY id", maxRows=1)
     public Employee[] selectOneEmployee() throws SQLException;
 
-    @SQL(statement="UPDATE EMPLOYEE SET title = {2} WHERE id = {1}")
-    public void changeTitle(int p_id, String p_title) throws SQLException;
+    @SQL(statement="UPDATE EMPLOYEE SET title = {title} WHERE id = {id}")
+    public void changeTitle(int id, String title) throws SQLException;
 
-    @SQL(statement="DELETE FROM EMPLOYEE WHERE id = {1}")
-    public void deleteEmployee(int p_id) throws SQLException;
+    @SQL(statement="DELETE FROM EMPLOYEE WHERE id = {id}")
+    public void deleteEmployee(int id) throws SQLException;
 }

Modified: incubator/beehive/trunk/controls/test/src/drivers/org/apache/beehive/controls/test/driver/database/DriveDatabaseControl.java
==============================================================================
--- incubator/beehive/trunk/controls/test/src/drivers/org/apache/beehive/controls/test/driver/database/DriveDatabaseControl.java	(original)
+++ incubator/beehive/trunk/controls/test/src/drivers/org/apache/beehive/controls/test/driver/database/DriveDatabaseControl.java	Mon Oct 18 09:26:39 2004
@@ -92,7 +92,7 @@
 			//Insert test employees
 			for (int i = 0; i < emps.length; i++)
 			{
-				testDBControl.insertEmployee(emps[i].id, emps[i].fName, emps[i].lName, emps[i].title);
+				testDBControl.insertEmployee(emps[i]);
 			}
 
 			//Retrieve the two employees just inserted, and verify they match those

Modified: incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/database/ParserTest.java
==============================================================================
--- incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/database/ParserTest.java	(original)
+++ incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/database/ParserTest.java	Mon Oct 18 09:26:39 2004
@@ -39,8 +39,8 @@
 		SQLParameter[] params = stmt.getParameters();
 		assertNotNull(params);
 		assertEquals(2, params.length);
-		assertEquals("1", params[0].name);
-		assertEquals("2", params[1].name);
+		assertEquals("1", params[0].getName());
+		assertEquals("2", params[1].getName());
 	}
 
 	@Freq("checkin")

Modified: incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/database/SQLStatementTest.java
==============================================================================
--- incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/database/SQLStatementTest.java	(original)
+++ incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/database/SQLStatementTest.java	Mon Oct 18 09:26:39 2004
@@ -53,7 +53,8 @@
 		String fName = "Tom";
 		String lName = "Clancy";
 		String title = "Writer";
-		try {
+		try
+		{
 			int rowsInserted = insertRow(fName, lName, title);
             assertEquals(1, rowsInserted);
 			Employee emp = selectByName(fName, lName);
@@ -61,7 +62,9 @@
 			assertEquals(fName, emp.fName);
 			assertEquals(lName, emp.lName);
 			assertEquals(title, emp.title);
-		} catch (Exception e) {
+		}
+		catch (Exception e)
+		{
             assertTrue("The following error occurred in testInsert(): " + e, false);
 		}
 
@@ -72,22 +75,26 @@
 		PreparedStatement ps = null;
 		ResultSet rs = null;
 
-		try {
+		try
+		{
             int rowsInserted = insertRow(this.firstName, this.lastName, this.title);
             assertEquals(1, rowsInserted);
 	        String sql = "DELETE FROM SQLTEST_EMPLOYEE WHERE ID=?";
 	        Object[] values = {this.id};
-	        SQLParameter[] params = {new SQLParameter("1")};
+	        SQLParameter[] params = {new SQLParameter("id", this.id)};
             SQLStatement stmt = new SQLStatement(sql, params);
-            stmt.setParameterValues(values);
             ps = stmt.getPreparedStatement(con);
             int rowsDeleted = ps.executeUpdate();
 			assertEquals(1, rowsDeleted);
 			Employee emp = selectById();
 			assertNull(emp);
-        } catch (Exception e) {
+        }
+        catch (Exception e)
+        {
             assertTrue("The following error occurred in testDelete(): " + e, false);
-        } finally {
+        }
+        finally
+        {
             try { rs.close(); } catch (Throwable t) {}
             try { ps.close(); } catch (Throwable t) {}
         }
@@ -97,15 +104,18 @@
     public void testUpdate() {
         PreparedStatement ps = null;
 
-        try {
+        try
+        {
             int rowsInserted = insertRow(this.firstName, this.lastName, this.title);
             assertEquals(1, rowsInserted);
 
             String sql = "UPDATE SQLTEST_EMPLOYEE SET FNAME=? WHERE ID=?";
-            Object[] values = {this.id, this.newFirstName};
-            SQLParameter[] params = { new SQLParameter("2"), new SQLParameter("1")};
+            SQLParameter[] params =
+            	{
+					new SQLParameter("FNAME", this.newFirstName),
+    				new SQLParameter("ID", this.id)
+            	};
             SQLStatement stmt = new SQLStatement(sql, params);
-            stmt.setParameterValues(values);
             ps = stmt.getPreparedStatement(this.con);
             int rowsUpdated = ps.executeUpdate();
             assertEquals(1, rowsUpdated);
@@ -114,9 +124,13 @@
             assertNotNull(emp);
             assertEquals(this.newFirstName, emp.fName);
 
-        } catch (Exception e) {
+        }
+        catch (Exception e)
+        {
             assertTrue("The following error occurred in testUpdate(): " + e, false);
-        } finally {
+        }
+        finally
+        {
             try { ps.close(); } catch (Throwable t) {}
         }
 
@@ -125,16 +139,22 @@
     private int insertRow(String fName, String lName, String title) throws Exception
     {
         String sql = "INSERT INTO SQLTEST_EMPLOYEE (ID, FNAME, LNAME, TITLE) VALUES (?,?,?,?)";
-        Object[] values = {++this.id, fName, lName, title};
-        SQLParameter[] params = { new SQLParameter("1"), new SQLParameter("2"),
-            new SQLParameter("3"), new SQLParameter("4")};
+        SQLParameter[] params =
+        	{
+				new SQLParameter("ID", ++this.id),
+				new SQLParameter("FNAME", fName),
+            	new SQLParameter("LNAME", lName),
+            	new SQLParameter("TITLE", title)
+            };
         PreparedStatement ps = null;
-        try {
+        try
+        {
             SQLStatement stmt = new SQLStatement(sql, params);
-            stmt.setParameterValues(values);
             ps = stmt.getPreparedStatement(con);
             return ps.executeUpdate();
-        } finally {
+        }
+        finally
+        {
             try { ps.close(); } catch (Throwable t) {}
         }
 
@@ -145,13 +165,15 @@
         PreparedStatement ps = null;
         ResultSet rs = null;
 
-        try {
-            String sql = "SELECT * FROM SQLTEST_EMPLOYEE WHERE fName=? and lName=?";
-            String[] values = {fName, lName};
-            SQLParameter[] params = { new SQLParameter("1"), new SQLParameter("2")};
-
+        try
+        {
+            String sql = "SELECT * FROM SQLTEST_EMPLOYEE WHERE FNAME=? and LNAME=?";
+            SQLParameter[] params =
+            	{
+					new SQLParameter("FNAME", fName),
+					new SQLParameter("LNAME", lName)
+				};
             SQLStatement stmt = new SQLStatement(sql, params);
-            stmt.setParameterValues(values);
             ps = stmt.getPreparedStatement(con);
             rs = ps.executeQuery();
 
@@ -160,7 +182,9 @@
             else
                 return null;
 
-        } finally {
+        }
+        finally
+        {
             try { rs.close(); } catch (Throwable t) {}
             try { ps.close(); } catch (Throwable t) {}
         }
@@ -172,13 +196,13 @@
         PreparedStatement ps = null;
         ResultSet rs = null;
 
-        try {
+        try
+        {
             String sql = "SELECT * FROM SQLTEST_EMPLOYEE WHERE ID=?";
-            Object[] values = {new Integer(this.id)};
-            SQLParameter[] params = { new SQLParameter("1")};
+            SQLParameter[] params =
+            	{ new SQLParameter("ID", new Integer(this.id))};
 
             SQLStatement stmt = new SQLStatement(sql, params);
-            stmt.setParameterValues(values);
             ps = stmt.getPreparedStatement(con);
             rs = ps.executeQuery();
 
@@ -187,7 +211,9 @@
             else
                 return null;
 
-        } finally {
+        }
+        finally
+        {
             try { rs.close(); } catch (Throwable t) {}
             try { ps.close(); } catch (Throwable t) {}
         }
@@ -197,10 +223,13 @@
     private static Connection getConnection() {
 
         Connection con = null;
-        try {
+        try
+        {
             Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
             con = DriverManager.getConnection("jdbc:derby:build/databaseControlTestDB;create=true");
-        } catch (Exception e) {
+        }
+        catch (Exception e)
+        {
             e.printStackTrace();
         }
         return con;
@@ -212,13 +241,18 @@
                    "FNAME VARCHAR(20), LNAME VARCHAR(20), TITLE VARCHAR(15))";
 
         PreparedStatement ps = null;
-        try {
+        try
+        {
             SQLStatement stmt = new SQLStatement(sql);
             ps = stmt.getPreparedStatement(con);
             ps.execute();
-        } catch (Exception e) {
+        }
+        catch (Exception e)
+        {
             assertTrue("The following error occurred in createTable(): " + e, false);
-        } finally {
+        }
+        finally
+        {
             try { ps.close(); } catch (Throwable t) {}
         }
     }
@@ -226,13 +260,18 @@
     private void dropTable() {
         String sql = "DROP TABLE SQLTEST_EMPLOYEE";
         PreparedStatement ps = null;
-        try {
+        try
+        {
             SQLStatement stmt = new SQLStatement(sql);
             ps = stmt.getPreparedStatement(con);
             ps.execute();
-        } catch (Exception e) {
+        }
+        catch (Exception e)
+        {
             //ignore
-        } finally {
+        }
+        finally
+        {
             try { ps.close(); } catch (Throwable t) {}
         }
     }
@@ -243,7 +282,8 @@
         public String lName;
         public String title;
 
-        public Employee(String fName, String lName, String title) {
+        public Employee(String fName, String lName, String title)
+        {
 			this.fName = fName;
 			this.lName = lName;
 			this.title = title;