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/06 01:12:31 UTC

svn commit: rev 53833 - in incubator/beehive/trunk/controls/test: . src/controls/org/apache/beehive/controls/test/controls/database src/controls/org/apache/beehive/controls/test/controls/database/test src/controls/org/apache/beehive/controls/test/controls/database/util src/drivers/org/apache/beehive/controls/test/driver/database src/units/org/apache/beehive/controls/test/java/database src/units/org/apache/beehive/controls/test/jpf/database webapps webapps/controlsWeb webapps/controlsWeb/database

Author: kentam
Date: Tue Oct  5 16:12:30 2004
New Revision: 53833

Added:
   incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/
   incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/DatabaseControl.java   (contents, props changed)
   incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/DatabaseControlImpl.jcs   (contents, props changed)
   incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/ResultSetExtractor.java   (contents, props changed)
   incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/SQLParameter.java   (contents, props changed)
   incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/SQLParser.java   (contents, props changed)
   incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/SQLStatement.java   (contents, props changed)
   incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/test/
   incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/test/Employee.java   (contents, props changed)
   incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/test/TestDBControl.jcx   (contents, props changed)
   incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/util/
   incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/util/JavaTypeHelper.java   (contents, props changed)
   incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/util/PreparedStatementHelper.java   (contents, props changed)
   incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/util/ResultSetHelper.java   (contents, props changed)
   incubator/beehive/trunk/controls/test/src/drivers/org/apache/beehive/controls/test/driver/database/
   incubator/beehive/trunk/controls/test/src/drivers/org/apache/beehive/controls/test/driver/database/DriveDatabaseControl.java   (contents, props changed)
   incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/database/
   incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/database/Car.java   (contents, props changed)
   incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/database/ParserTest.java   (contents, props changed)
   incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/database/ResultSetExtractorTest.java   (contents, props changed)
   incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/database/SQLStatementTest.java   (contents, props changed)
   incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/jpf/database/
   incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/jpf/database/TestDatabaseControl.java   (contents, props changed)
   incubator/beehive/trunk/controls/test/webapps/controlsWeb/database/
   incubator/beehive/trunk/controls/test/webapps/controlsWeb/database/Controller.jpf   (contents, props changed)
Modified:
   incubator/beehive/trunk/controls/test/build.xml
   incubator/beehive/trunk/controls/test/webapps/build.xml
   incubator/beehive/trunk/controls/test/webapps/controlsWeb/app.properties
Log:
Integration of Derby database and initial implementation/tests for a database (JDBC) control.

Contributed by: Hoi Lam (hlam@bea.com)



Modified: incubator/beehive/trunk/controls/test/build.xml
==============================================================================
--- incubator/beehive/trunk/controls/test/build.xml	(original)
+++ incubator/beehive/trunk/controls/test/build.xml	Tue Oct  5 16:12:30 2004
@@ -55,6 +55,7 @@
         <pathelement location="${velocity14.jar}"/>
         <pathelement location="${velocitydep14.jar}"/>
         <pathelement location="${servlet24.jar}"/>
+        <pathelement location="${derby.jar}"/>
         <pathelement path="../build/jars/controls.jar"/>
         <pathelement path="${build.beans}"/>
     </path>
@@ -72,6 +73,7 @@
         <pathelement location="${velocity14.jar}"/>
         <pathelement location="${velocitydep14.jar}"/>
         <pathelement location="${servlet24.jar}"/>
+        <pathelement location="${derby.jar}"/>
         <pathelement location="../build/jars/controls.jar"/>
         <pathelement path="${build.beans}"/>
 	

Added: incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/DatabaseControl.java
==============================================================================
--- (empty file)
+++ incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/DatabaseControl.java	Tue Oct  5 16:12:30 2004
@@ -0,0 +1,64 @@
+package org.apache.beehive.controls.test.controls.database;
+
+import org.apache.beehive.controls.api.bean.AnnotationConstraints;
+import org.apache.beehive.controls.api.bean.AnnotationMemberTypes.*;
+import org.apache.beehive.controls.api.bean.AnnotationMemberTypes;
+import org.apache.beehive.controls.api.bean.ControlInterface;
+import org.apache.beehive.controls.api.bean.ControlInterface;
+import org.apache.beehive.controls.api.properties.PropertySet;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.sql.Connection;
+import java.util.Calendar;
+
+@ControlInterface
+public interface DatabaseControl
+{
+
+    /**
+     * This constant can be used as the value for the maxRows member of the SQL PropertySet.
+     * It indicates that all rows should be returned (i.e. no limit)
+     */
+    public final int MAXROWS_ALL = -1;
+
+    /**
+     * This class acts as a default value for the iteratorElementType member of the
+     * SQL PropertySet.  It signals that no type has been defined for the method
+     * (common if the method return type isn't itself an iterator)
+     */
+    public interface UndefinedIteratorType {}
+
+
+    @PropertySet
+    @Inherited
+    @AnnotationConstraints.AllowExternalOverride
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ElementType.TYPE, ElementType.FIELD})
+    public @interface ConnectionDataSource
+    {
+    	String jndiName();   // no default ... value is required
+    }
+
+    @PropertySet
+    @Inherited
+    @Retention(RetentionPolicy.RUNTIME)
+    @AnnotationConstraints.AllowExternalOverride // not sure we want to do this
+    @Target( { ElementType.METHOD } )
+    public @interface SQL
+    {
+        String statement()              default "";
+        int maxRows()                   default MAXROWS_ALL;
+        @AnnotationMemberTypes.Optional
+        Class iteratorElementType()     default UndefinedIteratorType.class;
+
+    }
+
+    public Calendar getDataSourceCalendar();
+
+    public void setDataSourceCalendar(Calendar cal);
+
+    public Connection getConnection();
+}

Added: incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/DatabaseControlImpl.jcs
==============================================================================
--- (empty file)
+++ incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/DatabaseControlImpl.jcs	Tue Oct  5 16:12:30 2004
@@ -0,0 +1,212 @@
+package org.apache.beehive.controls.test.controls.database;
+
+import java.lang.reflect.Method;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Calendar;
+import java.util.Iterator;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+import javax.naming.InitialContext;
+import org.apache.beehive.controls.api.ControlException;
+import org.apache.beehive.controls.api.bean.ControlImplementation;
+import org.apache.beehive.controls.api.bean.Extensible;
+import org.apache.beehive.controls.api.context.ControlBeanContext;
+import org.apache.beehive.controls.api.context.ResourceContext;
+import org.apache.beehive.controls.api.ControlException;
+import org.apache.beehive.controls.api.context.ResourceContext.ResourceEvents;
+import org.apache.beehive.controls.api.events.EventHandler;
+import org.apache.beehive.controls.test.controls.database.util.JavaTypeHelper;
+
+@ControlImplementation
+public class DatabaseControlImpl implements DatabaseControl, Extensible
+{
+	//Error messages
+    private static final String ERROR_GET_DATABASE_CONTROL = "Failed to obtain database control.";
+    private static final String ERROR_MISSING_SQL_ATTRIBUTE = "SQL attribute not defined.";
+    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";
+
+    @org.apache.beehive.controls.api.context.Context ControlBeanContext context;
+    @org.apache.beehive.controls.api.context.Context ResourceContext resourceContext;
+
+    transient Calendar calendar = null;
+    transient Connection connection = null;
+    Vector resources = new Vector();
+
+    public Calendar getDataSourceCalendar()
+    {
+        return calendar;
+    }
+
+    public void setDataSourceCalendar(Calendar cal)
+    {
+        this.calendar = (Calendar)cal.clone();
+    }
+
+    public Connection getConnection()
+    {
+        if (this.connection == null)
+        {
+			DatabaseControl.ConnectionDataSource ds =
+						(ConnectionDataSource)context.getControlPropertySet(ConnectionDataSource.class);
+			if (ds == null)
+				throw new ControlException("no @" + ConnectionDataSource.class.getName() + "\' property found.");
+
+			//TODO: Need to change this code to use data source.
+            try {
+                Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
+                this.connection = DriverManager.getConnection(ds.jndiName());
+            } catch (Exception e) {
+                throw new ControlException(ERROR_GET_DATABASE_CONTROL, e);
+            }
+        }
+        return this.connection;
+    }
+
+    @EventHandler(field="resourceContext",eventSet=ResourceEvents.class, eventName="onRelease")
+    public void onRelease()
+    {
+        for (int i = 0 ; i < this.resources.size() ; i++)
+        {
+            Object o = this.resources.get(i);
+            if (o instanceof PreparedStatement)
+            {
+                try {
+                    ((PreparedStatement)o).close();
+                }
+                catch (SQLException sqe) {
+                    //TODO: log error closing prepared statement.
+                }
+            }
+            else
+            {
+                //TODO: log unexpected resource type
+            }
+        }
+        resources.clear();
+
+        try {
+            if (this.connection != null)
+                this.connection.close();
+        } catch (SQLException sqe) {
+            //TODO: log error closing connection
+        }
+
+        this.connection = null;
+    }
+
+    @EventHandler(field="resourceContext",eventSet=ResourceEvents.class, eventName="onAcquire")
+    public void onAcquire()
+    {
+        try {
+            getConnection();
+        }
+        catch (ControlException e) {
+			//TODO: log error
+        }
+    }
+
+    /**
+     * Extensible.invoke
+     * Handles all extended interface methods
+     */
+    public Object invoke(Method method, Object[] args) throws Throwable
+    {
+		//Retrieve the SQL statement from the STATEMENT member of the SQL attribute.
+        SQL methodSQL = (SQL)context.getMethodPropertySet(method, SQL.class);
+        if (methodSQL == null)
+            throw new ControlException (ERROR_MISSING_SQL_ATTRIBUTE);
+        String statement = methodSQL.statement();
+        if (statement == null || statement.length() == 0)
+            throw new ControlException (ERROR_MISSING_STATEMENT_MEMBER);
+
+		//Parse the SQL statement
+        SQLParser parser = new SQLParser(statement);
+        SQLStatement sql = parser.parse();
+        //Set the parameters of the SQL statement based on the method arguments
+        sql.setParameterValues(args);
+        PreparedStatement ps = sql.getPreparedStatement(this.getConnection());
+
+        //Set the max. rows returned
+        int maxRows = methodSQL.maxRows();
+        if (maxRows != MAXROWS_ALL && maxRows > 0)
+            ps.setMaxRows(maxRows);
+
+        boolean hasResults = ps.execute();
+
+        //
+        // process returned data
+        //
+        Class returnType = method.getReturnType();
+
+        Object returnObject = null;
+
+        if (hasResults)
+        {
+            // If a result must live beyond the lifetime of this
+            // 'invoke', the statement must be kept open and
+            // closed later.
+            ResultSet rs = ps.getResultSet();
+            if (returnType.equals(ResultSet.class))
+            {
+                this.resources.add(ps);
+                returnObject = rs;
+            }
+            else
+            {
+                ResultSetExtractor extractor = new ResultSetExtractor(rs, this.calendar);
+                //return iterator
+                if (returnType.equals(Iterator.class))
+                {
+                    this.resources.add(ps);
+                    Class iteratorElement = methodSQL.iteratorElementType();
+                    if (null == iteratorElement)
+                        throw new Exception(ERROR_ITERATOR_ELEMENT_TYPE_NOT_SPECIFIED);
+                    returnObject = extractor.extractIterator(iteratorElement);
+                }
+                //return array
+                else if (returnType.isArray())
+                {
+                    returnObject = extractor.extractArray(returnType);
+                }
+                //return HashMap
+		        else if (returnType.equals(HashMap.class))
+            	{
+                	returnObject = extractor.extractHashMap();
+            	}
+            	//return an unmodifiable view of the HashMap
+            	else if (returnType.equals(Map.class))
+            	{
+            	    returnObject = extractor.extractUnmodifiableMap();
+            	}
+
+                else
+                {
+                    if (!rs.next())
+                    //return null or if return type is a primitive, return the primitive's default value.
+                        returnObject = JavaTypeHelper.getJaveTypeDefaultValue(returnType);
+                    else
+                    //return object
+                        returnObject = extractor.extractObject(returnType);
+                }
+            }
+        }
+        else {
+            if (returnType.equals(Void.TYPE))
+                returnObject = null;
+            else if (!returnType.equals(Integer.TYPE))
+                throw new ControlException(ERROR_RESULT_NOT_MATCH_RETURN_TYPE);
+
+            returnObject = new Integer(ps.getUpdateCount());
+        }
+
+        return returnObject;
+    }
+
+}

Added: incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/ResultSetExtractor.java
==============================================================================
--- (empty file)
+++ incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/ResultSetExtractor.java	Tue Oct  5 16:12:30 2004
@@ -0,0 +1,368 @@
+package org.apache.beehive.controls.test.controls.database;
+
+//import org.apache.beehive.controls.api.ControlException;
+import org.apache.beehive.controls.test.controls.database.util.JavaTypeHelper;
+import org.apache.beehive.controls.test.controls.database.util.ResultSetHelper;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Field;
+import java.sql.ResultSetMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.GregorianCalendar;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.logging.Logger;
+
+/**
+ * This class extracts the the content of a ResultSet into various forms of
+ * object (e.g. an Iterator, HashMap, etc)
+ */
+public class ResultSetExtractor
+{
+    //Error messages
+    private static final String ERROR_SETTING_FIELD = "Error occurred while setting a value from the database to class field.";
+    private static final String ERROR_SETTING_ARRAY = "Error occurred while adding an elment to array.";
+    private static final String ERROR_NO_TYPE_SPECIFIED_FOR_EXTRACT_OBJECT = "Object type not specified when extracting object from ResultSet.";
+    private static final String ERROR_NO_TYPE_SPECIFIED_FOR_EXTRACT_ITERATOR = "Iterator element type not specified when extracting iterator from ResultSet.";
+
+    //ResultSet to extract data from
+    ResultSet rs;
+    //Meta data of the resultset.
+    ResultSetMetaData rsMetaData;
+    //Calendar used for working with dates.
+    protected GregorianCalendar cal;
+
+    //Column count of the resultset
+    int columnCount;
+
+    //Name of columns in the resultset
+    String[] columnNames = null;
+
+    // Field or Method
+    AccessibleObject[] fields = null;
+
+    /**
+     * Constructor
+     * @param rs the resultset to exrract data from
+     * @param cal the calendar to use when working with dates
+     */
+    public ResultSetExtractor(ResultSet rs, Calendar cal) throws SQLException
+    {
+        this.rs = rs;
+        this.columnCount = rs.getMetaData().getColumnCount();
+        this.rsMetaData = rs.getMetaData();
+        this.columnNames = new String[columnCount + 1];
+        for (int i = 1 ; i <= columnCount ; i++)
+            this.columnNames[i] = this.rsMetaData.getColumnName(i).toUpperCase();
+
+    }
+
+    private Map<String, AccessibleObject> getColumnNameToFieldMap(Class objectType) throws SQLException
+    {
+        HashMap<String, AccessibleObject> columnNameToFieldMap =
+            new HashMap<String, AccessibleObject>(columnCount * 2);
+
+        //Add names of all column from resultset to map.
+        for (int i = 1 ; i <= columnCount ; i++)
+            columnNameToFieldMap.put(columnNames[i], null);
+
+        //Map the class fields to column names in the map.
+        for (Class clazz = objectType ; null != clazz && Object.class != clazz ; clazz = clazz.getSuperclass())
+        {
+            Field[] classFields = clazz.getDeclaredFields();
+            if (null != classFields)
+                for (int i = 0 ; i < classFields.length ; i++)
+                {
+                    Field f = classFields[i];
+                    if (Modifier.isStatic(f.getModifiers()))
+                        continue;
+                    String fieldName = f.getName().toUpperCase();
+                    if (!columnNameToFieldMap.containsKey(fieldName))
+                        continue;
+                    columnNameToFieldMap.put(fieldName, f);
+                }
+        }
+
+        //Map the class's attribute setter methods to column names in the map.
+        Method[] classMethods = objectType.getMethods();
+        if (null != classMethods)
+            for (int i = 0 ; i < classMethods.length ; i++)
+            {
+                Method m = classMethods[i];
+                String methodName = m.getName();
+                if (methodName.length() < 4 || !methodName.startsWith("set"))
+                    continue;
+                if (!Character.isUpperCase(methodName.charAt(3)))
+                    continue;
+                String fieldName = methodName.substring(3).toUpperCase();
+                if (!columnNameToFieldMap.containsKey(fieldName))
+                    continue;
+                if (Modifier.isStatic(m.getModifiers()))
+                    continue;
+                Class[] params = m.getParameterTypes();
+                if (1 != params.length)
+                    continue;
+                if (Types.OTHER == JavaTypeHelper.getSqlType(params[0]))
+                    continue;
+                if (!Void.TYPE.equals(m.getReturnType()))
+                    continue;
+                // check for overloads
+                Object field = columnNameToFieldMap.get(fieldName);
+                if (null != field)
+                    continue;
+                columnNameToFieldMap.put(fieldName, m);
+            }
+        return columnNameToFieldMap;
+    }
+
+    /**
+     * Extracts the data of the resultset into a array of a specified
+     * type.
+     * @param arrayClass array type
+     * @return array of the specified type
+     */
+    public Object extractArray(Class arrayClass) throws Exception{
+
+        Class componentType = arrayClass.getComponentType();
+
+        ArrayList list = new ArrayList();
+
+        while(rs.next())
+        {
+            list.add(extractObject(componentType));
+        }
+
+        Object array = java.lang.reflect.Array.newInstance(componentType, list.size());
+
+        try
+        {
+            for (int i = 0 ; i < list.size() ; i++)
+                java.lang.reflect.Array.set(array, i, list.get(i));
+        }
+        catch (IllegalArgumentException iae)
+        {
+            throw new Exception(ERROR_SETTING_ARRAY, iae);
+        }
+        return array;
+
+    }
+
+    /**
+     * Extracts the data of a resultset into an iterator of a specified type.
+     * @param iteratorElementType type of the elements in the iterator
+     * @return an iterator with elements of the specified type.
+     */
+    public Iterator extractIterator(Class iteratorElementType) throws Exception
+    {
+        return new ResultSetIterator(iteratorElementType);
+    }
+
+    /**
+     * Extracts one row of data from a resultset into a HashMap with
+     * the column names as keys.
+     * @return column name to value map of a row from the resultset.
+     */
+    public HashMap<String, Object> extractHashMap() throws Exception
+    {
+        return new ResultSetHashMap();
+    }
+
+    /**
+     * Extracts one row of data from a resultset into a unmodifiable
+     * map with the column names as keys.
+     * @return column name to value map of a row from the resultset.
+     */
+    public Map<String, Object> extractUnmodifiableMap() throws Exception
+    {
+	    return Collections.unmodifiableMap(new ResultSetHashMap());
+	}
+
+    /**
+     * Extracts one row of data into an object of a specified type.
+     * @param returnClass type of object to extract the data to
+     * @return an object of the specified type
+     */
+    public Object extractObject(Class returnClass) throws Exception
+    {
+        if (returnClass == null)
+        {
+            throw new Exception(ERROR_NO_TYPE_SPECIFIED_FOR_EXTRACT_OBJECT);
+        }
+
+        if (columnCount == 1)
+        {
+            Object val = ResultSetHelper.readValue(rs, columnNames[1], returnClass.getClass(), cal);
+            if (returnClass.isAssignableFrom(val.getClass()))
+            {
+                return val;
+            }
+        }
+
+        // calculate reflection information
+        Map<String, AccessibleObject> columnNameToFieldMap = getColumnNameToFieldMap(returnClass);
+
+        Object resultObject = returnClass.newInstance();
+
+        // array used for method.invoke()
+        Object[] args = new Object[1];
+
+        Set<String> columnNames = columnNameToFieldMap.keySet();
+
+        for (String columnName : columnNames)
+        {
+            AccessibleObject accessibleObj = columnNameToFieldMap.get(columnName);
+
+            if (accessibleObj == null)
+                continue;
+
+            try
+            {
+                if (accessibleObj instanceof Field)
+                {
+                    Object resultValue = ResultSetHelper.readValue(rs, columnName, ((Field)accessibleObj).getType(), cal);
+                    ((Field)accessibleObj).set(resultObject, resultValue);
+                }
+                else
+                {
+                    Object resultValue = ResultSetHelper.readValue(rs, columnName, ((Method)accessibleObj).getParameterTypes()[0], cal);
+                    args[0] = resultValue;
+                    ((Method)accessibleObj).invoke(resultObject, args);
+                }
+            }
+            catch (IllegalArgumentException iae)
+            {
+                throw new Exception(ERROR_SETTING_FIELD, iae);
+            }
+        }
+        return resultObject;
+    }
+
+    /**
+     * The ResultSetHashMap class extends a standard HashMap and
+     * populates it with data derived from a JDBC ResultSet.
+     * <p>
+     * Note: the keys are treated case-insensitively, and therefore requests
+     * made on the map are case-insensitive.  Any direct access to the keys
+     * will yield uppercase keys.
+     * <p>
+     * Note: only the row associated with the current cursor position
+     * is used.
+     */
+    private class ResultSetHashMap extends HashMap<String, Object>
+    {
+        ResultSetHashMap() throws Exception
+        {
+            super();
+
+            ResultSetMetaData md = rs.getMetaData();
+           	if (rs.next())
+           	{
+				for (int i = 1 ; i <= md.getColumnCount() ; i++)
+				{
+					super.put(md.getColumnName(i).toUpperCase(), rs.getObject(i));
+				}
+			}
+        }
+
+
+        public boolean containsKey(Object key)
+        {
+            if (key instanceof String)
+                key = ((String)key).toUpperCase();
+            return super.containsKey(key);
+        }
+
+
+        public Object get(Object key)
+        {
+            if (key instanceof String)
+                key = ((String)key).toUpperCase();
+            return super.get(key);
+        }
+
+
+        public Object put(String key, Object value)
+        {
+            key = key.toUpperCase();
+            return super.put(key, value);
+        }
+
+
+        public Object remove(String key)
+        {
+                key = key.toUpperCase();
+            return super.remove(key);
+        }
+    }
+
+    private class ResultSetIterator implements Iterator {
+
+        Class iteratorElementType;
+        boolean primed = false;
+
+        ResultSetIterator(Class iteratorElementType) throws Exception
+        {
+            if (iteratorElementType == null)
+                throw new Exception(ERROR_NO_TYPE_SPECIFIED_FOR_EXTRACT_ITERATOR);
+
+            this.iteratorElementType = iteratorElementType;
+        }
+
+        public boolean hasNext()
+        {
+            if (primed)
+                return true;
+            try
+            {
+                primed = rs.next();
+            }
+            catch (SQLException sqle)
+            {
+                return false;
+            }
+
+            return primed;
+        }
+
+
+        public Object next()
+        {
+            try
+            {
+                if (!primed)
+                {
+                    primed = rs.next();
+                    if (!primed)
+                        throw new NoSuchElementException();
+                }
+                // reset upon consumption
+                primed = false;
+                return extractObject(iteratorElementType);
+            }
+            catch (Exception e)
+            {
+                // Since Iterator interface is locked, all we can do
+                // is put the real exception inside an expected one.
+                NoSuchElementException xNoSuch = new NoSuchElementException("ResultSet exception: " + e);
+                xNoSuch.initCause(e);
+                throw xNoSuch;
+            }
+        }
+
+        public void remove()
+        {
+            throw new UnsupportedOperationException("remove not supported");
+        }
+    }
+
+
+}

Added: incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/SQLParameter.java
==============================================================================
--- (empty file)
+++ incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/SQLParameter.java	Tue Oct  5 16:12:30 2004
@@ -0,0 +1,44 @@
+package org.apache.beehive.controls.test.controls.database;
+
+import java.sql.Types;
+
+/**
+ * A parameter in the SQLStatment.
+ */
+public class SQLParameter
+{
+    /**
+     * Parameter name
+     */
+    public String name;
+    
+    /**
+     * Parameter value
+     */
+    public Object value;
+
+    /**
+     * Constructor
+     * @param name of the parameter
+     */
+    public SQLParameter(String name)
+    {
+        this.name = name;
+    }
+
+    /**
+     * Constructor
+     * @param name name of parameter
+     * @param value value of parameter
+     */
+    public SQLParameter(String name, Object value)
+    {
+        this.name  = name;
+        this.value = value;
+    }
+
+    public Object clone()
+    {
+        return new SQLParameter(name, value);
+    }
+}

Added: incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/SQLParser.java
==============================================================================
--- (empty file)
+++ incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/SQLParser.java	Tue Oct  5 16:12:30 2004
@@ -0,0 +1,125 @@
+package org.apache.beehive.controls.test.controls.database;
+
+/**
+ * This class parses the statement member of the SQL annotation in the
+ * Database Control into a SQLStatement object.
+ */
+public class SQLParser
+{
+    //Error messages.
+    private static final String ERROR_MISSING_QUOTE = "A quote is missing from SQL statement.";
+    private static final String ERROR_MISSING_BRACE = "A closing brace is missing from SQL statement.";
+    private static final String ERROR_UNEXPECTED_BRACE = "An unexpected closing brace found in SQL statement.";
+
+    //Points to a position in the SQL statement during parsing.
+    private int position = 0;
+
+    //The statement member in a SQL annotation.
+    private String statement;
+
+    /**
+     * Constructor
+     * @param stmt the statement member of a SQL annotation.
+     */
+    public SQLParser(String stmt)
+    {
+        this.statement = stmt;
+    }
+
+	/**
+	 * Specifies the statement member of a SQL annotation to parse.
+	 * @param stmt the statment member of a SQL annotation.
+	 */
+    public void setStatement(String stmt) {
+		this.statement = stmt;
+	}
+
+    /**
+     * Parse a statement member of a SQL annotation into a SQLStatement
+     * object
+     * @return the SQLStatement representing of statement
+     */
+    public SQLStatement parse() throws Exception
+    {
+        SQLStatement sql = new SQLStatement();
+        parseStatement(sql);
+
+        if (-1 != position)
+            throw new Exception(ERROR_UNEXPECTED_BRACE);
+
+        return sql;
+    }
+
+
+    private void parseEscape(SQLStatement stmt) throws Exception
+    {
+        int i = findOneOf(statement, " :}", position);
+
+        int closeBrace = statement.indexOf('}', position);
+
+        if (closeBrace < 0)
+            throw new Exception(ERROR_MISSING_BRACE);
+
+        String paramName = statement.substring(position, closeBrace);
+        this.position = closeBrace;
+        stmt.addParameter(new SQLParameter(paramName));
+
+        if (-1 == position || statement.charAt(position) != '}')
+            throw new Exception(ERROR_MISSING_BRACE);
+
+        this.position++;
+    }
+
+    /**
+     * bascially just accept everything as-is, only looking for escapes
+     * only need to recognize SQL strings properly
+     */
+    private void parseStatement(SQLStatement stmt)
+            throws Exception
+    {
+        int index = position;
+        while ((index = findOneOf(statement, "{'}", index)) >= 0)
+        {
+            char ch = statement.charAt(index);
+
+            if (ch == '\'')
+            {
+                index = statement.indexOf('\'', index + 1);
+                if (-1 == index)
+                {
+                    throw new Exception(ERROR_MISSING_QUOTE);
+                }
+                index++;
+                continue;
+            }
+
+            //Append to stmt text up-to, but not including { or }
+            stmt.append(statement.substring(position, index));
+            position = index;
+
+            if (ch == '}')
+                break;
+                
+            this.position++;
+            parseEscape(stmt);
+            index = this.position;
+        }
+
+        if (-1 == index)
+        {
+            stmt.append(statement.substring(position));
+            this.position = -1;
+        }
+    }
+
+    static int findOneOf(String s, String chars, int i)
+    {
+        if (i == -1)
+            return -1;
+        for (; i < s.length() ; i++)
+            if (-1 != chars.indexOf(s.charAt(i)))
+                return i;
+        return -1;
+    }
+
+}

Added: incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/SQLStatement.java
==============================================================================
--- (empty file)
+++ incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/SQLStatement.java	Tue Oct  5 16:12:30 2004
@@ -0,0 +1,216 @@
+package org.apache.beehive.controls.test.controls.database;
+
+import org.apache.beehive.controls.test.controls.database.util.PreparedStatementHelper;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * This class holds a SQL statement and its parameters.
+ */
+public class SQLStatement
+{
+    transient Calendar calendar = null;
+    protected CharSequence sql;
+    protected List<SQLParameter> parameters;
+
+    /**
+     * Default constructor
+     */
+    public SQLStatement()
+    {
+        super();
+        sql = new StringBuffer();
+        parameters = new _ArrayList();
+    }
+
+    /**
+     * Constructor
+     * @param a SQL statement
+     */
+    public SQLStatement(String sql)
+    {
+        if (sql != null)
+            this.sql = sql;
+        else
+            this.sql = new StringBuffer();
+
+        this.parameters = new _ArrayList();
+    }
+
+    /**
+     * Constructor
+     * @param a SQL statement
+     * @param parameters parameters of the SQL statement
+     */
+    public SQLStatement(String sql, SQLParameter[] parameters)
+    {
+        if (sql != null)
+            this.sql = sql;
+        else
+            this.sql = new StringBuffer();
+
+        this.parameters = parameters != null ? Arrays.asList(parameters) : new _ArrayList();
+    }
+
+    /**
+     * Constructor
+     * @param sql SQL statement
+     * @param parameters parameters of the SQL statement
+     * @param cal calendar for processing dates in the SQL statment.
+     */
+    public SQLStatement(String sql, SQLParameter[] parameters, Calendar cal)
+    {
+        if (sql != null)
+            this.sql = sql;
+        else
+            this.sql = new StringBuffer();
+
+        this.parameters = parameters != null ? Arrays.asList(parameters) : new _ArrayList();
+        this.calendar = cal;
+    }
+
+    /**
+     * Returns the SQL statement of this class
+     * @return a sql statement
+     */
+    public String getSQL()
+    {
+        return sql.toString();
+    }
+
+    /**
+     * Returns the parameters of the SQL statement in this class
+     * @return parameters of the SQL statement in this class
+     */
+    public SQLParameter[] getParameters()
+    {
+        if (null == parameters)
+            return new SQLParameter[0];
+        return (SQLParameter[])parameters.toArray(new SQLParameter[parameters.size()]);
+    }
+
+    /**
+     * Returns the SQL statement of this class
+     * @return a sql statement
+     */
+    public String toString()
+    {
+        return sql.toString();
+    }
+
+    /**
+     * Inserts a string into this SQL statement.
+     * @param offset the offset
+     * @param str the string
+     * @return a reference to this object
+     */
+    public SQLStatement insert(int offset, String str)
+    {
+        ((StringBuffer)sql).insert(offset, str);
+        return this;
+    }
+
+    /**
+     * Adds a parameter to this SQL statement
+     * @param param a SQL parameter
+     * @return a reference to this object.
+     */
+    protected SQLStatement addParameter(SQLParameter param)
+    {
+        try { ((StringBuffer)sql).append('?'); } catch (Exception ignore) {}
+        parameters.add(param);
+        return this;
+    }
+
+    /**
+     * Adds a collection of paramters to this sql statement
+     * @param params a collection of SQL parameters
+     */
+    protected void addAll(Collection<SQLParameter> params)
+    {
+        if (null == params)
+            return;
+        parameters.addAll(params);
+    }
+
+    /**
+     * Appends a seqence of characters to the SQL statement
+     */
+    public SQLStatement append(CharSequence sb)
+    {
+        try { ((StringBuffer)sql).append(sb); } catch (Exception ignore) {}
+        return this;
+    }
+
+    /**
+     * Appends a character to the SQL statement
+     */
+    public SQLStatement append(char c)
+    {
+        try { ((StringBuffer)sql).append(c); } catch (Exception ignore) {}
+        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) {
+            int pos;
+            try {
+                pos = Integer.parseInt(param.name);
+                //offset for zero base values array.
+                pos -= 1;
+            } catch (NumberFormatException nfe) {
+                throw new Exception("Parameter name is not an integer.", nfe);
+            }
+            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
+     * attributes of the class.
+     * @ return a prepared statement with its SQL statement and parameters set.
+     */
+    public PreparedStatement getPreparedStatement(Connection connection) throws SQLException
+    {
+        PreparedStatement ps = connection.prepareStatement(getSQL());
+        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);
+        }
+        return ps;
+    }
+
+    private class _ArrayList extends ArrayList
+    {
+        public void setSize(int size)
+        {
+            ensureCapacity(size);
+            while (size() < size)
+                add(null);
+        }
+        public Object set(int i, Object o)
+        {
+            if (i >= size())
+                setSize(i+1);
+            return super.set(i,o);
+        }
+    }
+
+}

Added: incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/test/Employee.java
==============================================================================
--- (empty file)
+++ incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/test/Employee.java	Tue Oct  5 16:12:30 2004
@@ -0,0 +1,49 @@
+package org.apache.beehive.controls.test.controls.database.test;
+
+public class Employee
+{
+	public int id;
+	public String fName;
+	public String lName;
+	public String title;
+
+	public Employee() {
+		super();
+	}
+
+	public Employee(int id, String fName, String lName, String title) {
+		this.id = id;
+		this.fName = fName;
+		this.lName = lName;
+		this.title = title;
+	}
+
+	public String toString()
+	{
+		return "[" + id + "," + fName + "," + lName + "," + title + "] ";
+	}
+
+	public boolean equals(Object obj) {
+		if (obj == null || !(obj instanceof Employee))
+			return false;
+
+		Employee emp = (Employee)obj;
+
+		if (this.id != emp.id)
+			return false;
+		else if (this.fName == null && emp.fName != null)
+			return false;
+		else if (!this.fName.equals(emp.fName))
+			return false;
+		else if (this.lName == null && emp.lName != null)
+			return false;
+		else if (!this.lName.equals(emp.lName))
+			return false;
+		else if (this.title == null && emp.title != null)
+			return false;
+		else if (!this.title.equals(emp.title))
+			return false;
+
+		return true;
+	}
+}

Added: incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/test/TestDBControl.jcx
==============================================================================
--- (empty file)
+++ incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/test/TestDBControl.jcx	Tue Oct  5 16:12:30 2004
@@ -0,0 +1,49 @@
+package org.apache.beehive.controls.test.controls.database.test;
+
+import java.sql.SQLException;
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.HashMap;
+
+import org.apache.beehive.controls.api.bean.ControlExtension;
+import org.apache.beehive.controls.test.controls.database.DatabaseControl;
+import org.apache.beehive.controls.test.controls.database.DatabaseControl.ConnectionDataSource;
+
+@ControlExtension
+@ConnectionDataSource(jndiName="jdbc:derby:build/databaseControlTestDB;create=true")
+public interface TestDBControl extends DatabaseControl
+{
+    @SQL(statement="CREATE TABLE EMPLOYEE ( id INT PRIMARY KEY NOT NULL, " +
+                   "fName VARCHAR(20), lName VARCHAR(20), title VARCHAR(15))")
+    public void createTable() throws SQLException;
+
+    @SQL(statement="DROP TABLE EMPLOYEE")
+    public void dropTable() throws SQLException;
+
+    @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;
+
+    @SQL(statement="SELECT * FROM EMPLOYEE WHERE id={1}")
+    public Employee selectEmployee(int p_id) throws SQLException;
+
+    @SQL(statement="SELECT * FROM EMPLOYEE ORDER BY id")
+    public Employee[] selectEmployees() throws SQLException;
+
+    @SQL(statement="SELECT * FROM EMPLOYEE ORDER BY id", iteratorElementType=Employee.class)
+    public Iterator selectEmployeesWithIterator() throws SQLException;
+
+    @SQL(statement="SELECT * FROM EMPLOYEE ORDER BY id")
+    public HashMap selectEmployeeWithHashMap() throws SQLException;
+
+    @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="DELETE FROM EMPLOYEE WHERE id = {1}")
+    public void deleteEmployee(int p_id) throws SQLException;
+}

Added: incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/util/JavaTypeHelper.java
==============================================================================
--- (empty file)
+++ incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/util/JavaTypeHelper.java	Tue Oct  5 16:12:30 2004
@@ -0,0 +1,85 @@
+package org.apache.beehive.controls.test.controls.database.util;
+
+import java.sql.Types;
+import java.util.HashMap;
+
+public class JavaTypeHelper
+{
+    private static final int TYPE_MAX = 29;
+    private static final int JAVA_PRIMITIVE_TYPES = 8;
+    private static HashMap javaSQLTypeMap = new HashMap(TYPE_MAX * 2);
+    private static HashMap primitiveDefaults = new HashMap(JAVA_PRIMITIVE_TYPES);
+
+    static {
+        // Class to java.sql.Types
+        javaSQLTypeMap.put(Boolean.TYPE, Types.BOOLEAN);
+        javaSQLTypeMap.put(Integer.TYPE, Types.INTEGER);
+        javaSQLTypeMap.put(Long.TYPE, Types.BIGINT);
+        javaSQLTypeMap.put(Byte.TYPE, Types.TINYINT);
+        javaSQLTypeMap.put(Short.TYPE, Types.SMALLINT);
+        javaSQLTypeMap.put(Float.TYPE, Types.REAL);
+        javaSQLTypeMap.put(Double.TYPE, Types.DOUBLE);
+        javaSQLTypeMap.put(Boolean.class, Types.BOOLEAN);
+        javaSQLTypeMap.put(Integer.class, Types.INTEGER);
+        javaSQLTypeMap.put(Long.class, Types.BIGINT);
+        javaSQLTypeMap.put(Byte.class, Types.TINYINT);
+        javaSQLTypeMap.put(Short.class, Types.SMALLINT);
+        javaSQLTypeMap.put(Float.class, Types.REAL);
+        javaSQLTypeMap.put(Double.class, Types.DOUBLE);
+        javaSQLTypeMap.put(String.class, Types.VARCHAR);
+        javaSQLTypeMap.put(java.math.BigDecimal.class, Types.DECIMAL);
+        javaSQLTypeMap.put(byte[].class, Types.VARBINARY);
+        javaSQLTypeMap.put(java.sql.Timestamp.class, Types.TIMESTAMP);
+        javaSQLTypeMap.put(java.sql.Time.class, Types.TIME);
+        javaSQLTypeMap.put(java.sql.Date.class, Types.DATE);
+        javaSQLTypeMap.put(java.sql.Ref.class, Types.REF);
+        javaSQLTypeMap.put(java.sql.Blob.class, Types.BLOB);
+        javaSQLTypeMap.put(java.sql.Clob.class, Types.CLOB);
+        javaSQLTypeMap.put(java.sql.Array.class, Types.ARRAY);
+        javaSQLTypeMap.put(java.util.Date.class, Types.TIMESTAMP);
+        javaSQLTypeMap.put(java.util.Calendar.class, Types.TIMESTAMP);
+        javaSQLTypeMap.put(java.util.GregorianCalendar.class, Types.TIMESTAMP);
+        //javaSQLTypeMap.put(java.io.Reader.class, Types.READER);
+        //javaSQLTypeMap.put(java.io.InputStream.class, Types.STREAM);
+
+        //Java Primitive to Default values.
+        primitiveDefaults.put(Boolean.TYPE, Boolean.FALSE);
+        primitiveDefaults.put(Integer.TYPE, new Integer(0));
+        primitiveDefaults.put(Long.TYPE, new Long(0));
+        primitiveDefaults.put(Byte.TYPE, new Byte((byte)0));
+        primitiveDefaults.put(Short.TYPE, new Short((short)0));
+        primitiveDefaults.put(Character.TYPE, new Character('\u0000'));
+        primitiveDefaults.put(Float.TYPE, new Float(0.0f));
+        primitiveDefaults.put(Double.TYPE, new Double(0.0d));
+
+    }
+
+
+
+    public static int getSqlType(Class classType)
+    {
+        while (null != classType)
+        {
+            Integer type = (Integer)javaSQLTypeMap.get(classType);
+            if (null != type)
+                return type.intValue();
+            classType = classType.getSuperclass();
+        }
+        return Types.OTHER;
+    }
+
+
+    public static int getSqlType(Object o)
+    {
+        if (null == o)
+            return Types.NULL;
+        return getSqlType(o.getClass());
+    }
+
+    public static Object getJaveTypeDefaultValue(Class primitiveType) {
+        if (primitiveType.isPrimitive())
+            return (primitiveDefaults.get(primitiveType));
+        else
+            return null;
+    }
+}

Added: incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/util/PreparedStatementHelper.java
==============================================================================
--- (empty file)
+++ incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/util/PreparedStatementHelper.java	Tue Oct  5 16:12:30 2004
@@ -0,0 +1,163 @@
+package org.apache.beehive.controls.test.controls.database.util;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.Map;
+
+public class PreparedStatementHelper
+{
+    private interface ParameterSetter {
+
+        public static final int NUM_OF_PARAMETER_SETTERS = 5;
+
+        public void setParameter(PreparedStatement ps, int index, Object value, Calendar cal) throws SQLException;
+
+        static ParameterSetter VARCHAR = new ParameterSetter()
+        {
+            public void setParameter(PreparedStatement ps, int index, Object value, Calendar cal) throws SQLException
+            {
+                String setValue = value instanceof String ? (String)value : value.toString();
+                ps.setObject(index, setValue, Types.VARCHAR);
+            }
+        };
+
+        static ParameterSetter BOOLEAN = new ParameterSetter()
+        {
+            public void setParameter(PreparedStatement ps, int index, Object value, Calendar cal) throws SQLException
+            {
+                if (value instanceof Boolean)
+                    ps.setBoolean(index, ((Boolean)value).booleanValue());
+            }
+        };
+
+        static ParameterSetter TIMESTAMP = new ParameterSetter()
+        {
+            public void setParameter(PreparedStatement ps, int index, Object value, Calendar cal) throws SQLException
+            {
+                if (value instanceof java.util.Calendar)
+                {
+                    Calendar calValue = (Calendar)value;
+
+                    if (null == cal)
+                    {
+                        /* 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());
+                }
+
+                if (value instanceof java.sql.Timestamp)
+                {
+                    if (null == cal)
+                        ps.setTimestamp(index, (java.sql.Timestamp)value);
+                    else
+                        ps.setTimestamp(index, (java.sql.Timestamp)value, cal);
+                    return;
+                }
+            }
+        };
+
+        static ParameterSetter DATE = new ParameterSetter() {
+            public void setParameter(PreparedStatement ps, int index, Object value, Calendar cal) throws SQLException
+            {
+                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;
+
+                    if (null == cal)
+                    {
+                        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());
+                }
+
+                if (value instanceof java.sql.Date)
+                {
+                    if (null == cal)
+                        ps.setDate(index, (java.sql.Date)value);
+                    else
+                        ps.setDate(index, (java.sql.Date)value, cal);
+                    return;
+                }
+            }
+        };
+
+        static ParameterSetter TIME = new ParameterSetter()
+        {
+            public void setParameter(PreparedStatement ps, int index, Object value, Calendar cal) throws SQLException
+            {
+                if (value instanceof java.sql.Time)
+                {
+                    if (null == cal)
+                        ps.setTime(index, (java.sql.Time)value);
+                    else
+                        ps.setTime(index, (java.sql.Time)value, cal);
+                    return;
+                }
+            }
+        };
+    }
+
+    private static Map<Integer,ParameterSetter> typeToSetterMap = new HashMap(ParameterSetter.NUM_OF_PARAMETER_SETTERS * 2);
+
+    static
+    {
+        typeToSetterMap.put(Types.BOOLEAN, ParameterSetter.BOOLEAN);
+        typeToSetterMap.put(Types.TIMESTAMP, ParameterSetter.TIMESTAMP);
+        typeToSetterMap.put(Types.DATE, ParameterSetter.DATE);
+        typeToSetterMap.put(Types.TIME, ParameterSetter.TIME);
+        typeToSetterMap.put(Types.VARCHAR, ParameterSetter.VARCHAR);
+    }
+
+    public static void setPreparedStatementParameter(PreparedStatement ps, int index, Object value, Calendar calendar)
+        throws SQLException
+    {
+        int sqlType = JavaTypeHelper.getSqlType(value);
+        ParameterSetter setter = typeToSetterMap.get(sqlType);
+        if (null != setter)
+            setter.setParameter(ps, index, value, calendar);
+        else if (null == value)
+            ps.setNull(index, Types.NULL == sqlType ? Types.VARCHAR : sqlType);
+        else
+            ps.setObject(index, value, sqlType);
+
+    }
+}

Added: incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/util/ResultSetHelper.java
==============================================================================
--- (empty file)
+++ incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/database/util/ResultSetHelper.java	Tue Oct  5 16:12:30 2004
@@ -0,0 +1,320 @@
+package org.apache.beehive.controls.test.controls.database.util;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.Map;
+
+public class ResultSetHelper
+{
+    private static final int TYPE_MAX = 29;
+
+    private interface ColumnReader {
+
+        public Object readValue(ResultSet rs, String columnName, GregorianCalendar cal) throws SQLException;
+
+        static ColumnReader UNKNOWN = new ColumnReader()
+        {
+            public Object readValue(ResultSet rs, String columnName, GregorianCalendar cal) throws SQLException
+            {
+                return rs.getObject(columnName);
+            }
+        };
+
+        static ColumnReader BYTE = new ColumnReader()
+        {
+            public Object readValue(ResultSet rs, String columnName, GregorianCalendar cal) throws SQLException
+            {
+                return new Byte(rs.getByte(columnName));
+            }
+        };
+
+        static ColumnReader SHORT = new ColumnReader()
+        {
+            public Object readValue(ResultSet rs, String columnName, GregorianCalendar cal) throws SQLException
+            {
+                return new Short(rs.getShort(columnName));
+            }
+        };
+
+        static ColumnReader INT = new ColumnReader()
+        {
+            public Object readValue(ResultSet rs, String columnName, GregorianCalendar cal) throws SQLException
+            {
+                return new Integer(rs.getInt(columnName));
+            }
+        };
+
+        static ColumnReader LONG = new ColumnReader()
+        {
+            public Object readValue(ResultSet rs, String columnName, GregorianCalendar cal) throws SQLException
+            {
+                return new Long(rs.getLong(columnName));
+            }
+        };
+
+        static ColumnReader FLOAT = new ColumnReader()
+        {
+            public Object readValue(ResultSet rs, String columnName, GregorianCalendar cal) throws SQLException
+            {
+                return new Float(rs.getFloat(columnName));
+            }
+        };
+
+        static ColumnReader DOUBLE = new ColumnReader()
+        {
+            public Object readValue(ResultSet rs, String columnName, GregorianCalendar cal) throws SQLException
+            {
+                return new Double(rs.getDouble(columnName));
+            }
+        };
+
+        static ColumnReader BOOLEAN = new ColumnReader()
+        {
+            public Object readValue(ResultSet rs, String columnName, GregorianCalendar cal) throws SQLException
+            {
+                return rs.getBoolean(columnName) ? Boolean.TRUE : Boolean.FALSE;
+            }
+        };
+
+        static ColumnReader BYTE_OBJ = new ColumnReader()
+        {
+            public Object readValue(ResultSet rs, String columnName, GregorianCalendar cal) throws SQLException
+            {
+                byte i = rs.getByte(columnName); return rs.wasNull() ? null : new Byte(i);
+            }
+        };
+
+        static ColumnReader SHORT_OBJ = new ColumnReader()
+        {
+            public Object readValue(ResultSet rs, String columnName, GregorianCalendar cal) throws SQLException
+            {
+                short i = rs.getShort(columnName); return rs.wasNull() ? null : new Short(i);
+            }
+        };
+
+        static ColumnReader INT_OBJ = new ColumnReader()
+        {
+            public Object readValue(ResultSet rs, String columnName, GregorianCalendar cal) throws SQLException
+            {
+                int i = rs.getInt(columnName); return rs.wasNull() ? null : new Integer(i);
+            }
+        };
+
+        static ColumnReader LONG_OBJ = new ColumnReader()
+        {
+            public Object readValue(ResultSet rs, String columnName, GregorianCalendar cal) throws SQLException
+            {
+                long i = rs.getLong(columnName); return rs.wasNull() ? null : new Long(i);
+            }
+        };
+
+        static ColumnReader FLOAT_OBJ = new ColumnReader()
+        {
+            public Object readValue(ResultSet rs, String columnName, GregorianCalendar cal) throws SQLException
+            {
+                float i = rs.getFloat(columnName); return rs.wasNull() ? null : new Float(i);
+            }
+        };
+        static ColumnReader DOUBLE_OBJ = new ColumnReader()
+        {
+            public Object readValue(ResultSet rs, String columnName, GregorianCalendar cal) throws SQLException
+            {
+                double i = rs.getDouble(columnName); return rs.wasNull() ? null : new Double(i);
+            }
+        };
+
+        static ColumnReader BOOLEAN_OBJ = new ColumnReader()
+        {
+            public Object readValue(ResultSet rs, String columnName, GregorianCalendar cal) throws SQLException
+            {
+                boolean i = rs.getBoolean(columnName); return rs.wasNull() ? null : (i ? Boolean.TRUE : Boolean.FALSE);
+            }
+        };
+
+        static ColumnReader BIG_DECIMAL = new ColumnReader()
+        {
+            public Object readValue(ResultSet rs, String columnName, GregorianCalendar cal) throws SQLException
+            {
+               return rs.getBigDecimal(columnName);
+            }
+        };
+
+        static ColumnReader STRING = new ColumnReader()
+        {
+            public Object readValue(ResultSet rs, String columnName, GregorianCalendar cal) throws SQLException
+            {
+                return rs.getString(columnName);
+            }
+        };
+
+        static ColumnReader BYTES = new ColumnReader()
+        {
+			public Object readValue(ResultSet rs, String columnName, GregorianCalendar cal) throws SQLException
+        	{
+                return rs.getBytes(columnName);
+            }
+        };
+
+        static ColumnReader SQLDATE = new ColumnReader()
+        {
+            public Object readValue(ResultSet rs, String columnName, GregorianCalendar cal) throws SQLException
+            {
+                if (null == cal)
+                    return rs.getDate(columnName);
+                else
+                    return rs.getDate(columnName, cal);
+            }
+        };
+
+        static ColumnReader TIME = new ColumnReader()
+        {
+            public Object readValue(ResultSet rs, String columnName, GregorianCalendar cal) throws SQLException
+            {
+                if (null == cal)
+                    return rs.getTime(columnName);
+                else
+                    return rs.getTime(columnName, cal);
+            }
+        };
+
+        static ColumnReader TIMESTAMP = new ColumnReader()
+        {
+            public Object readValue(ResultSet rs, String columnName, GregorianCalendar cal) throws SQLException
+            {
+                if (null == cal)
+                    return rs.getTimestamp(columnName);
+                else
+                    return rs.getTimestamp(columnName, cal);
+            }
+        };
+
+        static ColumnReader STREAM = new ColumnReader()
+        {
+            public Object readValue(ResultSet rs, String columnName, GregorianCalendar cal) throws SQLException
+            {
+                //not supported
+                return null;
+            }
+        };
+
+        static ColumnReader READER = new ColumnReader()
+        {
+            public Object readValue(ResultSet rs, String columnName, GregorianCalendar cal) throws SQLException
+            {
+                //not supported
+                return null;
+            }
+        };
+
+        static ColumnReader CLOB = new ColumnReader()
+        {
+            public Object readValue(ResultSet rs, String columnName, GregorianCalendar cal) throws SQLException
+            {
+                return rs.getClob(columnName);
+            }
+        };
+
+        static ColumnReader BLOB = new ColumnReader()
+        {
+            public Object readValue(ResultSet rs, String columnName, GregorianCalendar cal) throws SQLException
+            {
+                return rs.getBlob(columnName);
+            }
+        };
+
+        static ColumnReader ARRAY = new ColumnReader()
+        {
+            public Object readValue(ResultSet rs, String columnName, GregorianCalendar cal) throws SQLException
+            {
+                return rs.getArray(columnName);
+            }
+        };
+
+        static ColumnReader REF = new ColumnReader()
+        {
+            public Object readValue(ResultSet rs, String columnName, GregorianCalendar cal) throws SQLException
+            {
+                return rs.getRef(columnName);
+            }
+        };
+
+        static ColumnReader DATE = new ColumnReader()
+        {
+            public Object readValue(ResultSet rs, String columnName, GregorianCalendar cal) throws SQLException
+            {
+                java.sql.Timestamp ts = (null == cal) ? rs.getTimestamp(columnName) : rs.getTimestamp(columnName, cal);
+                if (null == ts)
+                    return null;
+                return new java.util.Date(ts.getTime());
+            }
+        };
+
+        static ColumnReader CALENDAR = new ColumnReader()
+        {
+            public Object readValue(ResultSet rs, String columnName, GregorianCalendar cal) throws SQLException
+            {
+                java.sql.Timestamp ts = (null == cal) ? rs.getTimestamp(columnName) : rs.getTimestamp(columnName, cal);
+                if (null == ts)
+                    return null;
+                Calendar c = (null == cal) ? Calendar.getInstance() : (Calendar)cal.clone();
+                c.setTimeInMillis(ts.getTime());
+                return c;
+            }
+        };
+    }
+
+
+
+
+
+    private static Map<Class,ColumnReader> typeToReaderMap = new HashMap(TYPE_MAX * 2);
+
+    static
+    {
+        typeToReaderMap.put(Boolean.TYPE, ColumnReader.BOOLEAN);
+        typeToReaderMap.put(Integer.TYPE, ColumnReader.INT);
+        typeToReaderMap.put(Long.TYPE, ColumnReader.LONG);
+        typeToReaderMap.put(Byte.TYPE, ColumnReader.BYTE);
+        typeToReaderMap.put(Short.TYPE, ColumnReader.SHORT);
+        typeToReaderMap.put(Float.TYPE, ColumnReader.FLOAT);
+        typeToReaderMap.put(Double.TYPE, ColumnReader.DOUBLE);
+        typeToReaderMap.put(Boolean.class, ColumnReader.BOOLEAN_OBJ);
+        typeToReaderMap.put(Integer.class, ColumnReader.INT_OBJ);
+        typeToReaderMap.put(Long.class, ColumnReader.LONG_OBJ);
+        typeToReaderMap.put(Byte.class, ColumnReader.BYTE_OBJ);
+        typeToReaderMap.put(Short.class, ColumnReader.SHORT_OBJ);
+        typeToReaderMap.put(Float.class, ColumnReader.FLOAT_OBJ);
+        typeToReaderMap.put(Double.class, ColumnReader.DOUBLE_OBJ);
+        typeToReaderMap.put(String.class, ColumnReader.STRING);
+        typeToReaderMap.put(java.math.BigDecimal.class, ColumnReader.BIG_DECIMAL);
+        typeToReaderMap.put(byte[].class, ColumnReader.BYTES);
+        typeToReaderMap.put(java.sql.Timestamp.class, ColumnReader.TIMESTAMP);
+        typeToReaderMap.put(java.sql.Time.class, ColumnReader.TIME);
+        typeToReaderMap.put(java.sql.Date.class, ColumnReader.SQLDATE);
+        typeToReaderMap.put(java.sql.Ref.class, ColumnReader.REF);
+        typeToReaderMap.put(java.sql.Blob.class, ColumnReader.BLOB);
+        typeToReaderMap.put(java.sql.Clob.class, ColumnReader.CLOB);
+        typeToReaderMap.put(java.sql.Array.class, ColumnReader.ARRAY);
+        typeToReaderMap.put(java.io.Reader.class, ColumnReader.READER);
+        typeToReaderMap.put(java.io.InputStream.class, ColumnReader.STREAM);
+        typeToReaderMap.put(java.util.Date.class, ColumnReader.DATE);
+        typeToReaderMap.put(java.util.Calendar.class, ColumnReader.CALENDAR);
+        typeToReaderMap.put(java.util.GregorianCalendar.class, ColumnReader.CALENDAR);
+    }
+
+    public static Object readValue(ResultSet rs, String columnName, Class resultType) throws SQLException
+    {
+        return readValue(rs, columnName, resultType, null);
+    }
+
+    public static Object readValue(ResultSet rs, String columnName, Class resultType, GregorianCalendar cal) throws SQLException
+    {
+        ColumnReader reader = typeToReaderMap.get(resultType);
+        if (reader == null)
+            reader = ColumnReader.UNKNOWN;
+        return reader.readValue(rs, columnName, cal);
+    }
+}

Added: incubator/beehive/trunk/controls/test/src/drivers/org/apache/beehive/controls/test/driver/database/DriveDatabaseControl.java
==============================================================================
--- (empty file)
+++ incubator/beehive/trunk/controls/test/src/drivers/org/apache/beehive/controls/test/driver/database/DriveDatabaseControl.java	Tue Oct  5 16:12:30 2004
@@ -0,0 +1,320 @@
+package org.apache.beehive.controls.test.driver.database;
+
+import org.apache.beehive.test.tools.milton.common.Report;
+import org.apache.beehive.controls.test.controls.database.test.TestDBControlBean;
+import org.apache.beehive.controls.test.controls.database.test.Employee;
+
+import java.util.Iterator;
+import java.util.HashMap;
+
+/* This class contains the logic to test control extensibility.
+ * By invoking methods on a SubControlBean, features of control extensibility are verified.
+ */
+
+public class DriveDatabaseControl
+{
+
+	//Error messages
+	private static final String INSERTED_EMPLOYEE_NOT_FOUND = "Inserted employee not found ";
+	private static final String EMPLOYEE_ARRAY_IS_EMPTY = "Employee array is empty";
+	private static final String BAD_DATA_IN_EMPLOYEE_ARRAY = "Data in employee array does not match expectation.";
+	private static final String EMPLOYEE_ITERATOR_IS_NULL = "Employee iterator is null";
+	private static final String BAD_DATA_IN_EMPLOYEE_ITERATOR = "Data in employee iterator does not match expectation.";
+	private static final String EMPLOYEE_HASHMAP_IS_NULL = "Employee HashMap is null";
+	private static final String BAD_DATA_IN_EMPLOYEE_HASHMAP = "Data in employee HashMap does not match expectation.";
+	private static final String SELECT_ONE_EMPLOYEE_FAILED = "Select one employee did not return one employee";
+	private static final String UPDATE_EMPLOYEE_FAILED = "Failed to update employee";
+	private static final String DELETE_EMPLOYEE_FAILED = "Failed to delete employee";
+
+	//Test data
+	private static Employee[] emps = { new Employee(1, "John", "Doe", "CEO"), new Employee(2, "Jane", "Doe", "CFO") };
+
+
+	private TestDBControlBean testDBControl;
+
+	public DriveDatabaseControl (TestDBControlBean aControl)
+	{
+		this.testDBControl = aControl;
+	}
+
+	public void setControl(TestDBControlBean aControl)
+	{
+
+		this.testDBControl = aControl;
+	}
+
+	public Report doCreateTable()
+	{
+		Report report=new Report();
+		try
+		{
+			testDBControl.createTable();
+			report.setStatus(Report.PASS);
+		}
+		catch(Exception e)
+		{
+			report.setStatus(Report.FAIL);
+			report.setExceptionStack(e);
+		}
+		return report;
+	}
+
+	public Report doDropTable()
+	{
+
+		Report report=new Report();
+		try
+		{
+			testDBControl.dropTable();
+			report.setStatus(Report.PASS);
+        }
+        catch(Exception e)
+        {
+			report.setStatus(Report.FAIL);
+			report.setExceptionStack(e);
+        }
+		return report;
+	}
+
+	public Report doInsertEmployees()
+	{
+		Report report=new Report();
+		try
+		{
+			//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);
+			}
+
+			//Retrieve the two employees just inserted, and verify they match those
+			//inserted.
+			for (int i = 0; i < emps.length; i++)
+			{
+				Employee emp = testDBControl.selectEmployee(emps[i].id);
+				if (emp == null || !emp.equals(emps[i]))
+				{
+					report.setMessage(INSERTED_EMPLOYEE_NOT_FOUND + emps[i] + emp);
+					break;
+				}
+				report.setStatus(Report.PASS);
+			}
+
+        }
+        catch(Exception e)
+        {
+			report.setExceptionStack(e);
+        }
+		return report;
+	}
+
+	public Report doSelectEmployeesWithArray()
+	{
+		Report report=new Report();
+		try
+		{
+
+			//Select employees into array
+			Employee[] employees = testDBControl.selectEmployees();
+
+			//Ensure the array is not empty
+			if (employees == null || employees.length == 0)
+			{
+				 report.setMessage(EMPLOYEE_ARRAY_IS_EMPTY + employees);
+			}
+			//Ensure correct number of employees in the array
+			else if (employees.length != emps.length)
+			{
+				 report.setMessage(BAD_DATA_IN_EMPLOYEE_ARRAY);
+			}
+			else {
+				//Ensure employee in array matches those inserted
+				for (int i = 0; i < emps.length; i++)
+				{
+					if (employees[i] == null || !employees[i].equals(emps[i]))
+					{
+						report.setMessage(BAD_DATA_IN_EMPLOYEE_ARRAY + employees[i] + emps[i]);
+						break;
+					}
+					report.setStatus(Report.PASS);
+				}
+			}
+
+		}
+        catch(Exception e)
+        {
+			report.setExceptionStack(e);
+        }
+		return report;
+	}
+
+	public Report doSelectEmployeesWithIterator()
+	{
+		Report report=new Report();
+		try
+		{
+			//Select employees into iterator
+			Iterator employees = testDBControl.selectEmployeesWithIterator();
+			//Ensure iterator is not null
+			if (employees == null)
+			{
+				 report.setMessage(EMPLOYEE_ITERATOR_IS_NULL);
+				 return report;
+			}
+
+			//Tracks number of employees in the iterator
+			int count = -1;
+
+			//Ensure employees in the iterator matches those inserted
+			while (employees.hasNext())
+			{
+				count++;
+				Employee emp = (Employee)employees.next();
+				if (emp == null || !emp.equals(emps[count]))
+				{
+					 report.setMessage(BAD_DATA_IN_EMPLOYEE_ITERATOR + emps[count] + emp);
+					 return report;
+				}
+			}
+
+			//Ensure the number of employees in the iterator matches that inserted.
+			if (count != emps.length-1)
+			{
+				 report.setMessage(BAD_DATA_IN_EMPLOYEE_ITERATOR + emps.length + " " + count);
+				 return report;
+			}
+			report.setStatus(Report.PASS);
+		}
+		catch(Exception e)
+		{
+			report.setExceptionStack(e);
+		}
+		return report;
+	}
+
+	public Report doSelectEmployeesWithHashMap()
+	{
+		Report report=new Report();
+		try
+		{
+			//Select employees into iterator
+			HashMap<String, Object> map = testDBControl.selectEmployeeWithHashMap();
+			//Ensure HashMap is not null
+			if (map == null)
+			{
+				report.setMessage(EMPLOYEE_HASHMAP_IS_NULL);
+			}
+			//Ensure employee id matches
+			else if (map.get("ID") == null || ((Integer)map.get("ID")).intValue() != emps[0].id)
+			{
+				report.setMessage(BAD_DATA_IN_EMPLOYEE_HASHMAP + "ID");
+			}
+			//Ensure employee fName matches
+			else if (map.get("FNAME") == null || !emps[0].fName.equals(map.get("FNAME")))
+			{
+				report.setMessage(BAD_DATA_IN_EMPLOYEE_HASHMAP + "FNAME");
+			}
+			//Ensure employee lName matches
+			else if (map.get("LNAME") == null || !emps[0].lName.equals(map.get("LNAME")))
+			{
+				report.setMessage(BAD_DATA_IN_EMPLOYEE_HASHMAP + "LNAME");
+			}
+			//Ensure employee title matches
+			else if (map.get("TITLE") == null || !emps[0].title.equals(map.get("TITLE")))
+			{
+				report.setMessage(BAD_DATA_IN_EMPLOYEE_HASHMAP + "TITLE");
+			}
+			else
+			{
+				report.setStatus(Report.PASS);
+			}
+		}
+		catch(Exception e)
+		{
+			report.setExceptionStack(e);
+		}
+		return report;
+	}
+
+	public Report doSelectOneEmployeeWithMaxRow()
+	{
+		Report report=new Report();
+		try
+		{
+			//Select employees into iterator
+			Employee[] employees = testDBControl.selectOneEmployee();
+
+			//Ensure only one employee is returned
+			if (employees == null || employees.length != 1)
+			{
+				report.setMessage(SELECT_ONE_EMPLOYEE_FAILED);
+			}
+			else
+			{
+				report.setStatus(Report.PASS);
+			}
+		}
+		catch(Exception e)
+		{
+			report.setExceptionStack(e);
+		}
+		return report;
+	}
+
+	public Report doUpdateEmployee()
+	{
+		Report report=new Report();
+		try
+		{
+			String newTitle = "President";
+
+			//Change title of an employee
+			testDBControl.changeTitle(emps[0].id, newTitle);
+
+			//Ensure title is changed
+			Employee emp = testDBControl.selectEmployee(emps[0].id);
+
+			if (emp == null || !emp.title.equals(newTitle))
+			{
+				report.setMessage(UPDATE_EMPLOYEE_FAILED);
+			}
+			else
+			{
+				report.setStatus(Report.PASS);
+			}
+		}
+		catch(Exception e)
+		{
+			report.setExceptionStack(e);
+		}
+		return report;
+	}
+
+	public Report doDeleteEmployee()
+	{
+		Report report=new Report();
+		try
+		{
+			//delete an employee
+			testDBControl.deleteEmployee(emps[0].id);
+
+			//Ensure employee is deleted
+			Employee emp = testDBControl.selectEmployee(emps[0].id);
+
+			if (emp != null)
+			{
+				report.setMessage(DELETE_EMPLOYEE_FAILED);
+			}
+			else
+			{
+				report.setStatus(Report.PASS);
+			}
+		}
+		catch(Exception e)
+		{
+			report.setExceptionStack(e);
+		}
+		return report;
+	}
+
+}

Added: incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/database/Car.java
==============================================================================
--- (empty file)
+++ incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/database/Car.java	Tue Oct  5 16:12:30 2004
@@ -0,0 +1,8 @@
+package org.apache.beehive.controls.test.java.database;
+
+public class Car
+{
+    public String make;
+    public String model;
+    public int cycl;
+}

Added: incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/database/ParserTest.java
==============================================================================
--- (empty file)
+++ incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/database/ParserTest.java	Tue Oct  5 16:12:30 2004
@@ -0,0 +1,74 @@
+package org.apache.beehive.controls.test.java.database;
+
+import org.apache.beehive.controls.test.controls.database.SQLParameter;
+import org.apache.beehive.controls.test.controls.database.SQLParser;
+import org.apache.beehive.controls.test.controls.database.SQLStatement;
+import org.apache.beehive.test.tools.mantis.annotations.tch.Freq;
+import org.apache.beehive.test.tools.mantis.annotations.tch.Status;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+
+public class ParserTest extends TestCase
+{
+	public ParserTest(String name)
+	{
+		super(name);
+	}
+
+    public static void main (String[] args)
+    {
+		junit.textui.TestRunner.run (suite());
+	}
+
+	public static Test suite()
+	{
+		return new TestSuite(ParserTest.class);
+	}
+
+	@Freq("checkin")
+    public void testParseStatementWithSimpleParameters()
+    {
+		SQLStatement stmt = parse("SELECT * FROM EMPLOYEE WHERE FNAME={1} AND LNAME={2}");
+		assertNotNull(stmt);
+		String sql = stmt.getSQL();
+		assertEquals("SELECT * FROM EMPLOYEE WHERE FNAME=? AND LNAME=?", sql);
+		SQLParameter[] params = stmt.getParameters();
+		assertNotNull(params);
+		assertEquals(2, params.length);
+		assertEquals("1", params[0].name);
+		assertEquals("2", params[1].name);
+	}
+
+	@Freq("checkin")
+    public void testParseStatementWithNoParameters()
+    {
+		String inputStatement = "DELETE * FROM EMPLOYEE";
+		SQLStatement stmt = parse(inputStatement);
+		assertNotNull(stmt);
+		String sql = stmt.getSQL();
+		assertEquals(inputStatement, sql);
+		SQLParameter[] params = stmt.getParameters();
+		assertNotNull(params);
+		assertEquals(0, params.length);
+	}
+
+
+    private static SQLStatement parse (String sql)
+    {
+        try
+        {
+            SQLParser parser = new SQLParser(sql);
+            SQLStatement stmt = parser.parse();
+       		return stmt;
+        }
+        catch (Exception e)
+        {
+            assertTrue("The following error occurred in parse(): " + e, false);
+            return null;
+        }
+    }
+}

Added: incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/database/ResultSetExtractorTest.java
==============================================================================
--- (empty file)
+++ incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/database/ResultSetExtractorTest.java	Tue Oct  5 16:12:30 2004
@@ -0,0 +1,243 @@
+package org.apache.beehive.controls.test.java.database;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import org.apache.beehive.controls.test.controls.database.ResultSetExtractor;
+import org.apache.beehive.test.tools.mantis.annotations.tch.Freq;
+import org.apache.beehive.test.tools.mantis.annotations.tch.Status;
+
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import java.sql.*;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+public class ResultSetExtractorTest extends TestCase
+{
+    private static final String DROP_TABLE = "DROP TABLE CAR";
+    private static final String CREATE_TABLE = "CREATE TABLE CAR ( ID INT PRIMARY KEY NOT NULL, " +
+        "MAKE VARCHAR(20), MODEL VARCHAR(20), CYCL INT)";
+    private static final String INSERT_HONDA = "INSERT INTO CAR VALUES (1, 'HONDA', 'CIVIC', 4)";
+    private static final String INSERT_TOYOTA = "INSERT INTO CAR VALUES (2, 'TOYOTA', 'CAMRY', 6)";
+    private static final String SELECT_HONDA = "SELECT * FROM CAR WHERE MAKE = 'HONDA'";
+    private static final String SELECT_ALL = "SELECT * FROM CAR ORDER BY MAKE";
+
+    private Connection con;
+
+    public ResultSetExtractorTest(String name)
+    {
+		super(name);
+	}
+
+    public static void main (String[] args)
+    {
+		junit.textui.TestRunner.run (suite());
+	}
+
+	public static Test suite()
+	{
+		return new TestSuite(ResultSetExtractorTest.class);
+	}
+
+    protected void setUp()
+    {
+        this.con = getConnection();
+		this.dropTable();
+        try
+        {
+            executeSQL(CREATE_TABLE);
+            executeSQL(INSERT_HONDA);
+            executeSQL(INSERT_TOYOTA);
+        }
+        catch (Exception e)
+        {
+            assertTrue("The following error occurred in setup(): " + e, false);
+        }
+
+    }
+
+    protected void tearDown()
+    {
+		this.dropTable();
+        try { con.close(); } catch (Throwable t) {}
+
+	}
+
+	private void dropTable()
+	{
+        try
+        {
+            executeSQL(DROP_TABLE);
+        }
+        catch (Exception e)
+        {
+            //ignore exception
+        }
+	}
+
+	@Freq("checkin")
+    public void testExtractObject()
+    {
+        PreparedStatement ps = null;
+        ResultSet rs = null;
+
+        try
+        {
+            ps = this.con.prepareStatement(SELECT_HONDA);
+            rs = ps.executeQuery();
+            ResultSetExtractor extractor = new ResultSetExtractor(rs, null);
+
+            assertTrue(rs.next());
+            Car car = (Car)extractor.extractObject(Car.class);
+            assertNotNull(car);
+            assertEquals("HONDA", car.make);
+            assertEquals("CIVIC", car.model);
+            assertEquals(4, car.cycl);
+        }
+        catch (Exception e)
+        {
+            assertTrue("The following error occurred in testExtractObject(): " + e, false);
+        }
+        finally
+        {
+            try { rs.close(); } catch (Throwable t) {}
+            try { ps.close(); } catch (Throwable t) {}
+        }
+    }
+
+	@Freq("checkin")
+    public void testExtractArray()
+    {
+        PreparedStatement ps = null;
+        ResultSet rs = null;
+
+        try
+        {
+            ps = this.con.prepareStatement(SELECT_ALL);
+            rs = ps.executeQuery();
+            ResultSetExtractor extractor = new ResultSetExtractor(rs, null);
+
+            Car[] cars = (Car[])extractor.extractArray(Car[].class);
+
+            assertNotNull(cars);
+            assertEquals(2, cars.length);
+            assertEquals("HONDA", cars[0].make);
+            assertEquals("TOYOTA", cars[1].make);
+            assertEquals(4, cars[0].cycl);
+            assertEquals(6, cars[1].cycl);
+
+        }
+        catch (Exception e)
+        {
+            assertTrue("The following error occurred in testExtractArray(): " + e, false);
+        }
+        finally
+        {
+            try { rs.close(); } catch (Throwable t) {}
+            try { ps.close(); } catch (Throwable t) {}
+        }
+    }
+
+	@Freq("checkin")
+    public void testExtractIterator()
+    {
+        PreparedStatement ps = null;
+        ResultSet rs = null;
+
+        try
+        {
+            ps = this.con.prepareStatement(SELECT_ALL);
+            rs = ps.executeQuery();
+            ResultSetExtractor extractor = new ResultSetExtractor(rs, null);
+
+            Iterator<Car> i = extractor.extractIterator(Car.class);
+
+            assertNotNull(i);
+            Car[] cars = new Car[2];
+            for (int cnt = 0; i.hasNext(); cnt++)
+            {
+                cars[cnt] = i.next();
+            }
+            assertEquals(2, cars.length);
+            assertEquals("HONDA", cars[0].make);
+            assertEquals("TOYOTA", cars[1].make);
+            assertEquals(4, cars[0].cycl);
+            assertEquals(6, cars[1].cycl);
+        }
+        catch (Exception e)
+        {
+            assertTrue("The following error occurred in testExtractIterator(): " + e, false);
+        }
+        finally
+        {
+            try { rs.close(); } catch (Throwable t) {}
+            try { ps.close(); } catch (Throwable t) {}
+        }
+    }
+
+
+	@Freq("checkin")
+    public void testExtractHashMap()
+    {
+        PreparedStatement ps = null;
+        ResultSet rs = null;
+
+        try
+        {
+            ps = this.con.prepareStatement(SELECT_HONDA);
+            rs = ps.executeQuery();
+            ResultSetExtractor extractor = new ResultSetExtractor(rs, null);
+
+            HashMap<String, Object> map = extractor.extractHashMap();
+            assertNotNull(map);
+
+            assertEquals("HONDA", map.get("MAKE"));
+            assertEquals("CIVIC", map.get("MODEL"));
+            assertEquals(4, map.get("CYCL"));
+        }
+        catch (Exception e)
+        {
+            assertTrue("The following error occurred in testExtractHashMap(): " + e, false);
+        }
+        finally
+        {
+            try { rs.close(); } catch (Throwable t) {}
+            try { ps.close(); } catch (Throwable t) {}
+        }
+    }
+
+    private void executeSQL(String sql) throws Exception
+    {
+        PreparedStatement ps = null;
+
+        try
+        {
+            ps = this.con.prepareStatement(sql);
+            ps.execute();
+        }
+        finally
+        {
+            try { ps.close(); } catch (Throwable t) {}
+        }
+
+    }
+
+    private Connection getConnection()
+    {
+        Connection con = null;
+        try
+        {
+            Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
+            con = DriverManager.getConnection("jdbc:derby:build/databaseControlTestDB;create=true");
+        }
+        catch (Exception e)
+        {
+            assertTrue("The following error occurred in getConnection(): " + e, false);
+        }
+        return con;
+    }
+}

Added: incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/database/SQLStatementTest.java
==============================================================================
--- (empty file)
+++ incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/database/SQLStatementTest.java	Tue Oct  5 16:12:30 2004
@@ -0,0 +1,256 @@
+package org.apache.beehive.controls.test.java.database;
+
+import org.apache.beehive.controls.test.controls.database.SQLParameter;
+import org.apache.beehive.controls.test.controls.database.SQLStatement;
+import org.apache.beehive.test.tools.mantis.annotations.tch.Freq;
+import org.apache.beehive.test.tools.mantis.annotations.tch.Status;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import java.sql.*;
+
+public class SQLStatementTest extends TestCase
+{
+    private Connection con;
+    private int id;
+
+    //Test data
+    private String firstName = "Tom";
+    private String newFirstName = "Tommy";
+    private String lastName = "Hilfiger";
+    private String title = "Designer";
+
+	public SQLStatementTest(String name) {
+		super(name);
+	}
+
+    public static void main (String[] args) {
+		junit.textui.TestRunner.run (suite());
+	}
+
+	public static Test suite() {
+		return new TestSuite(SQLStatementTest.class);
+	}
+
+    public void setUp() {
+		this.con = getConnection();
+        dropTable();
+        createTable();
+	}
+
+	protected void tearDown() {
+		try { this.con.close(); } catch (Throwable t) {}
+        dropTable();
+	}
+
+
+	@Freq("checkin")
+    public void testInsert() {
+		//Test data
+		String fName = "Tom";
+		String lName = "Clancy";
+		String title = "Writer";
+		try {
+			int rowsInserted = insertRow(fName, lName, title);
+            assertEquals(1, rowsInserted);
+			Employee emp = selectByName(fName, lName);
+			assertNotNull(emp);
+			assertEquals(fName, emp.fName);
+			assertEquals(lName, emp.lName);
+			assertEquals(title, emp.title);
+		} catch (Exception e) {
+            assertTrue("The following error occurred in testInsert(): " + e, false);
+		}
+
+	}
+
+	@Freq("checkin")
+    public void testDelete() {
+		PreparedStatement ps = null;
+		ResultSet rs = null;
+
+		try {
+            int rowsInserted = insertRow(this.firstName, this.lastName, this.title);
+            assertEquals(1, rowsInserted);
+	        String sql = "DELETE FROM EMPLOYEE WHERE ID=?";
+	        Object[] values = {this.id};
+	        SQLParameter[] params = {new SQLParameter("1")};
+            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) {
+            assertTrue("The following error occurred in testDelete(): " + e, false);
+        } finally {
+            try { rs.close(); } catch (Throwable t) {}
+            try { ps.close(); } catch (Throwable t) {}
+        }
+    }
+
+	@Freq("checkin")
+    public void testUpdate() {
+        PreparedStatement ps = null;
+
+        try {
+            int rowsInserted = insertRow(this.firstName, this.lastName, this.title);
+            assertEquals(1, rowsInserted);
+
+            String sql = "UPDATE EMPLOYEE SET FNAME=? WHERE ID=?";
+            Object[] values = {this.id, this.newFirstName};
+            SQLParameter[] params = { new SQLParameter("2"), new SQLParameter("1")};
+            SQLStatement stmt = new SQLStatement(sql, params);
+            stmt.setParameterValues(values);
+            ps = stmt.getPreparedStatement(this.con);
+            int rowsUpdated = ps.executeUpdate();
+            assertEquals(1, rowsUpdated);
+
+            Employee emp = selectById();
+            assertNotNull(emp);
+            assertEquals(this.newFirstName, emp.fName);
+
+        } catch (Exception e) {
+            assertTrue("The following error occurred in testUpdate(): " + e, false);
+        } finally {
+            try { ps.close(); } catch (Throwable t) {}
+        }
+
+    }
+
+    private int insertRow(String fName, String lName, String title) throws Exception
+    {
+        String sql = "INSERT INTO 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")};
+        PreparedStatement ps = null;
+        try {
+            SQLStatement stmt = new SQLStatement(sql, params);
+            stmt.setParameterValues(values);
+            ps = stmt.getPreparedStatement(con);
+            return ps.executeUpdate();
+        } finally {
+            try { ps.close(); } catch (Throwable t) {}
+        }
+
+    }
+
+    private Employee selectByName(String fName, String lName) throws Exception {
+
+        PreparedStatement ps = null;
+        ResultSet rs = null;
+
+        try {
+            String sql = "SELECT * FROM EMPLOYEE WHERE fName=? and lName=?";
+            String[] values = {fName, lName};
+            SQLParameter[] params = { new SQLParameter("1"), new SQLParameter("2")};
+
+            SQLStatement stmt = new SQLStatement(sql, params);
+            stmt.setParameterValues(values);
+            ps = stmt.getPreparedStatement(con);
+            rs = ps.executeQuery();
+
+            if (rs.next())
+                return new Employee(rs.getString(2), rs.getString(3), rs.getString(4));
+            else
+                return null;
+
+        } finally {
+            try { rs.close(); } catch (Throwable t) {}
+            try { ps.close(); } catch (Throwable t) {}
+        }
+
+    }
+
+    private Employee selectById() throws Exception {
+
+        PreparedStatement ps = null;
+        ResultSet rs = null;
+
+        try {
+            String sql = "SELECT * FROM EMPLOYEE WHERE ID=?";
+            Object[] values = {new Integer(this.id)};
+            SQLParameter[] params = { new SQLParameter("1")};
+
+            SQLStatement stmt = new SQLStatement(sql, params);
+            stmt.setParameterValues(values);
+            ps = stmt.getPreparedStatement(con);
+            rs = ps.executeQuery();
+
+            if (rs.next())
+                return new Employee(rs.getString(2), rs.getString(3), rs.getString(4));
+            else
+                return null;
+
+        } finally {
+            try { rs.close(); } catch (Throwable t) {}
+            try { ps.close(); } catch (Throwable t) {}
+        }
+    }
+
+
+    private static Connection getConnection() {
+
+        Connection con = null;
+        try {
+            Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
+            con = DriverManager.getConnection("jdbc:derby:test;create=true");
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return con;
+
+    }
+
+    private void createTable() {
+        //Test data
+        String sql = "CREATE TABLE EMPLOYEE ( ID INT PRIMARY KEY NOT NULL, " +
+                   "FNAME VARCHAR(20), LNAME VARCHAR(20), TITLE VARCHAR(15))";
+
+        PreparedStatement ps = null;
+        try {
+            SQLStatement stmt = new SQLStatement(sql);
+            ps = stmt.getPreparedStatement(con);
+            ps.execute();
+        } catch (Exception e) {
+            assertTrue("The following error occurred in createTable(): " + e, false);
+        } finally {
+            try { ps.close(); } catch (Throwable t) {}
+        }
+    }
+
+    private void dropTable() {
+        //Test data
+        String sql = "DROP TABLE EMPLOYEE";
+        PreparedStatement ps = null;
+        try {
+            SQLStatement stmt = new SQLStatement(sql);
+            ps = stmt.getPreparedStatement(con);
+            ps.execute();
+        } catch (Exception e) {
+            //ignore
+        } finally {
+            try { ps.close(); } catch (Throwable t) {}
+        }
+    }
+
+    private class Employee {
+
+        public String fName;
+        public String lName;
+        public String title;
+
+        public Employee(String fName, String lName, String title) {
+			this.fName = fName;
+			this.lName = lName;
+			this.title = title;
+		}
+
+    }
+
+}

Added: incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/jpf/database/TestDatabaseControl.java
==============================================================================
--- (empty file)
+++ incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/jpf/database/TestDatabaseControl.java	Tue Oct  5 16:12:30 2004
@@ -0,0 +1,119 @@
+package org.apache.beehive.controls.test.jpf.database;
+
+import org.apache.beehive.test.tools.milton.junit.HtmlReportTestCase;
+import org.apache.beehive.test.tools.mantis.annotations.tch.Freq;
+import org.apache.beehive.test.tools.mantis.annotations.tch.Status;
+
+
+/**
+ * Tests controls inheritance by invoking a sub control on a pageflow.
+ */
+public class TestDatabaseControl extends HtmlReportTestCase
+{
+	public TestDatabaseControl(String s)
+	{
+		super(s);
+	}
+
+	protected void setUp()
+	{
+		try
+		{
+			createTable();
+			insertEmployees();
+		}
+		catch (Exception e)
+		{
+			assertTrue("The following error occurred in setUp(): " + e, false);
+		}
+
+	}
+
+	protected void tearDown()
+	{
+		try
+		{
+			dropTable();
+        }
+        catch (Exception e)
+        {
+            //ignore
+        }
+	}
+
+    private void createTable() throws Exception
+    {
+		assertReport("/controlsWeb/database/testCreateTable.do");
+    }
+
+    private void dropTable() throws Exception
+    {
+		assertReport("/controlsWeb/database/testDropTable.do");
+    }
+
+    private void insertEmployees() throws Exception
+    {
+		assertReport("/controlsWeb/database/testInsertEmployees.do");
+    }
+
+    /**
+     * Tests invoking a method inherited from the super control
+     * The sub control is instantiated programmatically
+     */
+	@Freq("checkin")
+    public void testSelectEmployeesWithArray() throws Exception
+    {
+		assertReport("/controlsWeb/database/testSelectEmployeesWithArray.do");
+    }
+
+    /**
+     * Tests invoking a method inherited from the super control
+     * The sub control is instantiated programmatically
+     */
+	@Freq("checkin")
+    public void testSelectEmployeesWithIterator() throws Exception
+    {
+		assertReport("/controlsWeb/database/testSelectEmployeesWithIterator.do");
+    }
+
+    /**
+     * Tests invoking a method inherited from the super control
+     * The sub control is instantiated programmatically
+     */
+	@Freq("checkin")
+    public void testSelectEmployeeWithHashMap() throws Exception
+    {
+		assertReport("/controlsWeb/database/testSelectEmployeeWithHashMap.do");
+    }
+
+    /**
+     * Tests invoking a method inherited from the super control
+     * The sub control is instantiated programmatically
+     */
+	@Freq("checkin")
+    public void testSelectOneEmployeeWithMaxRow() throws Exception
+    {
+		assertReport("/controlsWeb/database/testSelectOneEmployeeWithMaxRow.do");
+    }
+
+    /**
+     * Tests invoking a method inherited from the super control
+     * The sub control is instantiated programmatically
+     */
+	@Freq("checkin")
+    public void testUpdateEmployee() throws Exception
+    {
+		assertReport("/controlsWeb/database/testUpdateEmployee.do");
+    }
+
+    /**
+     * Tests invoking a method inherited from the super control
+     * The sub control is instantiated programmatically
+     */
+	@Freq("checkin")
+    public void testDeleteEmployee() throws Exception
+    {
+		assertReport("/controlsWeb/database/testDeleteEmployee.do");
+    }
+
+}

Modified: incubator/beehive/trunk/controls/test/webapps/build.xml
==============================================================================
--- incubator/beehive/trunk/controls/test/webapps/build.xml	(original)
+++ incubator/beehive/trunk/controls/test/webapps/build.xml	Tue Oct  5 16:12:30 2004
@@ -58,6 +58,9 @@
         <condition property="do.inject.milton">
            <istrue value="${app.inject.milton}"/>
         </condition>
+        <condition property="do.inject.derby">
+           <istrue value="${app.inject.derby}"/>
+        </condition>        
         <condition property="do.inject.test.controls">
            <isset property="app.inject.test.controls"/>
         </condition>
@@ -96,6 +99,7 @@
 
         <antcall target="-inject.netui"/>
         <antcall target="-inject.milton"/>
+        <antcall target="-inject.derby"/>
         <antcall target="-inject.test.controls"/>
         <antcall target="-inject.test.drivers"/>
         <antcall target="-build.webapp"/>
@@ -142,6 +146,13 @@
         </copy>
     </target>
  
+    <target name="-inject.derby" if="do.inject.derby">
+        <echo message="Injecting ${derby.jar} to ${webapp.name}"/>
+        <copy todir="${webapp.dir}/WEB-INF/lib" 
+              file="${derby.jar}" verbose="true" 
+              overwrite="true"/>
+    </target>
+
     <target name="-inject.test.controls" if="do.inject.test.controls">
         <antcall target="-inject.test.controls.src"/>
         <antcall target="-inject.test.controls.jar"/>

Modified: incubator/beehive/trunk/controls/test/webapps/controlsWeb/app.properties
==============================================================================
--- incubator/beehive/trunk/controls/test/webapps/controlsWeb/app.properties	(original)
+++ incubator/beehive/trunk/controls/test/webapps/controlsWeb/app.properties	Tue Oct  5 16:12:30 2004
@@ -1,5 +1,6 @@
 app.inject.netui: true
 app.inject.milton: true
+app.inject.derby: true
 ### these two can be set to 'jar' or 'src' ###
 app.inject.test.drivers: jar
 app.inject.test.controls: jar

Added: incubator/beehive/trunk/controls/test/webapps/controlsWeb/database/Controller.jpf
==============================================================================
--- (empty file)
+++ incubator/beehive/trunk/controls/test/webapps/controlsWeb/database/Controller.jpf	Tue Oct  5 16:12:30 2004
@@ -0,0 +1,167 @@
+/*
+ *
+ * N E T U I
+ *
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * All Rights Reserved. Unpublished rights reserved under the copyright laws
+ * of the United States. The software contained on this media is proprietary
+ * to and embodies the confidential technology of BEA Systems, Inc. The
+ * possession or receipt of this information does not convey any right to
+ * disclose its contents, reproduce it, or use,  or license the use,
+ * for manufacture or sale, the information or anything described
+ * therein. Any use, disclosure, or reproduction without BEA System's
+ * prior written permission is strictly prohibited.
+ *
+ * $Header:$
+ */
+package database;
+
+import org.apache.beehive.netui.pageflow.PageFlowController;
+import org.apache.beehive.netui.pageflow.Forward;
+import org.apache.beehive.netui.pageflow.FormData;
+import org.apache.beehive.netui.pageflow.annotations.Jpf;
+
+import org.apache.beehive.controls.api.bean.Control;
+import org.apache.beehive.controls.api.bean.ControlBean;
+import org.apache.beehive.controls.test.controls.database.test.TestDBControlBean;
+import org.apache.beehive.controls.test.driver.database.DriveDatabaseControl;
+import org.apache.beehive.test.tools.milton.common.Report;
+
+/* Test control inheritance by invoking methods on a sub control instance*/
+
+@Jpf.Controller(
+    forwards = {
+        @Jpf.Forward(name=Report.RESULTS,path = Report.RESULTSJSP)
+    })
+public class Controller extends PageFlowController
+{
+
+    @Control
+    private TestDBControlBean testDBControl;
+
+    transient private DriveDatabaseControl driver = new DriveDatabaseControl(this.testDBControl);
+
+    @Jpf.Action(
+        )
+    protected Forward begin(){
+		Report report =new Report();
+		report.setStatus(Report.PASS);
+		report.setMessage("This is a bogus test.");
+
+        return new Forward(Report.RESULTS, Report.KEY, report);
+    }
+
+    /*
+     * Invokes create table
+     */
+    @Jpf.Action(
+        )
+    protected Forward testCreateTable()
+    {
+		driver.setControl(testDBControl);
+		Report report = this.driver.doCreateTable();
+        return new Forward(Report.RESULTS, Report.KEY, report);
+    }
+
+    /*
+     * Invokes drop table
+     */
+    @Jpf.Action(
+        )
+    protected Forward testDropTable()
+    {
+		driver.setControl(testDBControl);
+		Report report = this.driver.doDropTable();
+        return new Forward(Report.RESULTS, Report.KEY, report);
+    }
+
+
+    /*
+     * Invokes insert employee
+     */
+    @Jpf.Action(
+        )
+    protected Forward testInsertEmployees()
+    {
+		driver.setControl(testDBControl);
+		Report report = this.driver.doInsertEmployees();
+        return new Forward(Report.RESULTS, Report.KEY, report);
+    }
+
+    /*
+     * Invokes select employees with array
+     */
+    @Jpf.Action(
+        )
+    protected Forward testSelectEmployeesWithArray()
+    {
+		driver.setControl(testDBControl);
+		Report report = this.driver.doSelectEmployeesWithArray();
+        return new Forward(Report.RESULTS, Report.KEY, report);
+    }
+
+    /*
+     * Invokes select employees with Iterator
+     */
+    @Jpf.Action(
+        )
+    protected Forward testSelectEmployeesWithIterator()
+    {
+		driver.setControl(testDBControl);
+		Report report = this.driver.doSelectEmployeesWithIterator();
+        return new Forward(Report.RESULTS, Report.KEY, report);
+    }
+
+    /*
+     * Invokes select employee with HashMap
+     */
+    @Jpf.Action(
+        )
+    protected Forward testSelectEmployeeWithHashMap()
+    {
+		driver.setControl(testDBControl);
+		Report report = this.driver.doSelectEmployeesWithHashMap();
+        return new Forward(Report.RESULTS, Report.KEY, report);
+    }
+
+    /*
+     * Invokes select employees with max row
+     */
+    @Jpf.Action(
+        )
+    protected Forward testSelectOneEmployeeWithMaxRow()
+    {
+		driver.setControl(testDBControl);
+		Report report = this.driver.doSelectOneEmployeeWithMaxRow();
+        return new Forward(Report.RESULTS, Report.KEY, report);
+    }
+
+
+    /*
+     * Invokes update employee
+     */
+    @Jpf.Action(
+        )
+    protected Forward testUpdateEmployee()
+    {
+		driver.setControl(testDBControl);
+		Report report = this.driver.doUpdateEmployee();
+        return new Forward(Report.RESULTS, Report.KEY, report);
+    }
+
+    /*
+     * Invokes delete employee
+     */
+    @Jpf.Action(
+        )
+    protected Forward testDeleteEmployee()
+    {
+		driver.setControl(testDBControl);
+		Report report = this.driver.doDeleteEmployee();
+        return new Forward(Report.RESULTS, Report.KEY, report);
+    }
+
+}
+
+