Moved to use of prepared statements for JDBC connector.
authorwassa <wassa@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Tue, 19 Aug 2003 23:10:08 +0000 (23:10 +0000)
committerwassa <wassa@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Tue, 19 Aug 2003 23:10:08 +0000 (23:10 +0000)
Added caching of prepared statements.
Changed configuration schema.
Added interface for populating prepared statement parameters.

git-svn-id: https://subversion.switch.ch/svn/shibboleth/java-idp/trunk@731 ab3bd59b-922f-494d-bb5f-6f0a3c29deca

src/edu/internet2/middleware/shibboleth/aa/attrresolv/provider/JDBCDataConnector.java
src/edu/internet2/middleware/shibboleth/aa/attrresolv/provider/JDBCStatementCreator.java [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/aa/attrresolv/provider/JDBCStatementCreatorException.java [new file with mode: 0644]
src/schemas/shibboleth-resolver-1.0.xsd

index 7cf139e..d88c285 100644 (file)
@@ -29,18 +29,11 @@ import java.io.PrintWriter;
 import java.lang.reflect.Constructor;
 import java.security.Principal;
 import java.sql.Connection;
+import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.ResultSetMetaData;
 import java.sql.SQLException;
-import java.sql.Statement;
-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;
@@ -50,8 +43,8 @@ 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.ObjectPool;
 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;
@@ -62,7 +55,6 @@ 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 
@@ -78,108 +70,87 @@ 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 {
 
        private static Logger log = Logger.getLogger(JDBCDataConnector.class.getName());
-       protected Properties props = new Properties();
        protected String searchVal;
        protected DataSource dataSource;
        protected JDBCAttributeExtractor extractor;
+       protected JDBCStatementCreator statementCreator;
 
        public JDBCDataConnector(Element element) throws ResolutionPlugInException {
 
                super(element);
 
                //Get the query string
-               NodeList searchNode = element.getElementsByTagNameNS(AttributeResolver.resolverNamespace, "Search");
-               searchVal = ((Element) searchNode.item(0)).getAttribute("query");
-
+               NodeList queryNodes = element.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("")) {
-                       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");
-                               //TODO stinky error message
-                               throw new ResolutionPlugInException("mySQLDataConnection requires a \"Search\" specification");
-                       }
-               } else {
-                       log.debug("Search Query: (" + searchVal + ")");
+                       log.error("Database query must be specified.");
+                       throw new ResolutionPlugInException("Database query must be specified.");
                }
 
-               //Instantiate an attribute extractor, using the default if none is specified
-               String aeClassName = ((Element) searchNode.item(0)).getAttribute("attributeExtractor");
-               if (aeClassName == null || aeClassName.equals("")) {
-                       aeClassName = DefaultAE.class.getName();
+               //Load the supplied JDBC driver
+               String dbDriverName = element.getAttribute("dbDriver");
+               if (dbDriverName != null && (!dbDriverName.equals(""))) {
+                       loadDriver(dbDriverName);
                }
-               try {
-                       Class aeClass = Class.forName(aeClassName);
-                       Constructor constructor = aeClass.getConstructor(null);
-                       extractor = (JDBCAttributeExtractor) constructor.newInstance(null);
-                       log.debug("Supplied attributeExtractor class 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());
-               }
+               //Load site-specific implementation classes     
+               setupAttributeExtractor(
+                       (Element) element.getElementsByTagNameNS(AttributeResolver.resolverNamespace, "AttributeExtractor").item(
+                               0));
+               setupStatementCreator(
+                       (Element) element.getElementsByTagNameNS(AttributeResolver.resolverNamespace, "StatementCreator").item(0));
 
-               //Grab all other properties
-               NodeList propertiesNode = element.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;
+               try {
+                       if (element.getAttribute("maxActive") != null) {
+                               maxActive = Integer.parseInt(element.getAttribute("maxActive"));
+                       }
+                       if (element.getAttribute("maxIdle") != null) {
+                               maxIdle = Integer.parseInt(element.getAttribute("maxIdle"));
                        }
+               } catch (NumberFormatException e) {
+                       log.error("Malformed pooling limits: using defaults.");
                }
-
-               if (props.getProperty("dbURL") == null) {
+               if (element.getAttribute("dbURL") == null || element.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);
+       }
 
-               //Load the supplied JDBC driver
-               loadDriver((String) props.get("dbDriver"));
-               
-               //Setup the Pool
-               GenericObjectPool genericObjectPool = new GenericObjectPool(null);
+       /**
+        * Initialize a Pooling Data Source
+        */
+       private void setupDataSource(String dbURL, int maxActive, int maxIdle) throws ResolutionPlugInException {
 
-               try {
-                       if (props.getProperty("maxActiveConnections") != null) {
-                               genericObjectPool.setMaxActive(Integer.parseInt(props.getProperty("maxActiveConnections")));
-                       }
-                       if (props.getProperty("maxIdleConnections") != null) {
-                               genericObjectPool.setMaxIdle(Integer.parseInt(props.getProperty("maxIdleConnections")));
-                       }
-               } catch (NumberFormatException e) {
-                       log.error("Malformed pooling configuration settings: using defaults.");
+               GenericObjectPool objectPool = new GenericObjectPool(null);
+
+               if (maxActive > 0) {
+                       objectPool.setMaxActive(maxActive);
                }
-               genericObjectPool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK);
+               if (maxIdle > 0) {
+                       objectPool.setMaxIdle(maxIdle);
+               }
+
+               objectPool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK);
 
-               ObjectPool connPool = genericObjectPool;
                ConnectionFactory connFactory = null;
                PoolableConnectionFactory poolConnFactory = null;
 
                try {
-                       connFactory = new DriverManagerConnectionFactory(props.getProperty("dbURL"), null);
+                       connFactory = new DriverManagerConnectionFactory(dbURL, null);
                        log.debug("Connection factory initialized.");
                } catch (Exception ex) {
                        log.error(
@@ -188,12 +159,21 @@ public class JDBCDataConnector extends BaseResolutionPlugIn implements DataConne
                }
 
                try {
-                       poolConnFactory = new PoolableConnectionFactory(connFactory, connPool, null, null, false, true);
+                       new StackKeyedObjectPoolFactory();
+                       poolConnFactory =
+                               new PoolableConnectionFactory(
+                                       connFactory,
+                                       objectPool,
+                                       new StackKeyedObjectPoolFactory(),
+                                       null,
+                                       false,
+                                       true);
                } catch (Exception ex) {
                        log.debug("Poolable connection factory error");
                }
 
-               dataSource = new PoolingDataSource(connPool);
+               dataSource = new PoolingDataSource(objectPool);
+               log.info("Data Source initialized.");
                try {
                        dataSource.setLogWriter(
                                new Log4jPrintWriter(Logger.getLogger(JDBCDataConnector.class.getName() + ".Pool"), Priority.DEBUG));
@@ -202,90 +182,84 @@ public class JDBCDataConnector extends BaseResolutionPlugIn implements DataConne
                }
        }
 
-       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);
-                       }
+       /**
+        * 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());
                }
-               return source;
        }
 
-       public Attributes resolve(Principal principal, String requester, Dependencies depends)
-               throws ResolutionPlugInException {
+       /**
+        * Instantiate a Statement Creator, using the default if none was configured
+        */
+       private void setupStatementCreator(Element config) throws ResolutionPlugInException {
 
-               log.debug("Resolving connector: (" + getId() + ")");
-               log.debug(getId() + " resolving for principal: (" + principal.getName() + ")");
-               log.debug("The query string before inserting substitutions: " + searchVal);
+               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);
 
-               //Replaces %PRINCIPAL% in the query string with its value
-               String convertedSearchVal = searchVal.replaceAll("%PRINCIPAL%", principal.getName());
-               convertedSearchVal = convertedSearchVal.replaceAll("@PRINCIPAL@", "'" + principal.getName() + "'");
+                       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();
+                       }
 
-               //Find all delimited substitutions and replace with the named attribute value(s).
-               convertedSearchVal = substitute(convertedSearchVal, "%.+%", false, depends);
-               convertedSearchVal = substitute(convertedSearchVal, "@.+@", true, depends);
+                       log.debug("Statement Creator implementation loaded.");
 
-               //Replace any escaped substitution delimiters.
-               convertedSearchVal = convertedSearchVal.replaceAll("\\%", "%");
-               convertedSearchVal = convertedSearchVal.replaceAll("\\@", "@");
+               } 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());
+               }
+       }
 
-               log.debug("The query string after inserting substitutions: " + convertedSearchVal);
+       public Attributes resolve(Principal principal, String requester, Dependencies depends)
+               throws ResolutionPlugInException {
 
-               /**
-                * Retrieves a connection from the connection pool
-                */
+               log.debug("Resolving connector: (" + getId() + ")");
+
+               //Retrieve a connection from the connection pool
                Connection conn = null;
                try {
                        conn = dataSource.getConnection();
@@ -299,18 +273,27 @@ public class JDBCDataConnector extends BaseResolutionPlugIn implements DataConne
                        throw new ResolutionPlugInException("Pool didn't return a propertly initialized connection.");
                }
 
+               //Setup and execute a (pooled) prepared statement
                ResultSet rs = null;
                try {
-                       //Gets the results set for the query
-                       rs = executeQuery(conn, convertedSearchVal);
-                       if (!rs.next())
+                       PreparedStatement preparedStatement = conn.prepareStatement(searchVal);
+                       statementCreator.create(preparedStatement, principal, requester, depends);
+                       rs = preparedStatement.executeQuery();
+                       preparedStatement.close();
+
+                       if (!rs.next()) {
                                return new BasicAttributes();
+                       }
 
+               } 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 (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);
 
@@ -352,19 +335,6 @@ public class JDBCDataConnector extends BaseResolutionPlugIn implements DataConne
                log.debug("Driver loaded.");
        }
 
-       /**
-        * 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);
-       }
-
        private class Log4jPrintWriter extends PrintWriter {
 
                private Priority level;
@@ -486,7 +456,6 @@ public class JDBCDataConnector extends BaseResolutionPlugIn implements DataConne
                }
        }
 }
-
 /**
  * The default attribute extractor. 
  */
@@ -495,10 +464,6 @@ class DefaultAE implements JDBCAttributeExtractor {
 
        private static Logger log = Logger.getLogger(DefaultAE.class.getName());
 
-       // Constructor
-       public DefaultAE() {
-       }
-
        /**
         * Method of extracting the attributes from the supplied result set.
         *
@@ -509,8 +474,6 @@ class DefaultAE implements JDBCAttributeExtractor {
        public BasicAttributes extractAttributes(ResultSet rs) throws JDBCAttributeExtractorException {
                BasicAttributes attributes = new BasicAttributes();
 
-               log.debug("Using default Attribute Extractor");
-
                try {
                        ResultSetMetaData rsmd = rs.getMetaData();
                        int numColumns = rsmd.getColumnCount();
@@ -548,3 +511,30 @@ class DefaultAE implements JDBCAttributeExtractor {
                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());
+               } 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());
+               }
+       }
+}
+
+
+
+
+
diff --git a/src/edu/internet2/middleware/shibboleth/aa/attrresolv/provider/JDBCStatementCreator.java b/src/edu/internet2/middleware/shibboleth/aa/attrresolv/provider/JDBCStatementCreator.java
new file mode 100644 (file)
index 0000000..16f59bc
--- /dev/null
@@ -0,0 +1,67 @@
+/* 
+ * The Shibboleth License, Version 1. 
+ * Copyright (c) 2002 
+ * University Corporation for Advanced Internet Development, Inc. 
+ * All rights reserved
+ * 
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ * Redistributions of source code must retain the above copyright notice, this 
+ * list of conditions and the following disclaimer.
+ * 
+ * Redistributions in binary form must reproduce the above copyright notice, 
+ * this list of conditions and the following disclaimer in the documentation 
+ * and/or other materials provided with the distribution, if any, must include 
+ * the following acknowledgment: "This product includes software developed by 
+ * the University Corporation for Advanced Internet Development 
+ * <http://www.ucaid.edu>Internet2 Project. Alternately, this acknowledegement 
+ * may appear in the software itself, if and wherever such third-party 
+ * acknowledgments normally appear.
+ * 
+ * Neither the name of Shibboleth nor the names of its contributors, nor 
+ * Internet2, nor the University Corporation for Advanced Internet Development, 
+ * Inc., nor UCAID may be used to endorse or promote products derived from this 
+ * software without specific prior written permission. For written permission, 
+ * please contact shibboleth@shibboleth.org
+ * 
+ * Products derived from this software may not be called Shibboleth, Internet2, 
+ * UCAID, or the University Corporation for Advanced Internet Development, nor 
+ * may Shibboleth appear in their name, without prior written permission of the 
+ * University Corporation for Advanced Internet Development.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
+ * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK 
+ * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE. 
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY 
+ * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT, 
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package edu.internet2.middleware.shibboleth.aa.attrresolv.provider;
+
+import java.security.Principal;
+import java.sql.PreparedStatement;
+
+import edu.internet2.middleware.shibboleth.aa.attrresolv.Dependencies;
+
+/**
+ * Definition for the JDBC Statement Creator.  Implementations are responsible for 
+ * setting all parameters on the specified prepared statement.
+ * 
+ * @author Walter Hoehn (wassa@columbia.edu)
+ */
+public interface JDBCStatementCreator {
+
+       void create(PreparedStatement preparedStatement, Principal principal, String requester, Dependencies depends) throws JDBCStatementCreatorException;
+
+}
diff --git a/src/edu/internet2/middleware/shibboleth/aa/attrresolv/provider/JDBCStatementCreatorException.java b/src/edu/internet2/middleware/shibboleth/aa/attrresolv/provider/JDBCStatementCreatorException.java
new file mode 100644 (file)
index 0000000..2554216
--- /dev/null
@@ -0,0 +1,67 @@
+/* 
+ * The Shibboleth License, Version 1. 
+ * Copyright (c) 2002 
+ * University Corporation for Advanced Internet Development, Inc. 
+ * All rights reserved
+ * 
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ * Redistributions of source code must retain the above copyright notice, this 
+ * list of conditions and the following disclaimer.
+ * 
+ * Redistributions in binary form must reproduce the above copyright notice, 
+ * this list of conditions and the following disclaimer in the documentation 
+ * and/or other materials provided with the distribution, if any, must include 
+ * the following acknowledgment: "This product includes software developed by 
+ * the University Corporation for Advanced Internet Development 
+ * <http://www.ucaid.edu>Internet2 Project. Alternately, this acknowledegement 
+ * may appear in the software itself, if and wherever such third-party 
+ * acknowledgments normally appear.
+ * 
+ * Neither the name of Shibboleth nor the names of its contributors, nor 
+ * Internet2, nor the University Corporation for Advanced Internet Development, 
+ * Inc., nor UCAID may be used to endorse or promote products derived from this 
+ * software without specific prior written permission. For written permission, 
+ * please contact shibboleth@shibboleth.org
+ * 
+ * Products derived from this software may not be called Shibboleth, Internet2, 
+ * UCAID, or the University Corporation for Advanced Internet Development, nor 
+ * may Shibboleth appear in their name, without prior written permission of the 
+ * University Corporation for Advanced Internet Development.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
+ * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK 
+ * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE. 
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY 
+ * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT, 
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package edu.internet2.middleware.shibboleth.aa.attrresolv.provider;
+
+/**
+ * Exception thrown by implementations of <code>JDBCStatementCreator</code> to signal that an error
+ * occurred while creating a prepared statement.
+ * 
+ * @author Walter Hoehn (wassa@columbia.edu)
+ */
+public class JDBCStatementCreatorException extends Exception {
+
+       public JDBCStatementCreatorException() {
+               super();
+       }
+
+       public JDBCStatementCreatorException(String s) {
+               super(s);
+       }
+}
index 10d4477..047d41f 100644 (file)
                                                <xs:complexContent>
                                                        <xs:extension base="resolver:BaseResolutionPlugIn">
                                                                <xs:sequence>
-                                                                       <xs:element name="Search">
+                                                                       <xs:element name="Query">
                                                                                <xs:complexType>
                                                                                        <xs:simpleContent>
-                                                                                               <xs:extension base="xs:string">
-                                                                                                       <xs:attribute name="query" type="xs:string" use="optional"/>
-                                                                                                       <xs:attribute name="attributeExtractor" type="xs:string" use="optional"/>
-                                                                                               </xs:extension>
+                                                                                               <xs:extension base="xs:string"/>
                                                                                        </xs:simpleContent>
                                                                                </xs:complexType>
                                                                        </xs:element>
-                                                                       <xs:sequence>
-                                                                               <xs:element name="Property" maxOccurs="unbounded">
-                                                                                       <xs:complexType>
-                                                                                               <xs:attribute name="name" type="xs:string" use="required"/>
-                                                                                               <xs:attribute name="value" type="xs:string" use="required"/>
-                                                                                       </xs:complexType>
-                                                                               </xs:element>
-                                                                       </xs:sequence>
+                                                                       <xs:element name="AttributeExtractor" minOccurs="0">
+                                                                               <xs:complexType>
+                                                                                       <xs:attribute name="class" type="xs:string" use="required"/>
+                                                                               </xs:complexType>
+                                                                       </xs:element>
+                                                                       <xs:element name="StatementCreator" minOccurs="0">
+                                                                               <xs:complexType>
+                                                                                       <xs:sequence minOccurs="0" maxOccurs="unbounded">
+                                                                                               <xs:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+                                                                                       </xs:sequence>
+                                                                                       <xs:attribute name="class" type="xs:string" use="required"/>
+                                                                                       <xs:anyAttribute namespace="##any" processContents="lax"/>
+                                                                               </xs:complexType>
+                                                                       </xs:element>
                                                                </xs:sequence>
+                                                               <xs:attribute name="dbURL" type="xs:string" use="required"/>
+                                                               <xs:attribute name="dbDriver" type="xs:string" use="optional"/>
+                                                               <xs:attribute name="maxActive" type="xs:integer" use="optional"/>
+                                                               <xs:attribute name="maxIdle" type="xs:integer" use="optional"/>
                                                        </xs:extension>
                                                </xs:complexContent>
                                        </xs:complexType>