Clear statement parameters before new call.
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / aa / attrresolv / provider / JDBCDataConnector.java
index fb403e6..928a721 100644 (file)
 
 package edu.internet2.middleware.shibboleth.aa.attrresolv.provider;
 
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
+import java.io.PrintWriter;
+import java.lang.reflect.Constructor;
 import java.security.Principal;
+import java.sql.Blob;
+import java.sql.Clob;
 import java.sql.Connection;
-import java.sql.DriverManager;
+import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.ResultSetMetaData;
 import java.sql.SQLException;
-import java.sql.Statement;
+import java.sql.Types;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.Properties;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
-import javax.naming.NamingEnumeration;
 import javax.naming.NamingException;
 import javax.naming.directory.Attribute;
 import javax.naming.directory.Attributes;
 import javax.naming.directory.BasicAttribute;
 import javax.naming.directory.BasicAttributes;
+import javax.sql.DataSource;
 
+import org.apache.commons.dbcp.ConnectionFactory;
+import org.apache.commons.dbcp.DriverManagerConnectionFactory;
+import org.apache.commons.dbcp.PoolableConnectionFactory;
+import org.apache.commons.dbcp.PoolingDataSource;
+import org.apache.commons.pool.impl.GenericObjectPool;
+import org.apache.commons.pool.impl.StackKeyedObjectPoolFactory;
 import org.apache.log4j.Logger;
+import org.apache.log4j.Priority;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
@@ -71,51 +80,54 @@ import edu.internet2.middleware.shibboleth.aa.attrresolv.ResolverAttribute;
  * Data Connector that uses JDBC to access user attributes stored in databases.
  *
  * @author David Dearman (dearman@cs.dal.ca)
+ * @author Walter Hoehn (wassa@columbia.edu)
+ * @author Scott Cantor
  */
 
-public class JDBCDataConnector extends BaseResolutionPlugIn implements DataConnectorPlugIn {
+public class JDBCDataConnector extends BaseDataConnector implements DataConnectorPlugIn {
 
-    private static Logger log = Logger.getLogger(JDBCDataConnector.class.getName());
-    private Properties props = new Properties();
-    private String searchVal = null;
-    private String aeClassName = null;
+       private static Logger log = Logger.getLogger(JDBCDataConnector.class.getName());
+       protected String searchVal;
+       protected DataSource dataSource;
+       protected JDBCAttributeExtractor extractor;
+       protected JDBCStatementCreator statementCreator;
 
-    final private static String QueryAtt = "query";
-    final private static String AttributeExtractorAtt = "attributeExtractor";
-    final private static String DBDriverAtt = "dbDriver";
-    final private static String AEInstanceMethodAtt = "instance";
-    final private static String URLAtt = "dbURL";
+       public JDBCDataConnector(Element e) throws ResolutionPlugInException {
 
-    public JDBCDataConnector(Element e) throws ResolutionPlugInException {
+               super(e);
 
-        super(e);
+               //Get the query string
+               NodeList queryNodes = e.getElementsByTagNameNS(AttributeResolver.resolverNamespace, "Query");
+               Node tnode = queryNodes.item(0).getFirstChild();
+               if (tnode != null && tnode.getNodeType() == Node.TEXT_NODE) {
+                       searchVal = tnode.getNodeValue();
+               }
+               if (searchVal == null || searchVal.equals("")) {
+                       log.error("Database query must be specified.");
+                       throw new ResolutionPlugInException("Database query must be specified.");
+               }
 
-        NodeList propertiesNode = e.getElementsByTagNameNS(AttributeResolver.resolverNamespace, "Property");
-        NodeList searchNode = e.getElementsByTagNameNS(AttributeResolver.resolverNamespace, "Search");
-
-        /**
-         * Gets and sets the search parameter and the attribute extractor
-         */
-        searchVal = ((Element) searchNode.item(0)).getAttribute(QueryAtt);
-        aeClassName = ((Element) searchNode.item(0)).getAttribute(AttributeExtractorAtt);
-
-        if (searchVal == null || searchVal.equals("")) {
-            Node tnode = searchNode.item(0).getFirstChild();
-            if (tnode != null && tnode.getNodeType() == Node.TEXT_NODE) {
-                searchVal = tnode.getNodeValue();
-            }
-            if (searchVal == null || searchVal.equals("")) {
-                log.error("Search requires a specified query field");
-                throw new ResolutionPlugInException("mySQLDataConnection requires a \"Search\" specification");
-            }
-        }
-        else {
-            log.debug("Search Query: (" + searchVal + ")");
-        }
+               //Load the supplied JDBC driver
+               String dbDriverName = e.getAttribute("dbDriver");
+               if (dbDriverName != null && (!dbDriverName.equals(""))) {
+                       loadDriver(dbDriverName);
+               }
+
+               String validationQuery = e.getAttribute("validationQuery");
+               if (validationQuery == null || validationQuery.equals("")) {
+                       validationQuery = "select 1";
+               }
 
-        /**
-         * Assigns the property attribute name/value pairs to a hashtable
-         */
+               //Load site-specific implementation classes     
+               setupAttributeExtractor(
+                       (Element) e.getElementsByTagNameNS(AttributeResolver.resolverNamespace, "AttributeExtractor").item(
+                               0));
+               setupStatementCreator(
+                       (Element) e.getElementsByTagNameNS(AttributeResolver.resolverNamespace, "StatementCreator").item(0));
+        
+        //Load driver properties
+        Properties props = new Properties();
+        NodeList propertiesNode = e.getElementsByTagNameNS(AttributeResolver.resolverNamespace, "Property");
         for (int i = 0; propertiesNode.getLength() > i; i++) {
             Element property = (Element) propertiesNode.item(i);
             String propertiesName = property.getAttribute("name");
@@ -134,293 +146,965 @@ public class JDBCDataConnector extends BaseResolutionPlugIn implements DataConne
             }
         }
         
-        if (props.getProperty(URLAtt) == null) {
-            log.error("JDBC connection requires a dbURL property");
-            throw new ResolutionPlugInException("JDBCDataConnection requires a \"dbURL\" property");
-        }
-    }
-
-    protected String substitute(String source, String pattern, boolean quote, Dependencies depends) {
-        Matcher m=Pattern.compile(pattern).matcher(source);
-        while (m.find()) {
-            String field = source.substring(m.start()+1, m.end()-1);
-            if (field != null && field.length() > 0) {
-                StringBuffer buf = new StringBuffer();
-                
-                //Look for an attribute dependency.
-                ResolverAttribute dep = depends.getAttributeResolution(field);
-                if (dep != null) {
-                    Iterator iter=dep.getValues();
-                    while (iter.hasNext()) {
-                        if (buf.length() > 0)
-                            buf = buf.append(',');
-                        if (quote)
-                            buf = buf.append("'");
-                        buf = buf.append(iter.next());
-                        if (quote)
-                            buf = buf.append("'");
-                    }
-                }
-                
-                //If no values found, cycle over the connectors.
-                Iterator connDeps = connectorDependencyIds.iterator();
-                while (buf.length() == 0 && connDeps.hasNext()) {
-                    Attributes attrs = depends.getConnectorResolution((String)connDeps.next());
-                    if (attrs != null) {
-                        Attribute attr = attrs.get(field);
-                        if (attr != null) {
-                            try {
-                                NamingEnumeration vals = attr.getAll();
-                                while (vals.hasMore()) {
-                                    if (buf.length() > 0)
-                                        buf = buf.append(',');
-                                    if (quote)
-                                        buf = buf.append("'");
-                                    buf = buf.append(vals.next());
-                                    if (quote)
-                                        buf = buf.append("'");
-                                }
-                            }
-                            catch (NamingException e) {
-                                // Auto-generated catch block
-                            }
-                        }
-                    }
-                }
-                
-                if (buf.length() == 0) {
-                    log.warn("Unable to find any values to substitute in query for " + field + ", so using the empty string");
-                }
-                source = source.replaceAll(m.group(), buf.toString());
-                m.reset(source);
+               //Initialize a pooling Data Source
+               int maxActive = 0;
+               int maxIdle = 0;
+        int maxWait = 30;
+               try {
+                       if (e.getAttributeNode("maxActive") != null) {
+                               maxActive = Integer.parseInt(e.getAttribute("maxActive"));
+                       }
+                       if (e.getAttributeNode("maxIdle") != null) {
+                               maxIdle = Integer.parseInt(e.getAttribute("maxIdle"));
+                       }
+            if (e.getAttributeNode("maxWait") != null) {
+                maxWait = Integer.parseInt(e.getAttribute("maxWait"));
             }
-        }
-        return source;
-    }
+               } catch (NumberFormatException ex) {
+                       log.error("Malformed pooling limits: using defaults.");
+               }
+               if (e.getAttribute("dbURL") == null || e.getAttribute("dbURL").equals("")) {
+                       log.error("JDBC connection requires a dbURL property");
+                       throw new ResolutionPlugInException("JDBCDataConnection requires a \"dbURL\" property");
+               }
+               setupDataSource(e.getAttribute("dbURL"), props, maxActive, maxIdle, maxWait, validationQuery);
+       }
 
-    public Attributes resolve(Principal principal, String requester, Dependencies depends) throws ResolutionPlugInException {
-        Connection conn = null;
-        ResultSet rs = null;
-        JDBCAttributeExtractor aeClassObj = null;
+       /**
+        * Initialize a Pooling Data Source
+        */
+       private void setupDataSource(String dbURL, Properties props, int maxActive, int maxIdle, int maxWait, String validationQuery) throws ResolutionPlugInException {
 
-        log.debug("Resolving connector: (" + getId() + ")");
-        log.debug(getId() + " resolving for principal: (" + principal.getName() + ")");
-        log.debug("The query string before inserting substitutions: " + searchVal);
+               GenericObjectPool objectPool = new GenericObjectPool(null);
 
-        //Replaces %PRINCIPAL% in the query string with its value
-        String convertedSearchVal = searchVal.replaceAll("%PRINCIPAL%", principal.getName());
-        convertedSearchVal = convertedSearchVal.replaceAll("@PRINCIPAL@", "'" + principal.getName() + "'");
-        
-        //Find all delimited substitutions and replace with the named attribute value(s).
-        convertedSearchVal = substitute(convertedSearchVal,"%.+%",false,depends);
-        convertedSearchVal = substitute(convertedSearchVal,"@.+@",true,depends);
-        
-        //Replace any escaped substitution delimiters.
-        convertedSearchVal = convertedSearchVal.replaceAll("\\%","%");
-        convertedSearchVal = convertedSearchVal.replaceAll("\\@","@");
-
-        log.debug("The query string after inserting substitutions: " + convertedSearchVal);
-
-        try {
-            //Loads the database driver
-            loadDriver((String) props.get(DBDriverAtt));
-        } catch (ClassNotFoundException e) {
-            log.error("An ClassNotFoundException occured while loading database driver");
-            throw new ResolutionPlugInException(
-                "An ClassNotFoundException occured while loading database driver: " + e.getMessage());
-        } catch (IllegalAccessException e) {
-            log.error("An IllegalAccessException occured while loading database driver");
-            throw new ResolutionPlugInException(
-                "An IllegalAccessException occured while loading database driver: " + e.getMessage());
-        } catch (InstantiationException e) {
-            log.error("An InstantionException occured while loading database driver");
-            throw new ResolutionPlugInException(
-                "An InstantiationException occured while loading database driver: " + e.getMessage());
-        }
+               if (maxActive > 0) {
+                       objectPool.setMaxActive(maxActive);
+               }
+               if (maxIdle > 0) {
+                       objectPool.setMaxIdle(maxIdle);
+               }
+               if (maxWait > 0) {
+                       objectPool.setMaxWait(1000*maxWait);
+               }
 
-        try {
-            //Makes the connection to the database
-            conn = connect();
-        } catch (SQLException e) {
-            log.error("An ERROR occured while connecting to database");
-            throw new ResolutionPlugInException("An ERROR occured while connecting to the database: " + e.getMessage());
-        }
+               objectPool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK);
+               objectPool.setTestOnBorrow(true);
 
-        try {
-            //Gets the results set for the query
-            rs = executeQuery(conn, convertedSearchVal);
-            if (!rs.next())
-                return new BasicAttributes();
+               ConnectionFactory connFactory = null;
+               PoolableConnectionFactory poolConnFactory = null;
 
-        } catch (SQLException e) {
-            log.error("An ERROR occured while executing the query");
-            throw new ResolutionPlugInException("An ERROR occured while executing the query: " + e.getMessage());
-        }
+               try {
+                       connFactory = new DriverManagerConnectionFactory(dbURL, props);
+                       log.debug("Connection factory initialized.");
+               } catch (Exception ex) {
+                       log.error(
+                               "Connection factory couldn't be initialized, ensure database URL, username and password are correct.");
+                       throw new ResolutionPlugInException("Connection factory couldn't be initialized: " + ex.getMessage());
+               }
 
-        /**
-         * If the user has supplied their own class for extracting the attributes from the 
-         * result set, then their class will be run.  A BasicAttributes object is expected as
-         * the result of the extraction.
-         *
-         * If the user has no supplied their own class for extracting the attributes then 
-         * the default extraction is run, which is specified in DefaultAEAtt.
-         */
-        if (aeClassName == null || aeClassName.equals("")) {
-            aeClassName = DefaultAE.class.getName();
-        }
+               try {
+                       poolConnFactory =
+                       new PoolableConnectionFactory(
+                               connFactory,
+                               objectPool,
+                               new StackKeyedObjectPoolFactory(),
+                               validationQuery,
+                               true,
+                                       false);
+               } catch (Exception ex) {
+                       log.debug("Poolable connection factory error");
+               }
 
-        try {
-            Class aeClass = Class.forName(aeClassName);
-            Method aeMethod = aeClass.getMethod(AEInstanceMethodAtt, null);
-
-            //runs the "instance" method returning and instance of the object
-            aeClassObj = (JDBCAttributeExtractor) (aeMethod.invoke(null, null));
-            log.debug("Supplied attributeExtractor class loaded.");
-
-        } catch (ClassNotFoundException e) {
-            log.error("The supplied attribute extractor class could not be found");
-            throw new ResolutionPlugInException(
-                "The supplied attribute extractor class could not be found: " + e.getMessage());
-        } catch (NoSuchMethodException e) {
-            log.error("The requested method does not exist");
-            throw new ResolutionPlugInException("The requested method does not exist: " + e.getMessage());
-        } catch (IllegalAccessException e) {
-            log.error("Access is not permitted for invoking requested method");
-            throw new ResolutionPlugInException(
-                "Access is not permitted for invoking requested method: " + e.getMessage());
-        } catch (InvocationTargetException e) {
-            log.error("An ERROR occured invoking requested method");
-            throw new ResolutionPlugInException("An ERROR occured involking requested method: " + e.getMessage());
-        }
+               dataSource = new PoolingDataSource(objectPool);
+               log.info("Data Source initialized.");
+               try {
+                       dataSource.setLogWriter(
+                               new Log4jPrintWriter(Logger.getLogger(JDBCDataConnector.class.getName() + ".Pool"), Priority.DEBUG));
+               } catch (SQLException e) {
+                       log.error("Coudn't setup logger for database connection pool.");
+               }
+       }
+
+       /**
+        * Instantiate an Attribute Extractor, using the default if none was configured
+        */
+       private void setupAttributeExtractor(Element config) throws ResolutionPlugInException {
+
+               String className = null;
+               if (config != null) {
+                       className = config.getAttribute("class");
+               }
+               if (className == null || className.equals("")) {
+                       log.debug("Using default Attribute Extractor.");
+                       className = DefaultAE.class.getName();
+               }
+               try {
+                       Class aeClass = Class.forName(className);
+                       extractor = (JDBCAttributeExtractor) aeClass.newInstance();
+                       log.debug("Attribute Extractor implementation loaded.");
+
+               } catch (ClassNotFoundException e) {
+                       log.error("The supplied Attribute Extractor class could not be found: " + e);
+                       throw new ResolutionPlugInException(
+                               "The supplied Attribute Extractor class could not be found: " + e.getMessage());
+               } catch (Exception e) {
+                       log.error("Unable to instantiate Attribute Extractor implementation: " + e);
+                       throw new ResolutionPlugInException(
+                               "Unable to instantiate Attribute Extractor implementation: " + e.getMessage());
+               }
+       }
+
+       /**
+        * Instantiate a Statement Creator, using the default if none was configured
+        */
+       private void setupStatementCreator(Element config) throws ResolutionPlugInException {
+
+               String scClassName = null;
+               if (config != null) {
+                       scClassName = config.getAttribute("class");
+               }
+               if (scClassName == null || scClassName.equals("")) {
+                       log.debug("Using default Statement Creator.");
+                       scClassName = DefaultStatementCreator.class.getName();
+               }
+               try {
+                       Class scClass = Class.forName(scClassName);
+
+                       Class[] params = new Class[1];
+                       params[0] = Class.forName("org.w3c.dom.Element");
+                       try {
+                               Constructor implementorConstructor = scClass.getConstructor(params);
+                               Object[] args = new Object[1];
+                               args[0] = config;
+                               log.debug("Initializing Statement Creator of type (" + scClass.getName() + ").");
+                               statementCreator = (JDBCStatementCreator) implementorConstructor.newInstance(args);
+                       } catch (NoSuchMethodException nsme) {
+                               log.debug(
+                                       "Implementation constructor does have a parameterized constructor, attempting to load default.");
+                               statementCreator = (JDBCStatementCreator) scClass.newInstance();
+                       }
+                       log.debug("Statement Creator implementation loaded.");
+
+               } catch (ClassNotFoundException e) {
+                       log.error("The supplied Statement Creator class could not be found: " + e);
+                       throw new ResolutionPlugInException(
+                               "The supplied Statement Creator class could not be found: " + e.getMessage());
+               } catch (Exception e) {
+                       log.error("Unable to instantiate Statement Creator implementation: " + e);
+                       throw new ResolutionPlugInException(
+                               "Unable to instantiate Statement Creator implementation: " + e.getMessage());
+               }
+       }
+
+       public Attributes resolve(Principal principal, String requester, Dependencies depends)
+               throws ResolutionPlugInException {
+
+               log.debug("Resolving connector: (" + getId() + ")");
 
-        try {
-            return aeClassObj.extractAttributes(rs);
+               //Retrieve a connection from the connection pool
+               Connection conn = null;
+               try {
+                       conn = dataSource.getConnection();
+                       log.debug("Connection retrieved from pool");
+               } catch (Exception e) {
+                       log.error("JDBC Connector (" + getId() + ") unable to fetch a connection from the pool");
+                       throw new ResolutionPlugInException("Unable to fetch a connection from the pool: " + e.getMessage());
+               }
+               if (conn == null) {
+                       log.error("Pool didn't return a propertly initialized connection.");
+                       throw new ResolutionPlugInException("Pool didn't return a properly initialized connection.");
+               }
 
+               //Setup and execute a (pooled) prepared statement
+               ResultSet rs = null;
+               PreparedStatement preparedStatement = null;
+               try {
+                       preparedStatement = conn.prepareStatement(searchVal);
+            preparedStatement.clearParameters();
+                       statementCreator.create(preparedStatement, principal, requester, depends);
+                       rs = preparedStatement.executeQuery();
+                       if (!rs.next()) {
+                               return new BasicAttributes();
+                       }
+            return extractor.extractAttributes(rs);
+               } catch (JDBCStatementCreatorException e) {
+                       log.error("An ERROR occured while constructing the query");
+                       throw new ResolutionPlugInException("An ERROR occured while constructing the query: " + e.getMessage());
         } catch (JDBCAttributeExtractorException e) {
             log.error("An ERROR occured while extracting attributes from result set");
-            throw new ResolutionPlugInException(
-                "An ERROR occured while extracting attributes from result set: " + e.getMessage());
+            throw new ResolutionPlugInException("An ERROR occured while extracting attributes from result set: " + e.getMessage());
+               } catch (SQLException e) {
+                       log.error("An ERROR occured while executing the query");
+                       throw new ResolutionPlugInException("An ERROR occured while executing the query: " + e.getMessage());
         } finally {
+            Exception e_save = null;
             try {
-                //release result set
-                rs.close();
-                log.debug("Result set released");
+                if (preparedStatement != null) {
+                    preparedStatement.close();
+                }
             } catch (SQLException e) {
-                log.error("An error occured while closing the result set: " + e);
-                throw new ResolutionPlugInException("An error occured while closing the result set: " + e);
+                log.error("An error occured while closing the prepared statement: " + e.getMessage());
+                e_save = e;
+            }
+            try {
+                if (rs != null) {
+                    rs.close();
+                }
+            } catch (SQLException e) {
+                log.error("An error occured while closing the result set: " + e.getMessage());
+                e_save = e;
             }
-
             try {
-                //close the connection
                 conn.close();
-                log.debug("Connection to database closed");
             } catch (SQLException e) {
-                log.error("An error occured while closing the database connection: " + e);
-                throw new ResolutionPlugInException("An error occured while closing the database connection: " + e);
+                log.error("An error occured while closing the database connection: " + e.getMessage());
+                e_save = e;
+            }
+            if (e_save != null) {
+                throw new ResolutionPlugInException("An error occured while closing database objects:" + e_save.getMessage());
             }
         }
-    }
-
-    /** 
-     * Loads the driver used to access the database
-     * @param driver The driver used to access the database
-     * @throws ResolutionPlugInException If there is a failure to load the driver
-     */
-    public void loadDriver(String driver)
-        throws ClassNotFoundException, IllegalAccessException, InstantiationException {
-        Class.forName(driver).newInstance();
-        log.debug("Loading driver: " + driver);
-    }
-
-    /** 
-     * Makes a connection to the database using the property set.
-     * @return Connection object
-     * @throws SQLException If there is a failure to make a database connection
-     */
-    public Connection connect()
-        throws SQLException {
-        String url = props.getProperty(URLAtt);
-        log.debug(url);
-        Connection conn = DriverManager.getConnection(url,props);
-        log.debug("Connection with database established");
-
-        return conn;
-    }
-
-    /**
-     * Execute the users query
-     * @param query The query the user wishes to execute
-     * @return The result of the users <code>query</code>
-     * @return null if an error occurs during execution
-     * @throws SQLException If an error occurs while executing the query
-    */
-    public ResultSet executeQuery(Connection conn, String query) throws SQLException {
-        log.debug("Users Query: " + query);
-        Statement stmt = conn.createStatement();
-        return stmt.executeQuery(query);
-    }
+       }
+
+       /** 
+        * Loads the driver used to access the database
+        * @param driver The driver used to access the database
+        * @throws ResolutionPlugInException If there is a failure to load the driver
+        */
+       public void loadDriver(String driver) throws ResolutionPlugInException {
+               try {
+                       Class.forName(driver).newInstance();
+                       log.debug("Loading JDBC driver: " + driver);
+               } catch (Exception e) {
+                       log.error("An error loading database driver: " + e);
+                       throw new ResolutionPlugInException(
+                               "An IllegalAccessException occured while loading database driver: " + e.getMessage());
+               }
+               log.debug("Driver loaded.");
+       }
+
+       private class Log4jPrintWriter extends PrintWriter {
+
+               private Priority level;
+               private Logger logger;
+               private StringBuffer text = new StringBuffer("");
+
+               private Log4jPrintWriter(Logger logger, org.apache.log4j.Priority level) {
+                       super(System.err);
+                       this.level = level;
+                       this.logger = logger;
+               }
+
+               public void close() {
+                       flush();
+               }
+
+               public void flush() {
+                       if (!text.toString().equals("")) {
+                               logger.log(level, text.toString());
+                               text.setLength(0);
+                       }
+               }
+
+               public void print(boolean b) {
+                       text.append(b);
+               }
+
+               public void print(char c) {
+                       text.append(c);
+               }
+
+               public void print(char[] s) {
+                       text.append(s);
+               }
+
+               public void print(double d) {
+                       text.append(d);
+               }
+
+               public void print(float f) {
+                       text.append(f);
+               }
+
+               public void print(int i) {
+                       text.append(i);
+               }
+
+               public void print(long l) {
+                       text.append(l);
+               }
+
+               public void print(Object obj) {
+                       text.append(obj);
+               }
+
+               public void print(String s) {
+                       text.append(s);
+               }
+
+               public void println() {
+                       if (!text.toString().equals("")) {
+                               logger.log(level, text.toString());
+                               text.setLength(0);
+                       }
+               }
+
+               public void println(boolean x) {
+                       text.append(x);
+                       logger.log(level, text.toString());
+                       text.setLength(0);
+               }
+
+               public void println(char x) {
+                       text.append(x);
+                       logger.log(level, text.toString());
+                       text.setLength(0);
+               }
+
+               public void println(char[] x) {
+                       text.append(x);
+                       logger.log(level, text.toString());
+                       text.setLength(0);
+               }
+
+               public void println(double x) {
+                       text.append(x);
+                       logger.log(level, text.toString());
+                       text.setLength(0);
+               }
+
+               public void println(float x) {
+                       text.append(x);
+                       logger.log(level, text.toString());
+                       text.setLength(0);
+               }
+
+               public void println(int x) {
+                       text.append(x);
+                       logger.log(level, text.toString());
+                       text.setLength(0);
+               }
+
+               public void println(long x) {
+                       text.append(x);
+                       logger.log(level, text.toString());
+                       text.setLength(0);
+               }
+
+               public void println(Object x) {
+                       text.append(x);
+                       logger.log(level, text.toString());
+                       text.setLength(0);
+               }
+
+               public void println(String x) {
+                       text.append(x);
+                       logger.log(level, text.toString());
+                       text.setLength(0);
+               }
+       }
 }
 
 /**
  * The default attribute extractor. 
  */
-
 class DefaultAE implements JDBCAttributeExtractor {
-    private static DefaultAE _instance = null;
-    private static Logger log = Logger.getLogger(DefaultAE.class.getName());
-
-    // Constructor
-    protected DefaultAE() {
-    }
-
-    // Ensures that only one istance of the class at a time
-    public static DefaultAE instance() {
-        if (_instance == null)
-            return new DefaultAE();
-        else
-            return _instance;
-    }
-
-    /**
-     * Method of extracting the attributes from the supplied result set.
-     *
-     * @param ResultSet The result set from the query which contains the attributes
-     * @return BasicAttributes as objects containing all the attributes
-     * @throws JDBCAttributeExtractorException If there is a complication in retrieving the attributes
-     */
-    public BasicAttributes extractAttributes(ResultSet rs) throws JDBCAttributeExtractorException {
-        BasicAttributes attributes = new BasicAttributes();
-
-        log.debug("Using default Attribute Extractor");
-
-        try {
+
+       private static Logger log = Logger.getLogger(DefaultAE.class.getName());
+
+       /**
+        * Method of extracting the attributes from the supplied result set.
+        *
+        * @param ResultSet The result set from the query which contains the attributes
+        * @return BasicAttributes as objects containing all the attributes
+        * @throws JDBCAttributeExtractorException If there is a complication in retrieving the attributes
+        */
+       public BasicAttributes extractAttributes(ResultSet rs) throws JDBCAttributeExtractorException {
+               BasicAttributes attributes = new BasicAttributes();
+        int row = 0;
+        
+               try {
+            // Get metadata about result set.
             ResultSetMetaData rsmd = rs.getMetaData();
             int numColumns = rsmd.getColumnCount();
             log.debug("Number of returned columns: " + numColumns);
 
-            for (int i = 1; i <= numColumns; i++) {
-                String columnName = rsmd.getColumnName(i);
-                String columnType = rsmd.getColumnTypeName(i);
-                Object columnValue = rs.getObject(columnName);
-                log.debug(
-                    "(" + i + ". ColumnType = " + columnType + ") " + columnName + " -> " + (columnValue!=null ? columnValue.toString() : "(null)"));
-                attributes.put(new BasicAttribute(columnName, columnValue));
+            do {
+                for (int i = 1; i <= numColumns; i++) {
+                    String columnName = rsmd.getColumnName(i);
+                    Object columnValue = rs.getObject(columnName);
+                    if (log.isDebugEnabled()) {
+                        log.debug(
+                            "("
+                                + i
+                                + ". ColumnType = " + rsmd.getColumnTypeName(i)
+                                + ") "
+                                + columnName
+                                + " -> "
+                                + (columnValue != null ? columnValue.toString() : "(null)"));
+                    }
+                    if (row == 0) {
+                        BasicAttribute ba = new BasicAttribute(columnName, true);
+                        ba.add(row,columnValue);
+                        attributes.put(ba);
+                    }
+                    else {
+                        attributes.get(columnName).add(row,columnValue);
+                    }
+                }
+                row++;
+            } while (rs.next());
+               } catch (SQLException e) {
+                       log.error("An ERROR occured while processing result set");
+                       throw new JDBCAttributeExtractorException(
+                               "An ERROR occured while processing result set: " + e.getMessage());
+               }
+
+               return attributes;
+       }
+}
+
+class DefaultStatementCreator implements JDBCStatementCreator {
+
+       private static Logger log = Logger.getLogger(DefaultStatementCreator.class.getName());
+
+       public void create(
+               PreparedStatement preparedStatement,
+               Principal principal,
+               String requester,
+               Dependencies depends)
+               throws JDBCStatementCreatorException {
+
+               try {
+                       log.debug("Creating prepared statement.  Substituting principal: (" + principal.getName() + ")");
+                       preparedStatement.setString(1, principal.getName());
+            //Tried using ParameterMetaData to determine param count, but it fails, so...
+            try {
+                int i=2;
+                while (true) {
+                    preparedStatement.setString(i++, principal.getName());
+                }
+            } catch (SQLException e) {
+                //Ignore any additional exceptions, assume parameters simply don't exist.
             }
-        }
-        catch (SQLException e) {
-            log.error("An ERROR occured while retrieving result set meta data");
-            throw new JDBCAttributeExtractorException(
-                "An ERROR occured while retrieving result set meta data: " + e.getMessage());
-        }
+               } catch (SQLException e) {
+                       log.error("Encountered an error while creating prepared statement: " + e);
+                       throw new JDBCStatementCreatorException(
+                               "Encountered an error while creating prepared statement: " + e.getMessage());
+               }
+       }
+}
 
-        // Check for multiple rows.
-        try {
-            if (rs.next())
-                throw new JDBCAttributeExtractorException("Query returned more than one row.");
-        }
-        catch (SQLException e) {
+class DependencyStatementCreator implements JDBCStatementCreator {
+
+       private static Logger log = Logger.getLogger(DependencyStatementCreator.class.getName());
+       private ArrayList parameters = new ArrayList();
+
+       public DependencyStatementCreator(Element conf) throws JDBCStatementCreatorException {
+
+               NodeList nodes = conf.getElementsByTagName("Parameter");
+               for (int i = 0; i < nodes.getLength(); i++) {
+                       Element parameter = (Element) nodes.item(i);
+                       String type = "String";
+                       if (parameter.getAttribute("type") != null && (!parameter.getAttribute("type").equals(""))) {
+                               type = parameter.getAttribute("type");
+                       }
+
+                       if (parameter.getAttribute("attributeName") == null
+                               || parameter.getAttribute("attributeName").equals("")) {
+                               log.error("Statement Creator Parameter must reference an attribute by name.");
+                               throw new JDBCStatementCreatorException("Statement Creator Parameter must reference an attribute by name.");
+                       }
+
+                       if (parameter.getAttribute("connectorId") != null && (!parameter.getAttribute("connectorId").equals(""))) {
+                               parameters.add(
+                                       new Parameter(
+                                               type,
+                                               parameter.getAttribute("attributeName"),
+                                               parameter.getAttribute("connectorId")));
+                       } else {
+                               parameters.add(new Parameter(type, parameter.getAttribute("attributeName")));
+
+                       }
+
+                       if (parameter.getAttribute("nullMissing") != null && (!parameter.getAttribute("nullMissing").equals(""))) {
+                               if (parameter.getAttribute("nullMissing").equalsIgnoreCase("FALSE")) {
+                                       ((Parameter) parameters.get(i)).setNullMissing(false);
+                               }
+                       }
+               }
+               log.debug("Parameters configured: " + parameters.size());
+       }
+
+       public void create(
+               PreparedStatement preparedStatement,
+               Principal principal,
+               String requester,
+               Dependencies depends)
+               throws JDBCStatementCreatorException {
+
+               try {
+                       log.debug("Creating prepared statement.  Substituting values from dependencies.");
+                       for (int i = 0; i < parameters.size(); i++) {
+                               ((Parameter) parameters.get(i)).setParameterValue(preparedStatement, i + 1, depends);
+                       }
+
+               } catch (Exception e) {
+                       log.error("Encountered an error while creating prepared statement (principal=" + principal.getName() + "): " + e);
+                        throw new JDBCStatementCreatorException(
+                               "Encountered an error while creating prepared statement: " + e.getMessage());
+               }
+       }
+
+       protected class Parameter {
+               private String type;
+               private String attributeName;
+               private boolean referencesConnector = false;
+               private String connectorId;
+               private boolean nullMissing = true;
+
+               protected Parameter(String type, String attributeName) throws JDBCStatementCreatorException {
+                       if ((!type.equalsIgnoreCase("String"))
+                               && (!type.equalsIgnoreCase("Integer"))
+                               && (!type.equalsIgnoreCase("Byte"))
+                               && (!type.equalsIgnoreCase("Double"))
+                               && (!type.equalsIgnoreCase("Float"))
+                               && (!type.equalsIgnoreCase("Long"))
+                               && (!type.equalsIgnoreCase("Short"))
+                               && (!type.equalsIgnoreCase("Boolean"))
+                               && (!type.equalsIgnoreCase("Date"))
+                               && (!type.equalsIgnoreCase("Blob"))
+                               && (!type.equalsIgnoreCase("Clob"))) {
+                               log.error("Unsupported type configured for Statement Creator Parameter.");
+                               throw new JDBCStatementCreatorException("Unsupported type on Statement Creator Parameter.");
+                       }
+                       this.type = type;
+                       this.attributeName = attributeName;
+               }
+
+               protected Parameter(String type, String attributeName, String connectorId)
+                       throws JDBCStatementCreatorException {
+                       this(type, attributeName);
+                       referencesConnector = true;
+                       this.connectorId = connectorId;
+
+               }
+        
+        protected int getSQLType() {
+            if (type.equalsIgnoreCase("String")) {
+                return Types.VARCHAR;
+            } else if (type.equalsIgnoreCase("Integer")) {
+                return Types.INTEGER;
+            } else if (type.equalsIgnoreCase("Byte")) {
+                return Types.TINYINT;
+            } else if (type.equalsIgnoreCase("Double")) {
+                return Types.DOUBLE;
+            } else if (type.equalsIgnoreCase("Float")) {
+                return Types.FLOAT;
+            } else if (type.equalsIgnoreCase("Long")) {
+                return Types.INTEGER;
+            } else if (type.equalsIgnoreCase("Short")) {
+                return Types.SMALLINT;
+            } else if (type.equalsIgnoreCase("Boolean")) {
+                return Types.BOOLEAN;
+            } else if (type.equalsIgnoreCase("Date")) {
+                return Types.DATE;
+            } else if (type.equalsIgnoreCase("Blob")) {
+                return Types.BLOB;
+            } else if (type.equalsIgnoreCase("Clob")) {
+                return Types.CLOB;
+            } else {
+                return Types.VARCHAR;
+            }
         }
 
-        return attributes;
-    }
+               protected void setParameterValue(PreparedStatement preparedStatement, int valueIndex, Dependencies depends)
+                       throws JDBCStatementCreatorException {
+
+                       //handle values from DataConnectors
+                       if (referencesConnector) {
+                               Attributes attributes = depends.getConnectorResolution(connectorId);
+                               if (attributes == null) {
+                                       log.error(
+                                               "Statement Creator misconfiguration: Connector ("
+                                                       + connectorId
+                                                       + ") is not a dependency of this JDBCDataConnector.");
+                                       throw new JDBCStatementCreatorException(
+                                               "Statement Creator misconfiguration: Connector ("
+                                                       + connectorId
+                                                       + ") is not a dependency of this JDBCDataConnector.");
+                               }
+
+                               Attribute attribute = attributes.get(attributeName);
+                               if (attribute == null || attribute.size() < 1) {
+                                       if (nullMissing) {
+                                               try {
+                                                       preparedStatement.setNull(valueIndex, getSQLType());
+                                                       return;
+                                               } catch (SQLException e) {
+                                                       log.error(
+                                                               "Encountered a problem while attempting to convert missing attribute value to null parameter.");
+                                               }
+                                       }
+                                       log.error("Cannot parameterize prepared statement: missing dependency value.");
+                                       throw new JDBCStatementCreatorException("Cannot parameterize prepared statement: missing dependency value.");
+                               }
+
+                               if (attribute.size() > 1) {
+                                       log.error("Statement Creator encountered a multivalued dependent attribute.");
+                                       throw new JDBCStatementCreatorException("Statement Creator encountered a multivalued dependent attribute.");
+                               }
+
+                               try {
+                                       setSpecificParameter(preparedStatement, valueIndex, attribute.get());
+                                       return;
+                               } catch (NamingException e) {
+                                       log.error(
+                                               "Statement Creator encountered an error while extracting attributes from a Data Conector: "
+                                                       + e);
+                                       throw new JDBCStatementCreatorException(
+                                               "Statement Creator encountered an error while extracting attributes from a Data Conector: "
+                                                       + e.getMessage());
+                               }
+                       }
+
+                       //handle values from AttributeDefinitons
+                       ResolverAttribute attribute = depends.getAttributeResolution(attributeName);
+                       if (attribute != null) {
+                               Iterator iterator = attribute.getValues();
+                               if (iterator.hasNext()) {
+                                       setSpecificParameter(preparedStatement, valueIndex, iterator.next());
+                                       if (iterator.hasNext()) {
+                                               log.error("Statement Creator encountered a multivalued dependent attribute.");
+                                               throw new JDBCStatementCreatorException("Statement Creator encountered a multivalued dependent attribute.");
+                                       }
+                                       return;
+                               }
+                       }
+                       if (nullMissing) {
+                               try {
+                                       preparedStatement.setNull(valueIndex, getSQLType());
+                                       return;
+                               } catch (SQLException e) {
+                                       log.error(
+                                               "Encountered a problem while attempting to convert missing attribute value to null parameter.");
+                               }
+                       }
+                       log.error("Cannot parameterize prepared statement: missing dependency value.");
+                       throw new JDBCStatementCreatorException("Cannot parameterize prepared statement: missing dependency value.");
+               }
+
+               protected void setNullMissing(boolean nullMissing) {
+                       this.nullMissing = nullMissing;
+               }
+
+               private void setSpecificParameter(PreparedStatement preparedStatement, int valueIndex, Object object)
+                       throws JDBCStatementCreatorException {
+
+                       if (object == null) {
+                               try {
+                                       preparedStatement.setNull(valueIndex, getSQLType());
+                                       return;
+                               } catch (SQLException e) {
+                                       log.error(
+                                               "Encountered a problem while attempting to convert missing attribute value to null parameter.");
+                                       throw new JDBCStatementCreatorException("Encountered a problem while attempting to convert missing attribute value to null parameter.");
+                               }
+                       } else if (type.equalsIgnoreCase("String")) {
+                               setString(preparedStatement, valueIndex, object);
+                       } else if (type.equalsIgnoreCase("Integer")) {
+                               setInteger(preparedStatement, valueIndex, object);
+                       } else if (type.equalsIgnoreCase("Byte")) {
+                               setByte(preparedStatement, valueIndex, object);
+                       } else if (type.equalsIgnoreCase("Double")) {
+                               setDouble(preparedStatement, valueIndex, object);
+                       } else if (type.equalsIgnoreCase("Float")) {
+                               setFloat(preparedStatement, valueIndex, object);
+                       } else if (type.equalsIgnoreCase("Long")) {
+                               setLong(preparedStatement, valueIndex, object);
+                       } else if (type.equalsIgnoreCase("Short")) {
+                               setShort(preparedStatement, valueIndex, object);
+                       } else if (type.equalsIgnoreCase("Boolean")) {
+                               setBoolean(preparedStatement, valueIndex, object);
+                       } else if (type.equalsIgnoreCase("Date")) {
+                               setDate(preparedStatement, valueIndex, object);
+                       } else if (type.equalsIgnoreCase("Blob")) {
+                               setBlob(preparedStatement, valueIndex, object);
+                       } else if (type.equalsIgnoreCase("Clob")) {
+                               setClob(preparedStatement, valueIndex, object);
+                       } else {
+                               setString(preparedStatement, valueIndex, object);
+                       }
+               }
+
+               private void setClob(PreparedStatement preparedStatement, int valueIndex, Object object)
+                       throws JDBCStatementCreatorException {
+                       if (object instanceof Clob) {
+                               try {
+                                       preparedStatement.setClob(valueIndex, (Clob) object);
+                                       return;
+                               } catch (SQLException e) {
+                                       log.error("Encountered an error while adding parameter to prepared statement: " + e);
+                                       throw new JDBCStatementCreatorException(
+                                               "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
+                               }
+                       }
+                       log.error("Encountered a dependency with an invalid java type.");
+                       throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");
+               }
+
+               private void setBlob(PreparedStatement preparedStatement, int valueIndex, Object object)
+                       throws JDBCStatementCreatorException {
+                       if (object instanceof Blob) {
+                               try {
+                                       preparedStatement.setBlob(valueIndex, (Blob) object);
+                                       return;
+                               } catch (SQLException e) {
+                                       log.error("Encountered an error while adding parameter to prepared statement: " + e);
+                                       throw new JDBCStatementCreatorException(
+                                               "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
+                               }
+                       }
+                       log.error("Encountered a dependency with an invalid java type.");
+                       throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");
+               }
+
+               private void setDate(PreparedStatement preparedStatement, int valueIndex, Object object)
+                       throws JDBCStatementCreatorException {
+
+                       if (object instanceof java.sql.Date) {
+                               try {
+                                       preparedStatement.setDate(valueIndex, (java.sql.Date) object);
+                                       return;
+                               } catch (SQLException e) {
+                                       log.error("Encountered an error while adding parameter to prepared statement: " + e);
+                                       throw new JDBCStatementCreatorException(
+                                               "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
+                               }
+                       } else if (object instanceof java.util.Date) {
+                               try {
+                                       //If you want to be frustrated by the java class library, look no further...
+                                       preparedStatement.setDate(valueIndex, new java.sql.Date(((java.util.Date) object).getTime()));
+                                       return;
+                               } catch (SQLException e) {
+                                       log.error("Encountered an error while adding parameter to prepared statement: " + e);
+                                       throw new JDBCStatementCreatorException(
+                                               "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
+                               }
+                       } else if (object instanceof Long) {
+                               try {
+                                       preparedStatement.setDate(valueIndex, new java.sql.Date(((Long) object).longValue()));
+                                       return;
+                               } catch (SQLException e) {
+                                       log.error("Encountered an error while adding parameter to prepared statement: " + e);
+                                       throw new JDBCStatementCreatorException(
+                                               "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
+                               }
+                       } else if (object instanceof String) {
+                               try {
+                                       preparedStatement.setDate(
+                                               valueIndex,
+                                               new java.sql.Date(new SimpleDateFormat().parse((String) object).getTime()));
+                                       return;
+                               } catch (Exception e) {
+                                       log.error("Encountered an error while adding parameter to prepared statement: " + e);
+                                       throw new JDBCStatementCreatorException(
+                                               "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
+                               }
+                       }
+                       log.error("Encountered a dependency with an invalid java type.");
+                       throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");
+               }
+
+               private void setBoolean(PreparedStatement preparedStatement, int valueIndex, Object object)
+                       throws JDBCStatementCreatorException {
+                       if (object instanceof Boolean) {
+                               try {
+                                       preparedStatement.setBoolean(valueIndex, ((Boolean) object).booleanValue());
+                                       return;
+                               } catch (SQLException e) {
+                                       log.error("Encountered an error while adding parameter to prepared statement: " + e);
+                                       throw new JDBCStatementCreatorException(
+                                               "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
+                               }
+                       } else if (object instanceof String) {
+                               try {
+                                       preparedStatement.setBoolean(valueIndex, new Boolean((String) object).booleanValue());
+                                       return;
+                               } catch (Exception e) {
+                                       log.error("Encountered an error while adding parameter to prepared statement: " + e);
+                                       throw new JDBCStatementCreatorException(
+                                               "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
+                               }
+                       }
+                       log.error("Encountered a dependency with an invalid java type.");
+                       throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");
+               }
+
+               private void setShort(PreparedStatement preparedStatement, int valueIndex, Object object)
+                       throws JDBCStatementCreatorException {
+                       if (object instanceof Boolean) {
+                               try {
+                                       preparedStatement.setShort(valueIndex, ((Short) object).shortValue());
+                                       return;
+                               } catch (SQLException e) {
+                                       log.error("Encountered an error while adding parameter to prepared statement: " + e);
+                                       throw new JDBCStatementCreatorException(
+                                               "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
+                               }
+                       } else if (object instanceof String) {
+                               try {
+                                       preparedStatement.setShort(valueIndex, new Short((String) object).shortValue());
+                                       return;
+                               } catch (Exception e) {
+                                       log.error("Encountered an error while adding parameter to prepared statement: " + e);
+                                       throw new JDBCStatementCreatorException(
+                                               "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
+                               }
+                       }
+                       log.error("Encountered a dependency with an invalid java type.");
+                       throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");
+               }
+
+               private void setLong(PreparedStatement preparedStatement, int valueIndex, Object object)
+                       throws JDBCStatementCreatorException {
+                       if (object instanceof Long || object instanceof Integer || object instanceof Short) {
+                               try {
+                                       preparedStatement.setLong(valueIndex, ((Number) object).longValue());
+                                       return;
+                               } catch (SQLException e) {
+                                       log.error("Encountered an error while adding parameter to prepared statement: " + e);
+                                       throw new JDBCStatementCreatorException(
+                                               "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
+                               }
+                       } else if (object instanceof String) {
+                               try {
+                                       preparedStatement.setLong(valueIndex, new Long((String) object).longValue());
+                                       return;
+                               } catch (Exception e) {
+                                       log.error("Encountered an error while adding parameter to prepared statement: " + e);
+                                       throw new JDBCStatementCreatorException(
+                                               "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
+                               }
+                       }
+                       log.error("Encountered a dependency with an invalid java type.");
+                       throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");
+               }
+
+               private void setFloat(PreparedStatement preparedStatement, int valueIndex, Object object)
+                       throws JDBCStatementCreatorException {
+                       if (object instanceof Float) {
+                               try {
+                                       preparedStatement.setFloat(valueIndex, ((Float) object).floatValue());
+                                       return;
+                               } catch (SQLException e) {
+                                       log.error("Encountered an error while adding parameter to prepared statement: " + e);
+                                       throw new JDBCStatementCreatorException(
+                                               "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
+                               }
+                       } else if (object instanceof String) {
+                               try {
+                                       preparedStatement.setFloat(valueIndex, new Float((String) object).floatValue());
+                                       return;
+                               } catch (Exception e) {
+                                       log.error("Encountered an error while adding parameter to prepared statement: " + e);
+                                       throw new JDBCStatementCreatorException(
+                                               "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
+                               }
+                       }
+                       log.error("Encountered a dependency with an invalid java type.");
+                       throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");
+               }
+
+               private void setDouble(PreparedStatement preparedStatement, int valueIndex, Object object)
+                       throws JDBCStatementCreatorException {
+                       if (object instanceof Double || object instanceof Float) {
+                               try {
+                                       preparedStatement.setDouble(valueIndex, ((Number) object).doubleValue());
+                                       return;
+                               } catch (SQLException e) {
+                                       log.error("Encountered an error while adding parameter to prepared statement: " + e);
+                                       throw new JDBCStatementCreatorException(
+                                               "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
+                               }
+                       } else if (object instanceof String) {
+                               try {
+                                       preparedStatement.setDouble(valueIndex, new Double((String) object).doubleValue());
+                                       return;
+                               } catch (Exception e) {
+                                       log.error("Encountered an error while adding parameter to prepared statement: " + e);
+                                       throw new JDBCStatementCreatorException(
+                                               "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
+                               }
+                       }
+                       log.error("Encountered a dependency with an invalid java type.");
+                       throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");
+               }
+
+               private void setByte(PreparedStatement preparedStatement, int valueIndex, Object object)
+                       throws JDBCStatementCreatorException {
+                       if (object instanceof Byte) {
+                               try {
+                                       preparedStatement.setByte(valueIndex, ((Byte) object).byteValue());
+                                       return;
+                               } catch (SQLException e) {
+                                       log.error("Encountered an error while adding parameter to prepared statement: " + e);
+                                       throw new JDBCStatementCreatorException(
+                                               "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
+                               }
+                       } else if (object instanceof String) {
+                               try {
+                                       preparedStatement.setByte(valueIndex, new Byte((String) object).byteValue());
+                                       return;
+                               } catch (Exception e) {
+                                       log.error("Encountered an error while adding parameter to prepared statement: " + e);
+                                       throw new JDBCStatementCreatorException(
+                                               "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
+                               }
+                       }
+                       log.error("Encountered a dependency with an invalid java type.");
+                       throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");
+               }
+
+               private void setInteger(PreparedStatement preparedStatement, int valueIndex, Object object)
+                       throws JDBCStatementCreatorException {
+                       if (object instanceof Integer || object instanceof Short) {
+                               try {
+                                       preparedStatement.setInt(valueIndex, ((Number) object).intValue());
+                                       return;
+                               } catch (SQLException e) {
+                                       log.error("Encountered an error while adding parameter to prepared statement: " + e);
+                                       throw new JDBCStatementCreatorException(
+                                               "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
+                               }
+                       } else if (object instanceof String) {
+                               try {
+                                       preparedStatement.setInt(valueIndex, new Integer((String) object).intValue());
+                                       return;
+                               } catch (Exception e) {
+                                       log.error("Encountered an error while adding parameter to prepared statement: " + e);
+                                       throw new JDBCStatementCreatorException(
+                                               "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
+                               }
+                       }
+                       log.error("Encountered a dependency with an invalid java type.");
+                       throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");
+               }
+
+               private void setString(PreparedStatement preparedStatement, int valueIndex, Object object)
+                       throws JDBCStatementCreatorException {
+                       if (object instanceof String) {
+                               try {
+                                       preparedStatement.setString(valueIndex, (String) object);
+                                       return;
+                               } catch (SQLException e) {
+                                       log.error("Encountered an error while adding parameter to prepared statement: " + e);
+                                       throw new JDBCStatementCreatorException(
+                                               "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
+                               }
+                       }
+                       log.error("Encountered a dependency with an invalid java type.");
+                       throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");
+               }
+       }
 }