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 2006/07/13 03:34:07 UTC

svn commit: r421473 [2/6] - in /beehive/sandbox/hornet: ./ controls/ controls/api/ controls/api/src/ controls/api/src/main/ controls/api/src/main/java/ controls/api/src/main/java/org/ controls/api/src/main/java/org/apache/ controls/api/src/main/java/or...

Added: beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/DefaultResultSetMapper.java
URL: http://svn.apache.org/viewvc/beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/DefaultResultSetMapper.java?rev=421473&view=auto
==============================================================================
--- beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/DefaultResultSetMapper.java (added)
+++ beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/DefaultResultSetMapper.java Wed Jul 12 18:34:03 2006
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+
+package org.apache.beehive.controls.system.jdbc;
+
+import java.lang.reflect.Method;
+import java.sql.ResultSet;
+import java.util.Calendar;
+
+/**
+ * Default ResultSetMapper implementation for ResultSets.
+ */
+public class DefaultResultSetMapper extends ResultSetMapper {
+
+    /**
+     * Maps a ResultSet to a ResultSet.  The default implementation is a NOOP.
+     *
+     * @param m         Method assoicated with this call.
+     * @param resultSet Result set to map.
+     * @param cal       A Calendar instance for resolving date/time values.
+     * @return          An object.
+     */
+    public Object mapToResultType(Method m, ResultSet resultSet, Calendar cal) {
+        return resultSet;
+    }
+
+    /**
+     * Can the ResultSet which this mapper uses be closed by the database control?
+     * @return always false
+     */
+    public boolean canCloseResultSet() { return false; }
+}

Propchange: beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/DefaultResultSetMapper.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/DefaultRowSetResultSetMapper.java
URL: http://svn.apache.org/viewvc/beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/DefaultRowSetResultSetMapper.java?rev=421473&view=auto
==============================================================================
--- beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/DefaultRowSetResultSetMapper.java (added)
+++ beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/DefaultRowSetResultSetMapper.java Wed Jul 12 18:34:03 2006
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+
+package org.apache.beehive.controls.system.jdbc;
+
+import com.sun.rowset.CachedRowSetImpl;
+import org.apache.beehive.controls.api.ControlException;
+import org.apache.beehive.controls.api.PropertySetReader;
+import org.apache.beehive.controls.system.jdbc.JdbcControl.SQL;
+
+import javax.sql.RowSet;
+import java.lang.reflect.Method;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Calendar;
+
+/**
+ * Default ResultSetMapper implementation for RowSets.
+ */
+public class DefaultRowSetResultSetMapper extends ResultSetMapper {
+
+    /**
+     * Map a ResultSet to a RowSet.  Type of RowSet is defined by the SQL annotation for the method.
+     *
+     * @param m         Method assoicated with this call.
+     * @param resultSet Result set to map.
+     * @param cal       A Calendar instance for resolving date/time values.
+     * @return A RowSet object.
+     */
+    public RowSet mapToResultType(Method m, ResultSet resultSet, Calendar cal) {
+        final SQL methodSQL = PropertySetReader.getMethodPropertySet(m, SQL.class);
+        final int maxrows = methodSQL.maxRows();
+
+        try {
+            CachedRowSetImpl rows = new CachedRowSetImpl();
+
+            if (maxrows > 0) {
+                rows.setMaxRows(maxrows);
+            }
+
+            rows.populate(resultSet);
+            return rows;
+        } catch (SQLException e) {
+            throw new ControlException(e.getMessage(), e);
+        }
+    }
+
+    /**
+     * Can the ResultSet which this mapper uses be closed by the database control?
+     *
+     * @return always false
+     */
+    public boolean canCloseResultSet() { return false; }
+}

Propchange: beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/DefaultRowSetResultSetMapper.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/DefaultXmlObjectResultSetMapper.java
URL: http://svn.apache.org/viewvc/beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/DefaultXmlObjectResultSetMapper.java?rev=421473&view=auto
==============================================================================
--- beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/DefaultXmlObjectResultSetMapper.java (added)
+++ beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/DefaultXmlObjectResultSetMapper.java Wed Jul 12 18:34:03 2006
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+
+package org.apache.beehive.controls.system.jdbc;
+
+import org.apache.beehive.controls.api.ControlException;
+import org.apache.beehive.controls.api.PropertySetReader;
+import org.apache.beehive.controls.system.jdbc.JdbcControl.SQL;
+
+import java.lang.reflect.Method;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Calendar;
+
+/**
+ * Default ResultSetMapper implementation for XmlObjects.
+ */
+public class DefaultXmlObjectResultSetMapper extends DefaultObjectResultSetMapper {
+
+    /**
+     * Map a ResultSet to an XmlObject.  Object type is defined by the return type of the method.
+     *
+     * @param m         Method associated with this call.
+     * @param resultSet Result set to map.
+     * @param cal       A Calendar instance for resolving date/time values.
+     * @return An XmlObject
+     */
+    public Object mapToResultType(Method m, ResultSet resultSet, Calendar cal) {
+
+        final Class returnType = m.getReturnType();
+        final boolean isArray = returnType.isArray();
+
+        try {
+            if (isArray) {
+                final SQL methodSQL = PropertySetReader.getMethodPropertySet(m, SQL.class);
+                return arrayFromResultSet(resultSet, methodSQL.arrayMaxLength(), returnType, cal);
+            } else {
+
+                if (!resultSet.next()) {
+                    return _tmf.fixNull(m.getReturnType());
+                }
+
+                return RowMapperFactory.getRowMapper(resultSet, returnType, cal).mapRowToReturnType();
+            }
+        } catch (SQLException e) {
+            throw new ControlException(e.getMessage(), e);
+        }
+    }
+}

Propchange: beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/DefaultXmlObjectResultSetMapper.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/JdbcControl.java
URL: http://svn.apache.org/viewvc/beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/JdbcControl.java?rev=421473&view=auto
==============================================================================
--- beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/JdbcControl.java (added)
+++ beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/JdbcControl.java Wed Jul 12 18:34:03 2006
@@ -0,0 +1,643 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+
+package org.apache.beehive.controls.system.jdbc;
+
+import org.apache.beehive.controls.api.PropertySet;
+
+import javax.naming.NamingException;
+import javax.naming.Context;
+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.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.sql.SQLData;
+import java.util.Calendar;
+import java.util.List;
+import java.util.Arrays;
+
+/**
+ * Simplifies access to a relational database from your Java code using SQL commands.
+ * The Jdbc Control handles the work of connecting to, sending queries to, and ResultSet mapping from
+ * the database. You don't need to know how to use JDBC in order to use the Jdbc Control, just basic SQL.
+ * <p/>
+ * To use a Jdbc Control create a .jcx file (java file with a .jcx extension) which extends this interface.
+ * Add annotations to the jcx to tell the Jdbc Control how to connect to your database instance (either
+ * ConnectionDataSource or ConnectionDriver), then add methods which include SQL annotations to access the database.
+ */
+public interface JdbcControl {
+
+
+    /**
+     * Returns a database connection to the server associated
+     * with the control. It is typically not necessary to call this method
+     * when using the control.
+     *
+     * @return A Connection a database.
+     */
+    public Connection getConnection() throws SQLException;
+
+    /**
+     * Sets the Calendar instance that should be used when setting and getting
+     * {@link java.sql.Date Date}, {@link java.sql.Time Time}, and
+     * {@link java.sql.Timestamp Timestamp} values.
+     *
+     * @see java.sql.ResultSet#getDate(int, Calendar) java.sql.ResultSet#getDate(int, Calendar)
+     * @see java.sql.ResultSet#getTime(int, Calendar) java.sql.ResultSet#getTime(int, Calendar)
+     * @see java.sql.ResultSet#getTimestamp(int, Calendar) java.sql.ResultSet#getTimestamp(int, Calendar)
+     * @see java.sql.PreparedStatement#setDate(int, java.sql.Date, Calendar) java.sql.PreparedStatement#setDate(int, Date, Calendar)
+     * @see java.sql.PreparedStatement#setTime(int, java.sql.Time, Calendar) java.sql.PreparedStatement#setTime(int, Time, Calendar)
+     * @see java.sql.PreparedStatement#setTimestamp(int, java.sql.Timestamp, Calendar) java.sql.PreparedStatement#setTimestamp(int, Timestamp, Calendar)
+     */
+    public void setDataSourceCalendar(Calendar cal);
+
+    /**
+     * Gets the Calendar instance used when setting and getting
+     * {@link java.sql.Date Date}, {@link java.sql.Time Time}, and
+     * {@link java.sql.Timestamp Timestamp} values. This is the Calendar
+     * set by the setDataSourceCalendar method.
+     *
+     * @return The Calendar instance.
+     */
+    public Calendar getDataSourceCalendar();
+
+
+
+
+// ********************************************************************************************************************
+// ********************************************************************************************************************
+//                          Class-level Database Connection Annotations and Supporting Constructs
+// ********************************************************************************************************************
+// ********************************************************************************************************************
+
+
+    /**
+     * Abstract base class for a user defined Jndi Context factory which can be used
+     * as a value for the jndiContextFactory member of the ConnectionDataSource
+     * annotation.
+     */
+    public static abstract class JndiContextFactory {
+
+        /**
+         * Get a JNDI InitialContext instance.
+         *
+         * @return InitialContext instance
+         * @throws NamingException if context could not be found.
+         */
+        public abstract Context getContext() throws NamingException;
+    }
+
+    /**
+     * Class-level annotation for making a DataSource available for use with the Jdbc Control. Either this annotation or
+     * the ConnectionDriver annotation must be set for a jcx which extends the JdbcControl interface.
+     */
+    @PropertySet(prefix = "ConnectionDataSource")
+    @Inherited
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ElementType.TYPE, ElementType.FIELD})
+    public @interface ConnectionDataSource {
+
+        /**
+         * The jndi name of the DataSource. This is a required element for this annotation.
+         */
+        String jndiName();
+
+        /**
+         * The name of a class which implements the IJndiContextFactory interface. This is an optional element of this annotation.
+         */
+        Class<? extends JndiContextFactory> jndiContextFactory() default DefaultJndiContextFactory.class;
+    }
+
+    /* ConnectionDataSource( jndiName ) accessors */
+    public String getConnectionDataSourcejndiName();
+    public void   setConnectionDataSourcejndiName(String s);
+
+    /* ConnectionDataSource( jndiContextFactory ) accessors */
+    public Class<? extends JndiContextFactory> getConnectionDataSourcejndiContextFactory();
+    public void                                setConnectionDataSourcejndiContextFactory(Class<? extends JndiContextFactory> jcf);
+
+    /**
+     * Class-level annotation for making a ConnectionDriver available for use with the Jdbc Control. Either this
+     * annotation or the ConnectionDataSource annotation must be set for a jcx which extends the JdbcControl interface.
+     * See java.sql.DatabaseConnection for additional information about the elements of this annotation.
+     */
+    @PropertySet(prefix = "ConnectionDriver")
+    @Inherited
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ElementType.TYPE, ElementType.FIELD})
+    public @interface ConnectionDriver {
+
+        /**
+         * A String containing the fully qualified name of the database driver class. Required element.
+         */
+        String databaseDriverClass();
+
+        /**
+         * A String containing the database URL to connect to. Required element.
+         */
+        String databaseURL();
+
+        /**
+         * A String containing the user name to connect to the database as. Optional element.
+         */
+        String userName()                               default "";
+
+        /**
+         * A String containing the password associated with userName. Optional element.
+         */
+        String password()                               default "";
+
+        /**
+         * A String containing a comma seperated list of name/value pairs for the DatabaseConnection. Optional element.
+         */
+        String properties()                             default "";
+    }
+
+    /* ConnectionDriver( databaseDriverClass ) */
+    public String getConnectionDriverdatabaseDriverClass();
+    public void   setConnectionDriverdatabaseDriverClass(String s);
+
+    /* ConnectionDriver( databaseUrl ) */
+    public String getConnectionDriverdatabaseUrl();
+    public void   setConnectionDriverdatabaseUrl(String s);
+
+    /* ConnectionDriver( userName ) */
+    public String getConnectionDriveruserName();
+    public void   setConnectionDriveruserName(String s);
+
+    /* ConnectionDriver( password ) */
+    public String getConnectionDriverpassword();
+    public void   setConnectionDriverpassword(String s);
+
+    /* ConnectionDriver( properties ) */
+    public String getConnectionDriverproperties();
+    public void   setConnectionDriverproperties(String s);
+
+
+    /**
+     * Class level annotation used to set options on the JDBC connnection.
+     */
+    @PropertySet(prefix = "ConnectionOptions")
+    @Inherited
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ElementType.TYPE, ElementType.FIELD})
+    public @interface ConnectionOptions {
+
+        /**
+         * If set to true, database connection will optimize for read only queries, writes still permitted.
+         * Optional, defaults to false.
+         */
+        boolean readOnly()                              default false;
+
+        /**
+         * Specifies ResultSet holdability for the connection.  May be overridden at method level.
+         * Optional, defaults to jdbc driver's default setting.
+         */
+        HoldabilityType resultSetHoldability()          default HoldabilityType.DRIVER_DEFAULT;
+
+        /**
+         * Specifies type mappings for SQL user defined types (UDTs).  Any type mappings set here will be used
+         * by the underlying JDBC Connection for UDT type mappings.  These mappings can be overridden by using
+         * the SQL annotations methodTypeMappers element.  Optional element.
+         */
+        TypeMapper[] typeMappers()                      default {};
+    }
+
+    /* ConnectionOptions( readOnly ) */
+    public boolean getConnectionOptionsreadOnly();
+    public    void setConnectionOptionsreadOnly(boolean b);
+
+    /* ConnectionOptions( resultSetHoldability ) */
+    public HoldabilityType getConnectionOptionsresultSetHoldability();
+    public            void setConnectionOptionsresultSetHoldability(HoldabilityType ht);
+
+    /* ConnectionOptions( typeMappers ) */
+    public TypeMapper[] getConnectionOptionstypeMappers();
+    public         void setConnectionOptionstypeMappers(TypeMapper[] tm);
+
+    /**
+     * Class / method level annotation for mapping SQL user defined types (UDTs) to and from java objects.
+     * The mapper class element must implement the java.sql.SQLData interface.
+     */
+    @PropertySet(prefix = "TypeMapper")
+    @Inherited
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ElementType.TYPE, ElementType.METHOD})
+    public @interface TypeMapper {
+        String UDTName();
+        Class<? extends SQLData> mapperClass();
+    }
+
+    /* TypeMapper( UDTName ) */
+    public String getTypeMapperUDTName();
+    public   void setTypeMapperUDTName(String n);
+
+    /* TypeMapper( mapperClass ) */
+    public Class<? extends SQLData> getTypeMappermapperClass();
+    public                     void setTypeMappermapperClass(Class<? extends SQLData> c);
+
+
+// ********************************************************************************************************************
+// ********************************************************************************************************************
+//                          SQL Method-level Annotation and Supporting Constructs
+// ********************************************************************************************************************
+// ********************************************************************************************************************
+
+    /**
+     * This constant can be used as the value for the maxRows element of the SQL annotation.
+     * It indicates that all rows should be returned (i.e. no limit)
+     */
+    public final int MAXROWS_ALL = 0;
+
+    /**
+     * The default fetch size for result sets, indicates the database should determine the fetch size.
+     */
+    public final int DEFAULT_FETCH_SIZE = 0;
+
+    /**
+     * Default value for the iteratorElementType element of the
+     * SQL annotation.  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 {
+    }
+
+    /**
+     * Default value for the resultSetMapper element of the
+     * SQL annotation.  It signals that no type has been defined for the method.
+     */
+    public interface UndefinedResultSetMapper {
+    }
+
+    /**
+     * Enumeration of supported types of scrolling ResultSets
+     */
+    public enum ScrollType {
+        DRIVER_DEFAULT (-1, -1),
+        FORWARD_ONLY (ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY),
+        SCROLL_INSENSITIVE (ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY),
+        SCROLL_SENSITIVE (ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY),
+        FORWARD_ONLY_UPDATABLE (ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE),
+        SCROLL_INSENSITIVE_UPDATABLE (ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE),
+        SCROLL_SENSITIVE_UPDATABLE (ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
+
+        private final int _type;
+        private final int _concurrencyType;
+
+        ScrollType(int scrollType, int concurrencyType) {
+            _type = scrollType;
+            _concurrencyType = concurrencyType;
+        }
+
+        public int getType() { return _type; }
+
+        public int getConcurrencyType() { return _concurrencyType; }
+
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            if (_type == ResultSet.TYPE_FORWARD_ONLY) {
+                sb.append("Foward Only, ");
+            } else if (_type == ResultSet.TYPE_SCROLL_INSENSITIVE) {
+                sb.append("Scroll Insensitive, ");
+            } else if (_type == ResultSet.TYPE_SCROLL_SENSITIVE) {
+                sb.append("Scroll Sensitive, ");
+            } else {
+                sb.append("Jdbc Driver Default Direction");
+            }
+
+            if (_concurrencyType == ResultSet.CONCUR_READ_ONLY) {
+                sb.append("Read Only");
+            } else if (_concurrencyType == ResultSet.CONCUR_UPDATABLE) {
+                sb.append("Updatable");
+            } else {
+                sb.append("Jdbc Driver Default");
+            }
+            return sb.toString();
+        }
+    }
+
+    /**
+     * Enumeration of supported fetch directions.
+     */
+    public enum FetchDirection {
+        FORWARD (ResultSet.FETCH_FORWARD),
+        REVERSE (ResultSet.FETCH_REVERSE),
+        UNKNOWN (ResultSet.FETCH_UNKNOWN);
+
+        private final int _direction;
+
+        FetchDirection(int direction) {
+            _direction = direction;
+        }
+
+        public int getDirection() { return _direction; }
+    }
+
+    /**
+     * Enumeration of supported fetch directions.
+     */
+    public enum HoldabilityType {
+        DRIVER_DEFAULT (0),
+        HOLD_CURSORS (ResultSet.HOLD_CURSORS_OVER_COMMIT),
+        CLOSE_CURSORS (ResultSet.CLOSE_CURSORS_AT_COMMIT);
+
+        private final int _holdability;
+
+        HoldabilityType(int holdability) {
+            _holdability = holdability;
+        }
+
+        public int getHoldability() { return _holdability; }
+
+        public String toString() {
+            if (_holdability == ResultSet.HOLD_CURSORS_OVER_COMMIT) {
+                return "HOLD_CURSORS_OVER_COMMIT";
+            } else if (_holdability == ResultSet.CLOSE_CURSORS_AT_COMMIT) {
+                return "CLOSE_CURSORS_AT_COMMIT";
+            } else {
+                return "Default driver holdability";
+            }
+        }
+    }
+
+    /**
+     * Method-level annotation for methods in a jcx which wish to access a database instance.
+     */
+    @PropertySet(prefix = "SQL")
+    @Inherited
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ElementType.METHOD})
+    public @interface SQL {
+
+        /**
+         * The SQL statement to send to the database. Required annotation element.
+         */
+        String statement();
+
+
+        /**
+         * Maximum array length.
+         * This element has no effect on the call unless the method return type is an array.
+         * Optional element.
+         */
+        int arrayMaxLength()                            default 1024;
+
+
+        /**
+         * Max number of ResultSet rows to return.
+         * If used with arrayMaxLength the smaller value is used.
+         * Optional element, default value is no limit on number of rows returned.
+         */
+        int maxRows()                                   default MAXROWS_ALL;
+
+
+        /**
+         * Execute the SQL statement as a batch update.
+         * Methods which have this element set to true must return an array of ints.
+         * Optional element, defaults to false.
+         */
+        boolean batchUpdate()                           default false;
+
+
+        /**
+         * Specify the fetch size for the ResultSet. Optional element, defaults to 0.
+         */
+        int fetchSize()                                 default DEFAULT_FETCH_SIZE;
+
+
+        /**
+         * Specify the fetch direction for the ResultSEt. Optional element, defaults to FORWARD.
+         */
+        FetchDirection fetchDirection()                 default FetchDirection.FORWARD;
+
+
+        /**
+         * Return the generated key values generated by the SQL statement. Optional element, defaults to false.
+         */
+        boolean getGeneratedKeys()                      default false;
+
+
+        /**
+         * Specify generated key columns by column names to return when the getGeneratedKeys element is true.
+         * May only be set if getGeneratedKeys is set to true, otherwise a compile time error is generated.
+         * Optional element.
+         */
+        String[] generatedKeyColumnNames()              default {};
+
+
+        /**
+         * Specify generated key columns by column number to return when the getGeneratedKeys element is true.
+         * May only be set if getGeneratedKeys is set to true, otherwise a compile time error is generated
+         * Optional element.
+         */
+        int[] generatedKeyColumnIndexes()               default {};
+
+
+        /**
+         * Specify the holdability type for the annotated method.  Overrides the holability annotation element
+         * of the ConnectionOptions annotation.  The holdability type will be in effect for the duration of this
+         * method call. Optional, defaults to DRIVER_DEFAULT.
+         */
+        HoldabilityType resultSetHoldabilityOverride()  default HoldabilityType.DRIVER_DEFAULT;
+
+
+        /**
+         * Specifies type mappings for SQL user defined types (UDTs).  Any type mappings set here will be used
+         * by the underlying JDBC Connection for UDT type mappings. These type mappings will REPLACE any set on
+         * the JDBC connection for the duration of the method call. Optional element.
+         */
+        TypeMapper[] typeMappersOverride()              default {};
+
+
+        /**
+         * Specify the type of element to be interated over when the method's return type is java.util.Iterator.
+         * Optional element.
+         */
+        Class iteratorElementType()                     default UndefinedIteratorType.class;
+
+
+        /**
+         * Specify a custom result set mapper for the ResultSet generated by the SQL statement.
+         * ResultSet mappers must extend the ResultSetMapper abstract base class.  If a value is specified
+         * it will be used to map the ResultSet of the query to the return type of the method.
+         * See org.apache.beehive.controls.system.jdbc.ResultSetMapper for additional information.
+         * Optional element.
+         */
+        Class resultSetMapper()                         default UndefinedResultSetMapper.class;
+
+
+        /**
+         * Specify that the ResultSet returned by the method is scrollable. Valid only for methods which
+         * return a ResultSet, otherwise a compile-time error will occur.  Valid element values
+         * are defined by the ScrollType enumeration.
+         * Optional element, defaults to JDBC driver's default setting.
+         */
+        ScrollType scrollableResultSet()                default ScrollType.DRIVER_DEFAULT;
+    } // SQL annotation declaration
+
+
+// ********************************************************************************************************************
+// ********************************************************************************************************************
+//                                               Inner Classes
+// ********************************************************************************************************************
+// ********************************************************************************************************************
+
+    /**
+     * Nested class used for specifing parameters for a callable statement.  If a method in a control extension takes an array of
+     * SQLParameter, the JdbcControl treats the SQL as a CallableStatement and inserts values into the statement from
+     * the SQLParameter array.  After the CallableStatement executes, results are mapped into OUT type parameters found
+     * int the SQLParameter array.
+     * NOTE: To invoke a callable statement which does not take any arguments, an SQLParameter array of size zero must
+     * be passed to the JDBCControl method.
+     */
+    public static class SQLParameter {
+        /**
+         * IN direction constant.
+         */
+        public static final int IN = 1;
+        /**
+         * OUT direction constant.
+         */
+        public static final int OUT = 2;
+        /**
+         * IN and OUT directions constant.
+         */
+        public static final int INOUT = IN | OUT;
+
+        /**
+         * Parameter value. For parameters of type OUT this value should be set to null.
+         */
+        public Object value = null;
+
+        /**
+         * Parameter SQL data type. See java.sql.Types.
+         */
+        public int type = Types.NULL;
+
+        /**
+         * Parameter direction.
+         */
+        public int dir = IN;
+
+        /**
+         * Create a new SQLParameter with the specified value.
+         *
+         * @param value The parameter value.
+         */
+        public SQLParameter(Object value) {
+            this.value = value;
+        }
+
+        /**
+         * Create a new SQLParameter with the specified value and SQL data type.
+         *
+         * @param value The parameter value.
+         * @param type  SQL data type.
+         */
+        public SQLParameter(Object value, int type) {
+            this(value);
+            this.type = type;
+        }
+
+        /**
+         * Create a new SQLParameter with the specified value, SQL data type and direction.
+         *
+         * @param value The parameter value.
+         * @param type  SQL data type.
+         * @param dir   IN / OUT or INOUT
+         */
+        public SQLParameter(Object value, int type, int dir) {
+            this(value, type);
+            this.dir = dir;
+        }
+
+        /**
+         * Clone this parameter.
+         *
+         * @return A copy of this parameter.
+         */
+        public Object clone() {
+            return new SQLParameter(value, type, dir);
+        }
+    }
+
+    /**
+     * A ComplexSqlFragment can be used as a return value from a parameter reflection operation for
+     * return values which contain BOTH SQL text and parameters.  For Example, the text portion
+     * could be something like 'where NAME = ?' and the parameter value is 'Fred'.
+     */
+    public static class ComplexSqlFragment {
+
+        protected CharSequence sql;
+        protected List<SQLParameter> parameters;
+
+        /**
+         * Create a new SQLFragment.
+         */
+        public ComplexSqlFragment() {
+            sql = null;
+            parameters = null;
+        }
+
+        /**
+         * Create a new SQLFragment with the specified SQL and parameter list.
+         *
+         * @param sql        SQL contents of the fragment.
+         * @param parameters Substitution parameters.
+         */
+        public ComplexSqlFragment(String sql, SQLParameter[] parameters) {
+            this.sql = sql;
+            if (null != parameters)
+                this.parameters = Arrays.asList(parameters);
+        }
+
+        /**
+         * Get the SQL of this fragment.
+         *
+         * @return String.
+         */
+        public String getSQL() {
+            return sql.toString();
+        }
+
+        /**
+         * Get the parameters contained within this fragment.
+         * Returns a zero-based array.
+         *
+         * @return SQLParameter array.
+         */
+        public SQLParameter[] getParameters() {
+            if (null == parameters)
+                return new SQLParameter[0];
+            return parameters.toArray(new SQLParameter[parameters.size()]);
+        }
+
+        /**
+         * Get the SQL string contained within this fragment.
+         * @return String.
+         */
+        public String toString() {
+            return sql.toString();
+        }
+    }
+}

Propchange: beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/JdbcControl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/JdbcControlImpl.java
URL: http://svn.apache.org/viewvc/beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/JdbcControlImpl.java?rev=421473&view=auto
==============================================================================
--- beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/JdbcControlImpl.java (added)
+++ beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/JdbcControlImpl.java Wed Jul 12 18:34:03 2006
@@ -0,0 +1,544 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+package org.apache.beehive.controls.system.jdbc;
+
+import java.lang.reflect.Method;
+import java.sql.*;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Vector;
+import javax.naming.NamingException;
+import javax.naming.Context;
+import javax.sql.DataSource;
+
+import org.apache.beehive.controls.api.ControlException;
+import org.apache.beehive.controls.api.Extensible;
+import org.apache.beehive.controls.api.PropertySetReader;
+import org.apache.beehive.controls.system.jdbc.parser.SqlParser;
+import org.apache.beehive.controls.system.jdbc.parser.SqlStatement;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * The implementation class for the database controller.
+ */
+public class JdbcControlImpl implements JdbcControl, Extensible, java.io.Serializable {
+
+    protected transient Connection _connection;
+    protected transient DataSource _dataSource;
+
+    private Calendar _cal;
+    private transient Vector<PreparedStatement> _resources;
+
+    private static final String EMPTY_STRING = "";
+    private static final Log LOGGER = LogFactory.getLog(JdbcControlImpl.class);
+    private static final ResultSetMapper DEFAULT_MAPPER = new DefaultObjectResultSetMapper();
+    private static final SqlParser _sqlParser = new SqlParser();
+
+    protected static final HashMap<Class, ResultSetMapper> _resultMappers = new HashMap<Class, ResultSetMapper>();
+    protected static Class<?> _xmlObjectClass;
+
+    //
+    // initialize the result mapper table
+    //
+    static {
+        _resultMappers.put(ResultSet.class, new DefaultResultSetMapper());
+        _resultMappers.put(Iterator.class, new DefaultIteratorResultSetMapper());
+
+        try {
+            _xmlObjectClass = Class.forName("org.apache.xmlbeans.XmlObject");
+            _resultMappers.put(_xmlObjectClass, new DefaultXmlObjectResultSetMapper());
+        } catch (ClassNotFoundException e) {
+            // noop: OK if not found, just can't support mapping to an XmlObject
+        }
+    }
+
+    /**
+     * Constructor
+     */
+    public JdbcControlImpl() { }
+
+    /**
+     * Invoked by the controls runtime when a new instance of this class is aquired by the runtime
+     */
+    public void onAcquire() {
+
+        if (LOGGER.isDebugEnabled()) {
+            LOGGER.debug("Enter: onAquire()");
+        }
+
+    }
+
+    /**
+     * Invoked by the controls runtime when an instance of this class is released by the runtime
+     */
+    public void onRelease() {
+
+        if (LOGGER.isDebugEnabled()) {
+            LOGGER.debug("Enter: onRelease()");
+        }
+
+        for (PreparedStatement ps : getResources()) {
+            try {
+                ps.close();
+            } catch (SQLException sqe) {
+            }
+        }
+        getResources().clear();
+
+        if (_connection != null) {
+            try {
+                _connection.close();
+            } catch (SQLException e) {
+                throw new ControlException("SQL Exception while attempting to close database connection.", e);
+            }
+        }
+
+        _connection = null;
+    }
+
+    /**
+     * Returns a database connection to the server associated with the control.
+     * The connection type is specified by a ConnectionDataSource or ConnectionDriver annotation on the control class
+     * which extends this control.
+     * <p/>
+     * It is typically not necessary to call this method when using the control.
+     */
+    public Connection getConnection() throws SQLException {
+
+        if (_connection == null) {
+
+            if ( getConnectionDataSourcejndiName() != null) {
+                _connection = getConnectionFromDataSource( getConnectionDataSourcejndiName(),
+                                                           getConnectionDataSourcejndiContextFactory());
+
+            } else if ( getConnectionDriverdatabaseDriverClass() != null) {
+                _connection = getConnectionFromDriverManager( getConnectionDriverdatabaseDriverClass(),
+                                                              getConnectionDriverdatabaseUrl(),
+                                                              getConnectionDriveruserName(),
+                                                              getConnectionDriverpassword(),
+                                                              getConnectionDriverproperties());
+            } else {
+                throw new ControlException("no @\'" + ConnectionDataSource.class.getName()
+                                           + "\' or \'" + ConnectionDriver.class.getName() + "\' property found.");
+            }
+
+            //
+            // set any specifed connection options
+            //
+            if (_connection.isReadOnly() != getConnectionOptionsreadOnly()) {
+                _connection.setReadOnly( getConnectionOptionsreadOnly());
+            }
+
+            DatabaseMetaData dbMetadata = _connection.getMetaData();
+
+            final HoldabilityType holdability = getConnectionOptionsresultSetHoldability();
+            if (holdability != HoldabilityType.DRIVER_DEFAULT) {
+                if (dbMetadata.supportsResultSetHoldability(holdability.getHoldability())) {
+                    _connection.setHoldability(holdability.getHoldability());
+                } else {
+                    throw new ControlException("Database does not support ResultSet holdability type: "
+                                               + holdability.toString());
+                }
+            }
+
+            if (getConnectionOptionstypeMappers() != null)
+                setTypeMappers(getConnectionOptionstypeMappers());
+        }
+
+        return _connection;
+    }
+
+
+    /**
+     * Called by the Controls runtime to handle calls to methods of an extensible control.
+     *
+     * @param method The extended operation that was called.
+     * @param args   Parameters of the operation.
+     * @return The value that should be returned by the operation.
+     * @throws Throwable any exception declared on the extended operation may be
+     *                   thrown.  If a checked exception is thrown from the implementation that is not declared
+     *                   on the original interface, it will be wrapped in a ControlException.
+     */
+    public Object invoke(Method method, Object[] args) throws Throwable {
+
+        if (LOGGER.isDebugEnabled()) {
+            LOGGER.debug("Enter: invoke()");
+        }
+        assert _connection.isClosed() == false : "invoke(): JDBC Connection has been closed!!!!";
+        return execPreparedStatement(method, args);
+    }
+
+    /**
+     * Sets the {@link Calendar} used when working with time/date types
+     */
+    public void setDataSourceCalendar(Calendar cal) {
+        _cal = (Calendar) cal.clone();
+    }
+
+    /**
+     * Returns the {@link Calendar} used when working with time/date types.
+     *
+     * @return the {@link Calendar} to use with this {@link DataSource}
+     */
+    public Calendar getDataSourceCalendar() {
+        return _cal;
+    }
+
+// /////////////////////////////////////////// Protected Methods ////////////////////////////////////////////
+
+
+    /**
+     * Create and exec a {@link PreparedStatement}
+     *
+     * @param method the method to invoke
+     * @param args the method's arguments
+     * @return the return value from the {@link PreparedStatement}
+     * @throws Throwable any exception that occurs; the caller should handle these appropriately
+     */
+    protected Object execPreparedStatement(Method method, Object[] args)
+            throws Throwable {
+
+        final SQL methodSQL = (SQL) PropertySetReader.getMethodPropertySet(method, SQL.class);
+        if (methodSQL == null || methodSQL.statement() == null) {
+            throw new ControlException("Method " + method.getName() + " is missing @SQL annotation");
+        }
+
+        setTypeMappers(methodSQL.typeMappersOverride());
+
+        //
+        // build the statement and execute it
+        //
+
+        PreparedStatement ps = null;
+        try {
+            Class returnType = method.getReturnType();
+
+            SqlStatement sqlStatement = _sqlParser.parse(methodSQL.statement());
+            ps = sqlStatement.createPreparedStatement(_connection, _cal, method, args);
+
+            if (LOGGER.isInfoEnabled()) {
+                LOGGER.info("PreparedStatement: "
+                            + sqlStatement.createPreparedStatementString(_connection,  method, args));
+            }
+
+            //
+            // special processing for batch updates
+            //
+            if (sqlStatement.isBatchUpdate()) {
+                return ps.executeBatch();
+            }
+
+            //
+            // execute the statement
+            //
+            boolean hasResults = ps.execute();
+
+
+            //
+            // callable statement processing
+            //
+            if (sqlStatement.isCallableStatement()) {
+                SQLParameter[] params = (SQLParameter[]) args[0];
+                for (int i = 0; i < params.length; i++) {
+                    if (params[i].dir != SQLParameter.IN) {
+                        params[i].value = ((CallableStatement) ps).getObject(i + 1);
+                    }
+                }
+                return null;
+            }
+
+
+            //
+            // process returned data
+            //
+            ResultSet rs = null;
+            int updateCount = ps.getUpdateCount();
+
+            if (hasResults) {
+                rs = ps.getResultSet();
+            }
+
+            if (sqlStatement.getsGeneratedKeys()) {
+                rs = ps.getGeneratedKeys();
+                hasResults = true;
+            }
+
+            if (!hasResults && updateCount > -1) {
+                boolean moreResults = ps.getMoreResults();
+                int tempUpdateCount = ps.getUpdateCount();
+
+                while ((moreResults && rs == null) || tempUpdateCount > -1) {
+                    if (moreResults) {
+                        rs = ps.getResultSet();
+                        hasResults = true;
+                        moreResults = false;
+                        tempUpdateCount = -1;
+                    } else {
+                        moreResults = ps.getMoreResults();
+                        tempUpdateCount = ps.getUpdateCount();
+                    }
+                }
+            }
+
+            Object returnObject = null;
+            if (hasResults) {
+
+                //
+                // if a result set mapper was specified in the methods annotation, use it
+                // otherwise find the mapper for the return type in the hashmap
+                //
+                final Class resultSetMapperClass = methodSQL.resultSetMapper();
+                final ResultSetMapper rsm;
+                if (!UndefinedResultSetMapper.class.isAssignableFrom(resultSetMapperClass)) {
+                    if (ResultSetMapper.class.isAssignableFrom(resultSetMapperClass)) {
+                        rsm = (ResultSetMapper) resultSetMapperClass.newInstance();
+                    } else {
+                        throw new ControlException("Result set mappers must be subclasses of ResultSetMapper.class!");
+                    }
+                } else {
+                    if (_resultMappers.containsKey(returnType)) {
+                        rsm = _resultMappers.get(returnType);
+                    } else {
+                        if (_xmlObjectClass != null && _xmlObjectClass.isAssignableFrom(returnType)) {
+                            rsm = _resultMappers.get(_xmlObjectClass);
+                        } else {
+                            rsm = DEFAULT_MAPPER;
+                        }
+                    }
+                }
+
+                returnObject = rsm.mapToResultType(method, rs, _cal);
+                if (rsm.canCloseResultSet() == false) {
+                    getResources().add(ps);
+                }
+
+                //
+                // empty ResultSet
+                //
+            } else {
+                if (returnType.equals(Void.TYPE)) {
+                    returnObject = null;
+                } else if (returnType.equals(Integer.TYPE)) {
+                    returnObject = new Integer(updateCount);
+                } else if (!sqlStatement.isCallableStatement()) {
+                    throw new ControlException("Method " + method.getName() + "is DML but does not return void or int");
+                }
+            }
+            return returnObject;
+
+        } finally {
+            // Keep statements open that have in-use result sets
+            if (ps != null && !getResources().contains(ps)) {
+                ps.close();
+            }
+        }
+    }
+
+// /////////////////////////////////////////// Private Methods ////////////////////////////////////////////
+
+    /**
+     * Get a connection from a DataSource.
+     *
+     * @param jndiName    Specifed in the subclasse's ConnectionDataSource annotation
+     * @param jndiFactory Specified in the subclasse's ConnectionDataSource Annotation.
+     * @return null if a connection cannot be established
+     * @throws SQLException
+     */
+    private Connection getConnectionFromDataSource(String jndiName,
+                                                   Class<? extends JdbcControl.JndiContextFactory> jndiFactory)
+            throws SQLException
+    {
+
+        Connection con = null;
+        try {
+            JndiContextFactory jf = (JndiContextFactory) jndiFactory.newInstance();
+            Context jndiContext = jf.getContext();
+            _dataSource = (DataSource) jndiContext.lookup(jndiName);
+            con = _dataSource.getConnection();
+        } catch (IllegalAccessException iae) {
+            throw new ControlException("IllegalAccessException:", iae);
+        } catch (InstantiationException ie) {
+            throw new ControlException("InstantiationException:", ie);
+        } catch (NamingException ne) {
+            throw new ControlException("NamingException:", ne);
+        }
+        return con;
+    }
+
+    /**
+     * Get a JDBC connection from the DriverManager.
+     *
+     * @param dbDriverClassName Specified in the subclasse's ConnectionDriver annotation.
+     * @param dbUrlStr          Specified in the subclasse's ConnectionDriver annotation.
+     * @param userName          Specified in the subclasse's ConnectionDriver annotation.
+     * @param password          Specified in the subclasse's ConnectionDriver annotation.
+     * @return null if a connection cannot be established.
+     * @throws SQLException
+     */
+    private Connection getConnectionFromDriverManager(String dbDriverClassName, String dbUrlStr,
+                                                      String userName, String password, String propertiesString)
+            throws SQLException
+    {
+
+        Connection con = null;
+        try {
+            Class.forName(dbDriverClassName);
+            if (!EMPTY_STRING.equals(userName)) {
+                con = DriverManager.getConnection(dbUrlStr, userName, password);
+            } else if (!EMPTY_STRING.equals(propertiesString)) {
+                Properties props = parseProperties(propertiesString);
+                if (props == null) {
+                    throw new ControlException("Invalid properties annotation value: " + propertiesString);
+                }
+                con = DriverManager.getConnection(dbUrlStr, props);
+            } else {
+                con = DriverManager.getConnection(dbUrlStr);
+            }
+        } catch (ClassNotFoundException e) {
+            throw new ControlException("Database driver class not found!", e);
+        }
+        return con;
+    }
+
+    /**
+     * Get the Vector of Statements which we need to keep open.
+     * @return Vector of PreparedStatement
+     */
+    private Vector<PreparedStatement> getResources() {
+        if (_resources == null) {
+            _resources = new Vector<PreparedStatement>();
+        }
+        return _resources;
+    }
+
+    /**
+     * Parse the propertiesString into a Properties object.  The string must have the format of:
+     * propertyName=propertyValue;propertyName=propertyValue;...
+     *
+     * @param propertiesString
+     * @return A Properties instance or null if parse fails
+     */
+    private Properties parseProperties(String propertiesString) {
+        Properties properties = null;
+        String[] propPairs = propertiesString.split(";");
+        if (propPairs.length > 0) {
+            properties = new Properties();
+            for (String propPair : propPairs) {
+                int eq = propPair.indexOf('=');
+                assert eq > -1 : "Invalid properties syntax: " + propertiesString;
+                properties.put(propPair.substring(0, eq), propPair.substring(eq + 1, propPair.length()));
+            }
+        }
+        return properties;
+    }
+
+    /**
+     * Set any custom type mappers specifed in the annotation for the connection.  Used for mapping SQL UDTs to
+     * java classes.
+     *
+     * @param typeMappers An array of TypeMapper.
+     */
+    private void setTypeMappers(TypeMapper[] typeMappers) throws SQLException {
+
+        if (typeMappers.length > 0) {
+            Map<String, Class<?>> mappers = _connection.getTypeMap();
+            for (TypeMapper t : typeMappers) {
+                mappers.put(t.UDTName(), t.mapperClass());
+            }
+            _connection.setTypeMap(mappers);
+        }
+    }
+
+// //////////////////////////////////// Class / Instance Property Accessors /////////////////////////////////////////
+
+    /* ConnectionDataSource( jndiName ) accessors */
+    public String getConnectionDataSourcejndiName() { return _connectionDataSourceJndiName; }
+    public void   setConnectionDataSourcejndiName(String s) { _connectionDataSourceJndiName = s; }
+
+    private String _connectionDataSourceJndiName;
+
+    /* ConnectionDataSource( jndiContextFactory ) accessors */
+    public Class<? extends JndiContextFactory> getConnectionDataSourcejndiContextFactory() { return _connectionDataSourceJndiContextFactory; }
+    public void                                setConnectionDataSourcejndiContextFactory(Class<? extends JndiContextFactory> jcf) { _connectionDataSourceJndiContextFactory = jcf; }
+
+    public Class<? extends JndiContextFactory> _connectionDataSourceJndiContextFactory;
+
+    /* ConnectionDriver( databaseDriverClass ) */
+    public String getConnectionDriverdatabaseDriverClass() { return _connectionDriverDatabaseDriverClass; }
+    public void   setConnectionDriverdatabaseDriverClass(String s) { _connectionDriverDatabaseDriverClass = s; }
+
+    private String _connectionDriverDatabaseDriverClass;
+
+    /* ConnectionDriver( databaseUrl ) */
+    public String getConnectionDriverdatabaseUrl() { return _connectionDriverDatabaseUrl; }
+    public void   setConnectionDriverdatabaseUrl(String s) { _connectionDriverDatabaseUrl = s; }
+
+    private String _connectionDriverDatabaseUrl;
+
+    /* ConnectionDriver( userName ) */
+    public String getConnectionDriveruserName() { return _connectionDriverUserName; }
+    public void   setConnectionDriveruserName(String s) { _connectionDriverUserName = s; }
+
+    private String _connectionDriverUserName;
+
+    /* ConnectionDriver( password ) */
+    public String getConnectionDriverpassword() { return _connectionDriverPassword; }
+    public void   setConnectionDriverpassword(String s) { _connectionDriverPassword = s; }
+
+    private String _connectionDriverPassword;
+
+    /* ConnectionDriver( properties ) */
+    public String getConnectionDriverproperties() { return _connectionDriverProperties; }
+    public void   setConnectionDriverproperties(String s) { _connectionDriverProperties = s; }
+
+    private String _connectionDriverProperties;
+
+    /* ConnectionOptions( readOnly ) */
+    public boolean getConnectionOptionsreadOnly() { return _connectionOptionsReadOnly; }
+    public    void setConnectionOptionsreadOnly(boolean b) { _connectionOptionsReadOnly = b; }
+
+    private boolean _connectionOptionsReadOnly;
+
+    /* ConnectionOptions( resultSetHoldability ) */
+    public HoldabilityType getConnectionOptionsresultSetHoldability() { return _connectionOptionsResultSetHoldability; }
+    public            void setConnectionOptionsresultSetHoldability(HoldabilityType ht) { _connectionOptionsResultSetHoldability = ht; }
+
+    private HoldabilityType _connectionOptionsResultSetHoldability;
+
+    /* ConnectionOptions( typeMappers ) */
+    public TypeMapper[] getConnectionOptionstypeMappers() { return _connectionOptionsTypeMappers; }
+    public         void setConnectionOptionstypeMappers(TypeMapper[] tm) { _connectionOptionsTypeMappers = tm; }
+
+    private TypeMapper[] _connectionOptionsTypeMappers;
+
+    /* TypeMapper( UDTName ) */
+    public String getTypeMapperUDTName() { return _typeMapperUDTName; }
+    public void setTypeMapperUDTName(String n) { _typeMapperUDTName = n; }
+
+    private String _typeMapperUDTName;
+
+    /* TypeMapper( mapperClass ) */
+    public Class<? extends SQLData> getTypeMappermapperClass() { return _typeMappermapperClass; }
+    public void setTypeMappermapperClass(Class<? extends SQLData> c) { _typeMappermapperClass = c; }
+
+    private Class<? extends SQLData> _typeMappermapperClass;
+}

Propchange: beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/JdbcControlImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/ResultSetHashMap.java
URL: http://svn.apache.org/viewvc/beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/ResultSetHashMap.java?rev=421473&view=auto
==============================================================================
--- beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/ResultSetHashMap.java (added)
+++ beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/ResultSetHashMap.java Wed Jul 12 18:34:03 2006
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+package org.apache.beehive.controls.system.jdbc;
+
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.util.HashMap;
+
+/**
+ * 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.
+ */
+public class ResultSetHashMap extends HashMap<String, Object> {
+
+    /**
+     * Default constructor.
+     */
+    ResultSetHashMap() {
+        super();
+    }
+
+    /**
+     * Constructor that initializes the map to a specific size.
+     * @param size the size
+     */
+    ResultSetHashMap(int size) {
+        super(size);
+    }
+
+    /**
+     * This constructor is optimized for being called in a loop.  It also canonicalizes the
+     * column names into upper case so that values in a map can be looked up using either
+     * upper, lower, or mixed case strings.
+     *
+     * @param rs the ResultSet to map
+     * @param keys an array of key objects to store in the map
+     * @throws SQLException if an error occurs while reading from the ResultSet
+     */
+    ResultSetHashMap(ResultSet rs, String[] keys) throws SQLException {
+        super(keys.length);
+
+        assert keys.length == rs.getMetaData().getColumnCount() + 1;
+
+        for (int i = 1; i < keys.length; i++) {
+            assert keys[i].equals(keys[i].toUpperCase());
+            put(keys[i], rs.getObject(i));
+        }
+    }
+
+    ResultSetHashMap(ResultSet rs) throws SQLException {
+        super();
+        ResultSetMetaData md = rs.getMetaData();
+        for (int i = 1; i <= md.getColumnCount(); i++) {
+            put(md.getColumnName(i), rs.getObject(i));
+        }
+    }
+
+    public boolean containsKey(Object key) {
+        return super.containsKey(canonicalizeKey(key));
+    }
+
+    public Object get(Object key) {
+        return super.get(canonicalizeKey(key));
+    }
+
+    public Object put(String key, Object value) {
+        return super.put(canonicalizeKey(key), value);
+    }
+
+    public Object remove(Object key) {
+        return super.remove(canonicalizeKey(key));
+    }
+
+    private String canonicalizeKey(Object object) {
+        return object == null ? null : object.toString().toUpperCase();
+    }
+}
+

Propchange: beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/ResultSetHashMap.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/ResultSetIterator.java
URL: http://svn.apache.org/viewvc/beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/ResultSetIterator.java?rev=421473&view=auto
==============================================================================
--- beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/ResultSetIterator.java (added)
+++ beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/ResultSetIterator.java Wed Jul 12 18:34:03 2006
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+package org.apache.beehive.controls.system.jdbc;
+
+import org.apache.beehive.controls.api.ControlException;
+import org.apache.beehive.controls.api.PropertySetReader;
+
+import java.lang.reflect.Method;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Calendar;
+import java.util.NoSuchElementException;
+
+/**
+ * Used by DefaultIteratorResultSetMapper for mapping a ResultSet to an Iterator type.
+ */
+public class ResultSetIterator implements java.util.Iterator {
+
+    private final Class _returnClass;
+    private final ResultSet _rs;
+    private final RowMapper _rowMapper;
+
+    private boolean _primed = false;
+
+    /**
+     * Create a new ResultSetIterator.
+     * @param method The annotated method.
+     * @param rs The ResultSet to map.
+     * @param cal A Calendar instance for mapping date/time values.
+     */
+    ResultSetIterator(Method method, ResultSet rs, Calendar cal) {
+        _rs = rs;
+
+        JdbcControl.SQL methodSQL = PropertySetReader.getMethodPropertySet(method, JdbcControl.SQL.class);
+        _returnClass = methodSQL.iteratorElementType();
+
+        if (_returnClass == null) {
+            throw new ControlException("Invalid return class declared for Iterator:" + _returnClass.getName());
+        }
+
+        _rowMapper = RowMapperFactory.getRowMapper(rs, _returnClass, cal);
+    }
+
+    /**
+     * Does this iterater have more elements?
+     * @return true if there is another element
+     */
+    public boolean hasNext() {
+        if (_primed) {
+            return true;
+        }
+
+        try {
+            _primed = _rs.next();
+        } catch (SQLException sqle) {
+            return false;
+        }
+        return _primed;
+    }
+
+    /**
+     * Get the next element in the iteration.
+     * @return The next element in the iteration.
+     */
+    public Object next() {
+        try {
+            if (!_primed) {
+                _primed = _rs.next();
+                if (!_primed) {
+                    throw new NoSuchElementException();
+                }
+            }
+            // reset upon consumption
+            _primed = false;
+            return _rowMapper.mapRowToReturnType();
+        } catch (SQLException 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;
+        }
+    }
+
+    /**
+     * Remove is currently not supported.
+     */
+    public void remove() {
+        throw new UnsupportedOperationException("remove not supported");
+    }
+}
+

Propchange: beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/ResultSetIterator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/ResultSetMapper.java
URL: http://svn.apache.org/viewvc/beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/ResultSetMapper.java?rev=421473&view=auto
==============================================================================
--- beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/ResultSetMapper.java (added)
+++ beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/ResultSetMapper.java Wed Jul 12 18:34:03 2006
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+package org.apache.beehive.controls.system.jdbc;
+
+import java.lang.reflect.Method;
+import java.sql.ResultSet;
+import java.util.Calendar;
+
+/**
+ * Extend this class to create new ResultSet mappers. The extended class will be invoked by the JdbcController
+ * when it is time to map a ResultSet to a method's return type.
+ *
+ * ResultSet mappers are specified on a per method basis using the SQL annotation's resultSetMapper field.
+ */
+public abstract class ResultSetMapper {
+
+    /**
+     * Map a ResultSet to an object type
+     *
+     * @param m         Method assoicated with this call.
+     * @param resultSet Result set to map.
+     * @param cal       A Calendar instance for time/date value resolution.
+     * @return          The Object resulting from the ResultSet
+     */
+    public abstract Object mapToResultType(Method m, ResultSet resultSet, Calendar cal);
+
+    /**
+     * Can the ResultSet which this mapper uses be closed by the Jdbc control?
+     * @return true if the ResultSet can be closed by the JdbcControl
+     */
+    public boolean canCloseResultSet() { return true; }
+}

Propchange: beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/ResultSetMapper.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/RowMapper.java
URL: http://svn.apache.org/viewvc/beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/RowMapper.java?rev=421473&view=auto
==============================================================================
--- beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/RowMapper.java (added)
+++ beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/RowMapper.java Wed Jul 12 18:34:03 2006
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+
+package org.apache.beehive.controls.system.jdbc;
+
+import org.apache.beehive.controls.api.ControlException;
+
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.util.Calendar;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+/**
+ * Abstract base class for all row mappers.
+ *
+ * RowMappers are used to map the contents of a row in a ResultSet to the return type of an annotated method.
+ * Supported RowMapper types include: HashMap, Map, Object, XmlObject.  When a ResultSetMapper is ready to
+ * map a ResultSet row to an object, it requests a RowMapper for the return type of the method from the
+ * RowMapperFactory.
+ *
+ */
+public abstract class RowMapper {
+
+    private static final String SETTER_NAME_REGEX = "^(set)([A-Z_]\\w*+)";
+    protected static final TypeMappingsFactory _tmf = TypeMappingsFactory.getInstance();
+    protected static final Pattern _setterRegex = Pattern.compile(SETTER_NAME_REGEX);
+
+    /** ResultSet to map. */
+    protected final ResultSet _resultSet;
+
+    /** Calendar instance for date/time mappings. */
+    protected final Calendar _cal;
+
+    /** Class to map ResultSet Rows to. */
+    protected final Class<?> _returnTypeClass;
+
+    /**
+     * Create a new RowMapper for the specified ResultSet and return type Class.
+     * @param resultSet ResultSet to map
+     * @param returnTypeClass Class to map ResultSet rows to.
+     * @param cal Calendar instance for date/time values.
+     */
+    protected RowMapper(ResultSet resultSet, Class<?> returnTypeClass, Calendar cal) {
+        _resultSet = resultSet;
+        _returnTypeClass = returnTypeClass;
+        _cal = cal;
+    }
+
+    /**
+     * Map a ResultSet row to the return type class
+     * @return An instance of class.
+     */
+    public abstract Object mapRowToReturnType();
+
+
+    /**
+     * Build a String array of column names from the ResultSet.
+     * @return A String array containing the column names contained within the ResultSet.
+     * @throws SQLException on error
+     */
+    protected String[] getKeysFromResultSet() throws SQLException {
+
+        String[] keys;
+        final ResultSetMetaData md = _resultSet.getMetaData();
+        final int columnCount = md.getColumnCount();
+
+        keys = new String[columnCount + 1];
+        for (int i = 1; i <= columnCount; i++) {
+            keys[i] = md.getColumnName(i).toUpperCase();
+        }
+        return keys;
+    }
+
+    /**
+     * Determine if the given method is a java bean setter method.
+     * @param method Method to check
+     * @return True if the method is a setter method.
+     */ 
+    protected boolean isSetterMethod(Method method) {
+        Matcher matcher = _setterRegex.matcher(method.getName());
+        if (matcher.matches()) {
+
+            if (Modifier.isStatic(method.getModifiers())) return false;
+            if (!Modifier.isPublic(method.getModifiers())) return false;
+            if (!Void.TYPE.equals(method.getReturnType())) return false;
+
+            // method parameter checks
+            Class[] params = method.getParameterTypes();
+            if (params.length != 1) return false;
+            if (TypeMappingsFactory.TYPE_UNKNOWN == _tmf.getTypeId(params[0])) return false;
+
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Extract a column value from the ResultSet and return it as resultType.
+     *
+     * @param index The column index of the value to extract from the ResultSet.
+     * @param resultType The return type. Defined in TypeMappingsFactory.
+     * @return The extracted value
+     * @throws java.sql.SQLException on error.
+     */
+    protected Object extractColumnValue(int index, int resultType) throws SQLException {
+
+        switch (resultType) {
+            case TypeMappingsFactory.TYPE_INT:
+                return new Integer(_resultSet.getInt(index));
+            case TypeMappingsFactory.TYPE_LONG:
+                return new Long(_resultSet.getLong(index));
+            case TypeMappingsFactory.TYPE_FLOAT:
+                return new Float(_resultSet.getFloat(index));
+            case TypeMappingsFactory.TYPE_DOUBLE:
+                return new Double(_resultSet.getDouble(index));
+            case TypeMappingsFactory.TYPE_BYTE:
+                return new Byte(_resultSet.getByte(index));
+            case TypeMappingsFactory.TYPE_SHORT:
+                return new Short(_resultSet.getShort(index));
+            case TypeMappingsFactory.TYPE_BOOLEAN:
+                return _resultSet.getBoolean(index) ? Boolean.TRUE : Boolean.FALSE;
+            case TypeMappingsFactory.TYPE_INT_OBJ:
+                {
+                    int i = _resultSet.getInt(index);
+                    return _resultSet.wasNull() ? null : new Integer(i);
+                }
+            case TypeMappingsFactory.TYPE_LONG_OBJ:
+                {
+                    long i = _resultSet.getLong(index);
+                    return _resultSet.wasNull() ? null : new Long(i);
+                }
+            case TypeMappingsFactory.TYPE_FLOAT_OBJ:
+                {
+                    float i = _resultSet.getFloat(index);
+                    return _resultSet.wasNull() ? null : new Float(i);
+                }
+            case TypeMappingsFactory.TYPE_DOUBLE_OBJ:
+                {
+                    double i = _resultSet.getDouble(index);
+                    return _resultSet.wasNull() ? null : new Double(i);
+                }
+            case TypeMappingsFactory.TYPE_BYTE_OBJ:
+                {
+                    byte i = _resultSet.getByte(index);
+                    return _resultSet.wasNull() ? null : new Byte(i);
+                }
+            case TypeMappingsFactory.TYPE_SHORT_OBJ:
+                {
+                    short i = _resultSet.getShort(index);
+                    return _resultSet.wasNull() ? null : new Short(i);
+                }
+            case TypeMappingsFactory.TYPE_BOOLEAN_OBJ:
+                {
+                    boolean i = _resultSet.getBoolean(index);
+                    return _resultSet.wasNull() ? null : (i ? Boolean.TRUE : Boolean.FALSE);
+                }
+            case TypeMappingsFactory.TYPE_STRING:
+            case TypeMappingsFactory.TYPE_XMLBEAN_ENUM:
+                return _resultSet.getString(index);
+            case TypeMappingsFactory.TYPE_BIG_DECIMAL:
+                return _resultSet.getBigDecimal(index);
+            case TypeMappingsFactory.TYPE_BYTES:
+                return _resultSet.getBytes(index);
+            case TypeMappingsFactory.TYPE_TIMESTAMP:
+                {
+                    if (null == _cal)
+                        return _resultSet.getTimestamp(index);
+                    else
+                        return _resultSet.getTimestamp(index, _cal);
+                }
+            case TypeMappingsFactory.TYPE_TIME:
+                {
+                    if (null == _cal)
+                        return _resultSet.getTime(index);
+                    else
+                        return _resultSet.getTime(index, _cal);
+                }
+            case TypeMappingsFactory.TYPE_SQLDATE:
+                {
+                    if (null == _cal)
+                        return _resultSet.getDate(index);
+                    else
+                        return _resultSet.getDate(index, _cal);
+                }
+            case TypeMappingsFactory.TYPE_DATE:
+                {
+                    // convert explicity to java.util.Date
+                    // 12918 |  knex does not return java.sql.Date properly from web service
+                    java.sql.Timestamp ts = (null == _cal) ? _resultSet.getTimestamp(index) : _resultSet.getTimestamp(index, _cal);
+                    if (null == ts)
+                        return null;
+                    return new java.util.Date(ts.getTime());
+                }
+            case TypeMappingsFactory.TYPE_CALENDAR:
+                {
+                    java.sql.Timestamp ts = (null == _cal) ? _resultSet.getTimestamp(index) : _resultSet.getTimestamp(index, _cal);
+                    if (null == ts)
+                        return null;
+                    Calendar c = (null == _cal) ? Calendar.getInstance() : (Calendar) _cal.clone();
+                    c.setTimeInMillis(ts.getTime());
+                    return c;
+                }
+            case TypeMappingsFactory.TYPE_REF:
+                return _resultSet.getRef(index);
+            case TypeMappingsFactory.TYPE_BLOB:
+                return _resultSet.getBlob(index);
+            case TypeMappingsFactory.TYPE_CLOB:
+                return _resultSet.getClob(index);
+            case TypeMappingsFactory.TYPE_ARRAY:
+                return _resultSet.getArray(index);
+            case TypeMappingsFactory.TYPE_READER:
+            case TypeMappingsFactory.TYPE_STREAM:
+                throw new ControlException("streaming return types are not supported by the JdbcControl; use ResultSet instead");
+            case TypeMappingsFactory.TYPE_STRUCT:
+            case TypeMappingsFactory.TYPE_UNKNOWN:
+                // JAVA_TYPE (could be any), or REF
+                return _resultSet.getObject(index);
+            default:
+                throw new ControlException("internal error: unknown type ID: " + Integer.toString(resultType));
+        }
+    }
+}

Propchange: beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/RowMapper.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/RowMapperFactory.java
URL: http://svn.apache.org/viewvc/beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/RowMapperFactory.java?rev=421473&view=auto
==============================================================================
--- beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/RowMapperFactory.java (added)
+++ beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/RowMapperFactory.java Wed Jul 12 18:34:03 2006
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+
+package org.apache.beehive.controls.system.jdbc;
+
+import org.apache.beehive.controls.api.ControlException;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.sql.ResultSet;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Factory for creating row mappers.
+ * <p/>
+ * Row mapper types supported by this factory include: HashMap, Map, Object, XmlObject. The factory determines the
+ * proper row mapper to use by checking its List of RowMappers against the type of mapping requested.  When performing
+ * the lookup, the factory attempts to find the most specific type match.  If a match can't be found the most general
+ * type of RowMapper is returned, RowToObjectMapper.
+ */
+public final class RowMapperFactory {
+
+    private static final HashMap<Class, Class<? extends RowMapper>> _rowMappings
+            = new HashMap<Class, Class<? extends RowMapper>>();
+
+    private static Class<? extends RowMapper> DEFAULT_OBJ_ROWMAPPING = RowToObjectMapper.class;
+
+    private static Class XMLOBJ_CLASS = null;
+    private static Class<? extends RowMapper> DEFAULT_XMLOBJ_ROWMAPPING = null;
+    private final static Class[] _params = {ResultSet.class, Class.class, Calendar.class};
+
+    static {
+
+        _rowMappings.put(HashMap.class, RowToHashMapMapper.class);
+        _rowMappings.put(Map.class, RowToMapMapper.class);
+
+        try {
+            XMLOBJ_CLASS = Class.forName("org.apache.xmlbeans.XmlObject");
+            DEFAULT_XMLOBJ_ROWMAPPING = RowToXmlObjectMapper.class;
+        } catch (ClassNotFoundException e) {
+            // NOOP if apache xml beans not present
+        }
+    }
+
+    /**
+     * Get a RowMapper instance which knows how to map a ResultSet row to the given return type.
+     *
+     * @param rs              The ResultSet to map.
+     * @param returnTypeClass The class to map a ResultSet row to.
+     * @param cal             Calendar instance for mapping date/time values.
+     * @return A RowMapper instance.
+     */
+    public static RowMapper getRowMapper(ResultSet rs, Class returnTypeClass, Calendar cal) {
+
+        Class<? extends RowMapper> rm = _rowMappings.get(returnTypeClass);
+        if (rm != null) {
+            return getMapper(rm, rs, returnTypeClass, cal);
+        }
+
+        //
+        // if we made it to here, check if the default XMLObject Mapper can be used,
+        // otherwise use the default object mapper
+        //
+        if (XMLOBJ_CLASS != null && XMLOBJ_CLASS.isAssignableFrom(returnTypeClass)) {
+            return getMapper(DEFAULT_XMLOBJ_ROWMAPPING, rs, returnTypeClass, cal);
+        } else {
+            return getMapper(DEFAULT_OBJ_ROWMAPPING, rs, returnTypeClass, cal);
+        }
+    }
+
+    /**
+     * Add a new row mapper to the list of available row mappers.  The getRowMapper method traverses the
+     * list of mappers from beginning to end, checking to see if a mapper can handle the specified
+     * returnTypeClass.  There is a default mapper which is used if a match cannot be found in the list.
+     *
+     * @param returnTypeClass Class which this mapper maps a row to.
+     * @param rowMapperClass  The row mapper class.
+     */
+    public static void addRowMapping(Class returnTypeClass, Class<? extends RowMapper> rowMapperClass) {
+        _rowMappings.put(returnTypeClass, rowMapperClass);
+    }
+
+    /**
+     * Replace a row mapping.
+     *
+     * @param returnTypeClass Class which this mapper maps a row to.
+     * @param rowMapperClass  The row mapper class.
+     * @return if the mapper was replaced, false mapper for returnTypeClass was not found, no action taken.
+     */
+    public static Class<? extends RowMapper> replaceRowMapping(Class returnTypeClass, Class<? extends RowMapper> rowMapperClass) {
+        return _rowMappings.put(returnTypeClass, rowMapperClass);
+    }
+
+    /**
+     * remove the  row mapping for the specified class type.
+     *
+     * @param returnTypeClass
+     * @return the RowMapper class which was removed, null if returnTypeClass did not match any of the registered
+     *         row mappers.
+     */
+    public static Class<? extends RowMapper> removeRowMapping(Class returnTypeClass) {
+        return _rowMappings.remove(returnTypeClass);
+    }
+
+    /**
+     * Sets the rowmapper for Object.class
+     *
+     * @param rowMapperClass
+     */
+    public static Class <? extends RowMapper> setDefaultRowMapping(Class<? extends RowMapper> rowMapperClass) {
+        Class<? extends RowMapper> ret = DEFAULT_OBJ_ROWMAPPING;
+        DEFAULT_OBJ_ROWMAPPING = rowMapperClass;
+        return ret;
+    }
+
+    /**
+     * Sets the rowmapper for XmlObject.class
+     *
+     * @param rowMapperClass
+     */
+    public static Class<? extends RowMapper> setDefaultXmlRowMapping(Class mapToClass, Class<? extends RowMapper> rowMapperClass) {
+        Class<? extends RowMapper> ret = DEFAULT_XMLOBJ_ROWMAPPING;
+        DEFAULT_XMLOBJ_ROWMAPPING = rowMapperClass;
+        XMLOBJ_CLASS = mapToClass;
+        return ret;
+    }
+
+    /**
+     * Create an instance of the RowMapper class.
+     *
+     * @param rowMapper
+     * @param rs         ResultSet we are mapping from.
+     * @param returnType Class to map rows to.
+     * @param cal        Calendar instance for date/time values.
+     * @return A RowMapper instance.
+     */
+    private static RowMapper getMapper(Class<? extends RowMapper> rowMapper, ResultSet rs, Class returnType, Calendar cal)
+    {
+        Constructor c = null;
+        try {
+            c = rowMapper.getDeclaredConstructor(_params);
+            return (RowMapper) c.newInstance(new Object[]{rs, returnType, cal});
+        } catch (NoSuchMethodException e) {
+            throw new ControlException("Failure creating new instance of RowMapper, " + e.toString(), e);
+        } catch (InstantiationException e) {
+            throw new ControlException("Failure creating new instance of RowMapper, " + e.toString(), e);
+        } catch (IllegalAccessException e) {
+            throw new ControlException("Failure creating new instance of RowMapper, " + e.toString(), e);
+        } catch (InvocationTargetException e) {
+            throw new ControlException("Failure creating new instance of RowMapper, " + e.getCause().toString(), e);
+        }
+    }
+}

Propchange: beehive/sandbox/hornet/controls/samples/jdbc/src/main/java/org/apache/beehive/controls/system/jdbc/RowMapperFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native