Clear statement parameters before new call.
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / aa / attrresolv / provider / JDBCDataConnector.java
index d88c285..928a721 100644 (file)
@@ -28,12 +28,21 @@ package edu.internet2.middleware.shibboleth.aa.attrresolv.provider;
 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.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.ResultSetMetaData;
 import java.sql.SQLException;
-
+import java.sql.Types;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Properties;
+
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
 import javax.naming.directory.Attributes;
 import javax.naming.directory.BasicAttribute;
 import javax.naming.directory.BasicAttributes;
@@ -55,6 +64,7 @@ import edu.internet2.middleware.shibboleth.aa.attrresolv.AttributeResolver;
 import edu.internet2.middleware.shibboleth.aa.attrresolv.DataConnectorPlugIn;
 import edu.internet2.middleware.shibboleth.aa.attrresolv.Dependencies;
 import edu.internet2.middleware.shibboleth.aa.attrresolv.ResolutionPlugInException;
+import edu.internet2.middleware.shibboleth.aa.attrresolv.ResolverAttribute;
 
 /*
  * Built at the Canada Institute for Scientific and Technical Information (CISTI 
@@ -74,7 +84,7 @@ import edu.internet2.middleware.shibboleth.aa.attrresolv.ResolutionPlugInExcepti
  * @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());
        protected String searchVal;
@@ -82,12 +92,12 @@ public class JDBCDataConnector extends BaseResolutionPlugIn implements DataConne
        protected JDBCAttributeExtractor extractor;
        protected JDBCStatementCreator statementCreator;
 
-       public JDBCDataConnector(Element element) throws ResolutionPlugInException {
+       public JDBCDataConnector(Element e) throws ResolutionPlugInException {
 
-               super(element);
+               super(e);
 
                //Get the query string
-               NodeList queryNodes = element.getElementsByTagNameNS(AttributeResolver.resolverNamespace, "Query");
+               NodeList queryNodes = e.getElementsByTagNameNS(AttributeResolver.resolverNamespace, "Query");
                Node tnode = queryNodes.item(0).getFirstChild();
                if (tnode != null && tnode.getNodeType() == Node.TEXT_NODE) {
                        searchVal = tnode.getNodeValue();
@@ -98,42 +108,72 @@ public class JDBCDataConnector extends BaseResolutionPlugIn implements DataConne
                }
 
                //Load the supplied JDBC driver
-               String dbDriverName = element.getAttribute("dbDriver");
+               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";
+               }
+
                //Load site-specific implementation classes     
                setupAttributeExtractor(
-                       (Element) element.getElementsByTagNameNS(AttributeResolver.resolverNamespace, "AttributeExtractor").item(
+                       (Element) e.getElementsByTagNameNS(AttributeResolver.resolverNamespace, "AttributeExtractor").item(
                                0));
                setupStatementCreator(
-                       (Element) element.getElementsByTagNameNS(AttributeResolver.resolverNamespace, "StatementCreator").item(0));
-
+                       (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");
+            String propertiesValue = property.getAttribute("value");
+
+            if (propertiesName != null
+                && !propertiesName.equals("")
+                && propertiesValue != null
+                && !propertiesValue.equals("")) {
+                props.setProperty(propertiesName, propertiesValue);
+                log.debug("Property: (" + propertiesName + ")");
+                log.debug("   Value: (" + propertiesValue + ")");
+            } else {
+                log.error("Property is malformed.");
+                throw new ResolutionPlugInException("Property is malformed.");
+            }
+        }
+        
                //Initialize a pooling Data Source
                int maxActive = 0;
                int maxIdle = 0;
+        int maxWait = 30;
                try {
-                       if (element.getAttribute("maxActive") != null) {
-                               maxActive = Integer.parseInt(element.getAttribute("maxActive"));
+                       if (e.getAttributeNode("maxActive") != null) {
+                               maxActive = Integer.parseInt(e.getAttribute("maxActive"));
                        }
-                       if (element.getAttribute("maxIdle") != null) {
-                               maxIdle = Integer.parseInt(element.getAttribute("maxIdle"));
+                       if (e.getAttributeNode("maxIdle") != null) {
+                               maxIdle = Integer.parseInt(e.getAttribute("maxIdle"));
                        }
-               } catch (NumberFormatException e) {
+            if (e.getAttributeNode("maxWait") != null) {
+                maxWait = Integer.parseInt(e.getAttribute("maxWait"));
+            }
+               } catch (NumberFormatException ex) {
                        log.error("Malformed pooling limits: using defaults.");
                }
-               if (element.getAttribute("dbURL") == null || element.getAttribute("dbURL").equals("")) {
+               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(element.getAttribute("dbURL"), maxActive, maxIdle);
+               setupDataSource(e.getAttribute("dbURL"), props, maxActive, maxIdle, maxWait, validationQuery);
        }
 
        /**
         * Initialize a Pooling Data Source
         */
-       private void setupDataSource(String dbURL, int maxActive, int maxIdle) throws ResolutionPlugInException {
+       private void setupDataSource(String dbURL, Properties props, int maxActive, int maxIdle, int maxWait, String validationQuery) throws ResolutionPlugInException {
 
                GenericObjectPool objectPool = new GenericObjectPool(null);
 
@@ -143,31 +183,34 @@ public class JDBCDataConnector extends BaseResolutionPlugIn implements DataConne
                if (maxIdle > 0) {
                        objectPool.setMaxIdle(maxIdle);
                }
+               if (maxWait > 0) {
+                       objectPool.setMaxWait(1000*maxWait);
+               }
 
                objectPool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK);
+               objectPool.setTestOnBorrow(true);
 
                ConnectionFactory connFactory = null;
                PoolableConnectionFactory poolConnFactory = null;
 
                try {
-                       connFactory = new DriverManagerConnectionFactory(dbURL, null);
+                       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 facotry couldn't be initialized: " + ex.getMessage());
+                       throw new ResolutionPlugInException("Connection factory couldn't be initialized: " + ex.getMessage());
                }
 
                try {
-                       new StackKeyedObjectPoolFactory();
                        poolConnFactory =
-                               new PoolableConnectionFactory(
-                                       connFactory,
-                                       objectPool,
-                                       new StackKeyedObjectPoolFactory(),
-                                       null,
-                                       false,
-                                       true);
+                       new PoolableConnectionFactory(
+                               connFactory,
+                               objectPool,
+                               new StackKeyedObjectPoolFactory(),
+                               validationQuery,
+                               true,
+                                       false);
                } catch (Exception ex) {
                        log.debug("Poolable connection factory error");
                }
@@ -240,7 +283,6 @@ public class JDBCDataConnector extends BaseResolutionPlugIn implements DataConne
                                        "Implementation constructor does have a parameterized constructor, attempting to load default.");
                                statementCreator = (JDBCStatementCreator) scClass.newInstance();
                        }
-
                        log.debug("Statement Creator implementation loaded.");
 
                } catch (ClassNotFoundException e) {
@@ -265,57 +307,63 @@ public class JDBCDataConnector extends BaseResolutionPlugIn implements DataConne
                        conn = dataSource.getConnection();
                        log.debug("Connection retrieved from pool");
                } catch (Exception e) {
-                       log.error("Unable to fetch a connection from the pool");
+                       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 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 preparedStatement = conn.prepareStatement(searchVal);
+                       preparedStatement = conn.prepareStatement(searchVal);
+            preparedStatement.clearParameters();
                        statementCreator.create(preparedStatement, principal, requester, depends);
                        rs = preparedStatement.executeQuery();
-                       preparedStatement.close();
-
                        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());
                } catch (SQLException e) {
                        log.error("An ERROR occured while executing the query");
                        throw new ResolutionPlugInException("An ERROR occured while executing the query: " + e.getMessage());
-               }
-
-               //Extract attributes from the ResultSet
-               try {
-                       return extractor.extractAttributes(rs);
-
-               } 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());
-               } finally {
-                       try {
-                               rs.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);
-                       }
-
-                       try {
-                               conn.close();
-                       } 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);
-                       }
-               }
+        } finally {
+            Exception e_save = null;
+            try {
+                if (preparedStatement != null) {
+                    preparedStatement.close();
+                }
+            } catch (SQLException 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 {
+                conn.close();
+            } catch (SQLException 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());
+            }
+        }
        }
 
        /** 
@@ -456,10 +504,10 @@ public class JDBCDataConnector extends BaseResolutionPlugIn implements DataConne
                }
        }
 }
+
 /**
  * The default attribute extractor. 
  */
-
 class DefaultAE implements JDBCAttributeExtractor {
 
        private static Logger log = Logger.getLogger(DefaultAE.class.getName());
@@ -473,39 +521,43 @@ class DefaultAE implements JDBCAttributeExtractor {
         */
        public BasicAttributes extractAttributes(ResultSet rs) throws JDBCAttributeExtractorException {
                BasicAttributes attributes = new BasicAttributes();
-
+        int row = 0;
+        
                try {
-                       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));
-                       }
+            // Get metadata about result set.
+            ResultSetMetaData rsmd = rs.getMetaData();
+            int numColumns = rsmd.getColumnCount();
+            log.debug("Number of returned columns: " + numColumns);
+
+            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 retrieving result set meta data");
+                       log.error("An ERROR occured while processing result set");
                        throw new JDBCAttributeExtractorException(
-                               "An ERROR occured while retrieving result set meta data: " + e.getMessage());
-               }
-
-               // Check for multiple rows.
-               try {
-                       if (rs.next())
-                               throw new JDBCAttributeExtractorException("Query returned more than one row.");
-               } catch (SQLException e) {
-                       //TODO don't squelch this error!!!
+                               "An ERROR occured while processing result set: " + e.getMessage());
                }
 
                return attributes;
@@ -526,6 +578,15 @@ class DefaultStatementCreator implements JDBCStatementCreator {
                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("Encountered an error while creating prepared statement: " + e);
                        throw new JDBCStatementCreatorException(
@@ -534,7 +595,516 @@ class DefaultStatementCreator implements JDBCStatementCreator {
        }
 }
 
+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;
+            }
+        }
+
+               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.");
+               }
+       }
+}