Clear statement parameters before new call.
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / aa / attrresolv / provider / JDBCDataConnector.java
index 5b8b6a2..928a721 100644 (file)
@@ -84,23 +84,18 @@ import edu.internet2.middleware.shibboleth.aa.attrresolv.ResolverAttribute;
  * @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;
        protected DataSource dataSource;
        protected JDBCAttributeExtractor extractor;
        protected JDBCStatementCreator statementCreator;
-    protected String failover = null;
 
        public JDBCDataConnector(Element e) throws ResolutionPlugInException {
 
                super(e);
 
-        NodeList failoverNodes = e.getElementsByTagNameNS(AttributeResolver.resolverNamespace, "FailoverDependency");
-        if (failoverNodes.getLength() > 0) {
-            failover = ((Element)failoverNodes.item(0)).getAttribute("requires");
-        }
                //Get the query string
                NodeList queryNodes = e.getElementsByTagNameNS(AttributeResolver.resolverNamespace, "Query");
                Node tnode = queryNodes.item(0).getFirstChild();
@@ -118,6 +113,11 @@ public class JDBCDataConnector extends BaseResolutionPlugIn implements DataConne
                        loadDriver(dbDriverName);
                }
 
+               String validationQuery = e.getAttribute("validationQuery");
+               if (validationQuery == null || validationQuery.equals("")) {
+                       validationQuery = "select 1";
+               }
+
                //Load site-specific implementation classes     
                setupAttributeExtractor(
                        (Element) e.getElementsByTagNameNS(AttributeResolver.resolverNamespace, "AttributeExtractor").item(
@@ -149,6 +149,7 @@ public class JDBCDataConnector extends BaseResolutionPlugIn implements DataConne
                //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"));
@@ -156,6 +157,9 @@ public class JDBCDataConnector extends BaseResolutionPlugIn implements DataConne
                        if (e.getAttributeNode("maxIdle") != null) {
                                maxIdle = Integer.parseInt(e.getAttribute("maxIdle"));
                        }
+            if (e.getAttributeNode("maxWait") != null) {
+                maxWait = Integer.parseInt(e.getAttribute("maxWait"));
+            }
                } catch (NumberFormatException ex) {
                        log.error("Malformed pooling limits: using defaults.");
                }
@@ -163,13 +167,13 @@ public class JDBCDataConnector extends BaseResolutionPlugIn implements DataConne
                        log.error("JDBC connection requires a dbURL property");
                        throw new ResolutionPlugInException("JDBCDataConnection requires a \"dbURL\" property");
                }
-               setupDataSource(e.getAttribute("dbURL"), props, maxActive, maxIdle);
+               setupDataSource(e.getAttribute("dbURL"), props, maxActive, maxIdle, maxWait, validationQuery);
        }
 
        /**
         * Initialize a Pooling Data Source
         */
-       private void setupDataSource(String dbURL, Properties props, 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);
 
@@ -179,8 +183,12 @@ 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;
@@ -200,9 +208,9 @@ public class JDBCDataConnector extends BaseResolutionPlugIn implements DataConne
                                connFactory,
                                objectPool,
                                new StackKeyedObjectPoolFactory(),
-                               null,
-                               false,
-                                       true);
+                               validationQuery,
+                               true,
+                                       false);
                } catch (Exception ex) {
                        log.debug("Poolable connection factory error");
                }
@@ -299,7 +307,7 @@ 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) {
@@ -309,53 +317,53 @@ public class JDBCDataConnector extends BaseResolutionPlugIn implements DataConne
 
                //Setup and execute a (pooled) prepared statement
                ResultSet rs = null;
-               PreparedStatement preparedStatement;
+               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());
                } 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 {
-                               if (preparedStatement != null) {
-                                       preparedStatement.close();
-                               }
-                       } catch (SQLException e) {
-                               log.error("An error occured while closing the prepared statement: " + e);
-                               throw new ResolutionPlugInException("An error occured while closing the prepared statement: " + e);
-                       }
-                       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());
+            }
+        }
        }
 
        /** 
@@ -375,13 +383,6 @@ public class JDBCDataConnector extends BaseResolutionPlugIn implements DataConne
                log.debug("Driver loaded.");
        }
 
-    /**
-     * @see edu.internet2.middleware.shibboleth.aa.attrresolv.DataConnectorPlugIn#getFailoverDependencyId()
-     */
-    public String getFailoverDependencyId() {
-        return failover;
-    }
-
        private class Log4jPrintWriter extends PrintWriter {
 
                private Priority level;
@@ -649,8 +650,8 @@ class DependencyStatementCreator implements JDBCStatementCreator {
                        }
 
                } catch (Exception e) {
-                       log.error("Encountered an error while creating prepared statement: " + e);
-                       throw new JDBCStatementCreatorException(
+                       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());
                }
        }