2 * Copyright [2005] [University Corporation for Advanced Internet Development, Inc.]
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package edu.internet2.middleware.shibboleth.aa.attrresolv.provider;
19 import java.io.PrintWriter;
20 import java.lang.reflect.Constructor;
21 import java.security.Principal;
24 import java.sql.Connection;
25 import java.sql.PreparedStatement;
26 import java.sql.ResultSet;
27 import java.sql.ResultSetMetaData;
28 import java.sql.SQLException;
29 import java.sql.Types;
30 import java.text.SimpleDateFormat;
31 import java.util.ArrayList;
32 import java.util.Iterator;
33 import java.util.Properties;
35 import javax.naming.NamingException;
36 import javax.naming.directory.Attribute;
37 import javax.naming.directory.Attributes;
38 import javax.naming.directory.BasicAttribute;
39 import javax.naming.directory.BasicAttributes;
40 import javax.sql.DataSource;
42 import org.apache.commons.dbcp.ConnectionFactory;
43 import org.apache.commons.dbcp.DriverManagerConnectionFactory;
44 import org.apache.commons.dbcp.PoolableConnectionFactory;
45 import org.apache.commons.dbcp.PoolingDataSource;
46 import org.apache.commons.pool.impl.GenericObjectPool;
47 import org.apache.commons.pool.impl.StackKeyedObjectPoolFactory;
48 import org.apache.log4j.Logger;
49 import org.apache.log4j.Priority;
50 import org.w3c.dom.Element;
51 import org.w3c.dom.Node;
52 import org.w3c.dom.NodeList;
54 import edu.internet2.middleware.shibboleth.aa.attrresolv.AttributeResolver;
55 import edu.internet2.middleware.shibboleth.aa.attrresolv.DataConnectorPlugIn;
56 import edu.internet2.middleware.shibboleth.aa.attrresolv.Dependencies;
57 import edu.internet2.middleware.shibboleth.aa.attrresolv.ResolutionPlugInException;
58 import edu.internet2.middleware.shibboleth.aa.attrresolv.ResolverAttribute;
61 * Built at the Canada Institute for Scientific and Technical Information (CISTI
62 * <ahref="http://www.cisti-icist.nrc-cnrc.gc.ca/">http://www.cisti-icist.nrc-cnrc.gc.ca/ </a>, the National Research
63 * Council Canada (NRC <a href="http://www.nrc-cnrc.gc.ca/">http://www.nrc-cnrc.gc.ca/ </a>) by David Dearman, COOP
64 * student from Dalhousie University, under the direction of Glen Newton, Head research (IT)
65 * <ahref="mailto:glen.newton@nrc-cnrc.gc.ca">glen.newton@nrc-cnrc.gc.ca </a>.
69 * Data Connector that uses JDBC to access user attributes stored in databases.
71 * @author David Dearman (dearman@cs.dal.ca)
72 * @author Walter Hoehn (wassa@columbia.edu)
73 * @author Scott Cantor
76 public class JDBCDataConnector extends BaseDataConnector implements DataConnectorPlugIn {
78 private static Logger log = Logger.getLogger(JDBCDataConnector.class.getName());
79 protected String searchVal;
80 protected int minResultSet = 0, maxResultSet = 0, retryInterval = 300;
81 protected long deadSince = 0;
82 protected DataSource dataSource;
83 protected JDBCAttributeExtractor extractor;
84 protected JDBCStatementCreator statementCreator;
86 public JDBCDataConnector(Element e) throws ResolutionPlugInException {
90 // Get the query string
91 NodeList queryNodes = e.getElementsByTagNameNS(AttributeResolver.resolverNamespace, "Query");
92 Node tnode = queryNodes.item(0).getFirstChild();
93 if (tnode != null && tnode.getNodeType() == Node.TEXT_NODE) {
94 searchVal = tnode.getNodeValue();
96 if (searchVal == null || searchVal.equals("")) {
97 log.error("Database query must be specified.");
98 throw new ResolutionPlugInException("Database query must be specified.");
101 // Load the supplied JDBC driver
102 String dbDriverName = e.getAttribute("dbDriver");
103 if (dbDriverName != null && (!dbDriverName.equals(""))) {
104 loadDriver(dbDriverName);
107 String validationQuery = e.getAttribute("validationQuery");
108 if (validationQuery == null || validationQuery.equals("")) {
109 validationQuery = "select 1";
113 if (e.getAttributeNode("minResultSet") != null) {
114 minResultSet = Integer.parseInt(e.getAttribute("minResultSet"));
116 if (e.getAttributeNode("maxResultSet") != null) {
117 maxResultSet = Integer.parseInt(e.getAttribute("maxResultSet"));
119 if (e.getAttributeNode("retryInterval") != null) {
120 retryInterval = Integer.parseInt(e.getAttribute("retryInterval"));
122 } catch (NumberFormatException ex) {
123 log.error("Malformed result set and retry limits: using defaults.");
126 // Load site-specific implementation classes
127 setupAttributeExtractor((Element) e.getElementsByTagNameNS(AttributeResolver.resolverNamespace,
128 "AttributeExtractor").item(0));
129 setupStatementCreator((Element) e.getElementsByTagNameNS(AttributeResolver.resolverNamespace,
130 "StatementCreator").item(0));
132 // Load driver properties
133 Properties props = new Properties();
134 NodeList propertiesNode = e.getElementsByTagNameNS(AttributeResolver.resolverNamespace, "Property");
135 for (int i = 0; propertiesNode.getLength() > i; i++) {
136 Element property = (Element) propertiesNode.item(i);
137 String propertiesName = property.getAttribute("name");
138 String propertiesValue = property.getAttribute("value");
140 if (propertiesName != null && !propertiesName.equals("") && propertiesValue != null
141 && !propertiesValue.equals("")) {
142 props.setProperty(propertiesName, propertiesValue);
143 log.debug("Property: (" + propertiesName + ")");
144 log.debug(" Value: (" + propertiesValue + ")");
146 log.error("Property is malformed.");
147 throw new ResolutionPlugInException("Property is malformed.");
151 // Initialize a pooling Data Source
156 if (e.getAttributeNode("maxActive") != null) {
157 maxActive = Integer.parseInt(e.getAttribute("maxActive"));
159 if (e.getAttributeNode("maxIdle") != null) {
160 maxIdle = Integer.parseInt(e.getAttribute("maxIdle"));
162 if (e.getAttributeNode("maxWait") != null) {
163 maxWait = Integer.parseInt(e.getAttribute("maxWait"));
165 } catch (NumberFormatException ex) {
166 log.error("Malformed pooling limits: using defaults.");
168 if (e.getAttribute("dbURL") == null || e.getAttribute("dbURL").equals("")) {
169 log.error("JDBC connection requires a dbURL property");
170 throw new ResolutionPlugInException("JDBCDataConnection requires a \"dbURL\" property");
172 setupDataSource(e.getAttribute("dbURL"), props, maxActive, maxIdle, maxWait, validationQuery);
176 * Initialize a Pooling Data Source
178 private void setupDataSource(String dbURL, Properties props, int maxActive, int maxIdle, int maxWait,
179 String validationQuery) throws ResolutionPlugInException {
181 GenericObjectPool objectPool = new GenericObjectPool(null);
183 objectPool.setMaxActive(maxActive);
184 objectPool.setMaxIdle(maxIdle);
185 if (maxWait > 0) objectPool.setMaxWait(1000 * maxWait);
186 else objectPool.setMaxWait(maxWait);
188 objectPool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK);
189 objectPool.setTestOnBorrow(true);
191 ConnectionFactory connFactory = null;
192 PoolableConnectionFactory poolConnFactory = null;
195 connFactory = new DriverManagerConnectionFactory(dbURL, props);
196 log.debug("Connection factory initialized.");
197 } catch (Exception ex) {
199 .error("Connection factory couldn't be initialized, ensure database URL, username and password are correct.");
200 throw new ResolutionPlugInException("Connection factory couldn't be initialized: " + ex.getMessage());
204 poolConnFactory = new PoolableConnectionFactory(connFactory, objectPool, new StackKeyedObjectPoolFactory(),
205 validationQuery, true, true);
206 } catch (Exception ex) {
207 log.debug("Poolable connection factory error");
210 dataSource = new PoolingDataSource(objectPool);
211 log.info("Data Source initialized.");
213 dataSource.setLogWriter(new Log4jPrintWriter(Logger.getLogger(JDBCDataConnector.class.getName() + ".Pool"),
215 } catch (SQLException e) {
216 log.error("Coudn't setup logger for database connection pool.");
221 * Instantiate an Attribute Extractor, using the default if none was configured
223 private void setupAttributeExtractor(Element config) throws ResolutionPlugInException {
225 String className = null;
226 if (config != null) {
227 className = config.getAttribute("class");
229 if (className == null || className.equals("")) {
230 log.debug("Using default Attribute Extractor.");
231 className = DefaultAE.class.getName();
234 Class aeClass = Class.forName(className);
235 extractor = (JDBCAttributeExtractor) aeClass.newInstance();
236 log.debug("Attribute Extractor implementation loaded.");
238 } catch (ClassNotFoundException e) {
239 log.error("The supplied Attribute Extractor class could not be found: " + e);
240 throw new ResolutionPlugInException("The supplied Attribute Extractor class could not be found: "
242 } catch (Exception e) {
243 log.error("Unable to instantiate Attribute Extractor implementation: " + e);
244 throw new ResolutionPlugInException("Unable to instantiate Attribute Extractor implementation: "
250 * Instantiate a Statement Creator, using the default if none was configured
252 private void setupStatementCreator(Element config) throws ResolutionPlugInException {
254 String scClassName = null;
255 if (config != null) {
256 scClassName = config.getAttribute("class");
258 if (scClassName == null || scClassName.equals("")) {
259 log.debug("Using default Statement Creator.");
260 scClassName = DefaultStatementCreator.class.getName();
263 Class scClass = Class.forName(scClassName);
265 Class[] params = new Class[1];
266 params[0] = Class.forName("org.w3c.dom.Element");
268 Constructor implementorConstructor = scClass.getConstructor(params);
269 Object[] args = new Object[1];
271 log.debug("Initializing Statement Creator of type (" + scClass.getName() + ").");
272 statementCreator = (JDBCStatementCreator) implementorConstructor.newInstance(args);
273 } catch (NoSuchMethodException nsme) {
275 .debug("Implementation constructor does have a parameterized constructor, attempting to load default.");
276 statementCreator = (JDBCStatementCreator) scClass.newInstance();
278 log.debug("Statement Creator implementation loaded.");
280 } catch (ClassNotFoundException e) {
281 log.error("The supplied Statement Creator class could not be found: " + e);
282 throw new ResolutionPlugInException("The supplied Statement Creator class could not be found: "
284 } catch (Exception e) {
285 log.error("Unable to instantiate Statement Creator implementation: " + e);
286 throw new ResolutionPlugInException("Unable to instantiate Statement Creator implementation: "
292 * @see edu.internet2.middleware.shibboleth.aa.attrresolv.DataConnectorPlugIn#resolve(java.security.Principal,
293 * java.lang.String, java.lang.String, edu.internet2.middleware.shibboleth.aa.attrresolv.Dependencies)
295 public Attributes resolve(Principal principal, String requester, String responder, Dependencies depends)
296 throws ResolutionPlugInException {
298 log.debug("Resolving connector: (" + getId() + ")");
301 boolean alive = true;
302 long now = System.currentTimeMillis();
303 synchronized (this) {
304 if (deadSince > 0 && now - deadSince < (1000 * retryInterval)) {
312 log.info("JDBC Connector (" + getId() + ") is dead, returning immediately");
313 throw new ResolutionPlugInException("Connection is dead");
316 // Retrieve a connection from the connection pool
317 Connection conn = null;
319 conn = dataSource.getConnection();
320 log.debug("Connection retrieved from pool");
321 } catch (Exception e) {
322 synchronized (this) {
325 log.error("JDBC Connector (" + getId() + ") unable to fetch a connection from the pool, marking it dead");
326 throw new ResolutionPlugInException("Unable to fetch a connection from the pool, marking it dead: "
330 log.error("Pool didn't return a properly initialized connection.");
331 throw new ResolutionPlugInException("Pool didn't return a properly initialized connection.");
334 // Setup and execute a (pooled) prepared statement
336 PreparedStatement preparedStatement = null;
338 preparedStatement = conn.prepareStatement(searchVal);
339 preparedStatement.clearParameters();
340 statementCreator.create(preparedStatement, principal, requester, responder, depends);
341 rs = preparedStatement.executeQuery();
343 if (minResultSet == 0) return new BasicAttributes();
345 log.error("Statement returned no rows, violating minResultSet of " + minResultSet);
346 throw new ResolutionPlugInException("Statement didn't return any rows, violating minResultSet of "
350 return extractor.extractAttributes(rs, minResultSet, maxResultSet);
351 } catch (JDBCStatementCreatorException e) {
352 log.error("An ERROR occured while constructing the query");
353 throw new ResolutionPlugInException("An ERROR occured while constructing the query: " + e.getMessage());
354 } catch (JDBCAttributeExtractorException e) {
355 log.error("An ERROR occured while extracting attributes from result set");
356 throw new ResolutionPlugInException("An ERROR occured while extracting attributes from result set: "
358 } catch (SQLException e) {
359 synchronized (this) {
362 log.error("An ERROR occured while executing the query, marking connector dead");
363 throw new ResolutionPlugInException("An ERROR occured while executing the query, marking connector dead: "
366 Exception e_save = null;
368 if (preparedStatement != null) {
369 preparedStatement.close();
371 } catch (SQLException e) {
372 log.error("An error occured while closing the prepared statement: " + e.getMessage());
379 } catch (SQLException e) {
380 log.error("An error occured while closing the result set: " + e.getMessage());
385 } catch (SQLException e) {
386 log.error("An error occured while closing the database connection: " + e.getMessage());
389 if (e_save != null) { throw new ResolutionPlugInException(
390 "An error occured while closing database objects:" + e_save.getMessage()); }
395 * Loads the driver used to access the database
398 * The driver used to access the database
399 * @throws ResolutionPlugInException
400 * If there is a failure to load the driver
402 public void loadDriver(String driver) throws ResolutionPlugInException {
405 Class.forName(driver).newInstance();
406 log.debug("Loading JDBC driver: " + driver);
407 } catch (Exception e) {
408 log.error("An error loading database driver: " + e);
409 throw new ResolutionPlugInException("An IllegalAccessException occured while loading database driver: "
412 log.debug("Driver loaded.");
415 private class Log4jPrintWriter extends PrintWriter {
417 private Priority level;
418 private Logger logger;
419 private StringBuffer text = new StringBuffer("");
421 private Log4jPrintWriter(Logger logger, org.apache.log4j.Priority level) {
425 this.logger = logger;
428 public void close() {
433 public void flush() {
435 if (!text.toString().equals("")) {
436 logger.log(level, text.toString());
441 public void print(boolean b) {
446 public void print(char c) {
451 public void print(char[] s) {
456 public void print(double d) {
461 public void print(float f) {
466 public void print(int i) {
471 public void print(long l) {
476 public void print(Object obj) {
481 public void print(String s) {
486 public void println() {
488 if (!text.toString().equals("")) {
489 logger.log(level, text.toString());
494 public void println(boolean x) {
497 logger.log(level, text.toString());
501 public void println(char x) {
504 logger.log(level, text.toString());
508 public void println(char[] x) {
511 logger.log(level, text.toString());
515 public void println(double x) {
518 logger.log(level, text.toString());
522 public void println(float x) {
525 logger.log(level, text.toString());
529 public void println(int x) {
532 logger.log(level, text.toString());
536 public void println(long x) {
539 logger.log(level, text.toString());
543 public void println(Object x) {
546 logger.log(level, text.toString());
550 public void println(String x) {
553 logger.log(level, text.toString());
560 * The default attribute extractor.
563 class DefaultAE implements JDBCAttributeExtractor {
565 private static Logger log = Logger.getLogger(DefaultAE.class.getName());
567 public Attributes extractAttributes(ResultSet rs, int minResultSet, int maxResultSet)
568 throws JDBCAttributeExtractorException {
570 BasicAttributes attributes = new BasicAttributes(true);
574 // Get metadata about result set.
575 ResultSetMetaData rsmd = rs.getMetaData();
576 int numColumns = rsmd.getColumnCount();
577 log.debug("Number of returned columns: " + numColumns);
580 if (maxResultSet > 0 && row + 1 > maxResultSet) {
581 log.error("Statement returned too many rows, violating maxResultSet of " + maxResultSet);
582 throw new JDBCAttributeExtractorException(
583 "Statement returned too many rows, violating maxResultSet of " + maxResultSet);
586 for (int i = 1; i <= numColumns; i++) {
587 String columnName = rsmd.getColumnName(i);
588 Object columnValue = rs.getObject(columnName);
589 if (log.isDebugEnabled()) {
590 log.debug("(" + i + ". ColumnType = " + rsmd.getColumnTypeName(i) + ") " + columnName + " -> "
591 + (columnValue != null ? columnValue.toString() : "(null)"));
594 BasicAttribute ba = new BasicAttribute(columnName, true);
595 ba.add(row, columnValue);
598 attributes.get(columnName).add(row, columnValue);
603 } catch (SQLException e) {
604 log.error("An ERROR occured while processing result set");
605 throw new JDBCAttributeExtractorException("An ERROR occured while processing result set: " + e.getMessage());
608 if (row < minResultSet) {
609 log.error("Statement returned " + row + " rows, violating minResultSet of " + minResultSet);
610 throw new JDBCAttributeExtractorException("Statement returned " + row + " rows, violating minResultSet of "
617 class DefaultStatementCreator implements JDBCStatementCreator {
619 private static Logger log = Logger.getLogger(DefaultStatementCreator.class.getName());
620 private int numberOfParams = 1;
622 public DefaultStatementCreator(Element conf) throws JDBCStatementCreatorException {
624 if (conf != null && conf.getAttribute("numberOfParams") != null
625 && !(conf.getAttribute("numberOfParams").equals(""))) {
627 numberOfParams = Integer.parseInt(conf.getAttribute("numberOfParams"));
628 if (numberOfParams < 0) { throw new NumberFormatException(
629 "The number of parameters cannot be less than 0."); }
630 } catch (NumberFormatException nfe) {
631 log.error("Statement Creator () attribute must be a positive integer: " + nfe);
632 throw new JDBCStatementCreatorException("Statement Creator () attribute must be a positive integer.");
636 log.debug("Parameters configured: " + numberOfParams);
639 public void create(PreparedStatement preparedStatement, Principal principal, String requester, String responder,
640 Dependencies depends) throws JDBCStatementCreatorException {
642 log.debug("Creating prepared statement. Substituting principal: (" + principal.getName() + ")");
643 // Tried using ParameterMetaData to determine param count, but it fails, so...
645 for (int i = 1; i <= numberOfParams; i++) {
646 preparedStatement.setString(i++, principal.getName());
648 } catch (SQLException e) {
649 // Ignore any additional exceptions, assume parameters simply don't exist.
654 class DependencyStatementCreator implements JDBCStatementCreator {
656 private static Logger log = Logger.getLogger(DependencyStatementCreator.class.getName());
657 private ArrayList parameters = new ArrayList();
659 public DependencyStatementCreator(Element conf) throws JDBCStatementCreatorException {
661 NodeList nodes = conf.getElementsByTagName("Parameter");
662 for (int i = 0; i < nodes.getLength(); i++) {
663 Element parameter = (Element) nodes.item(i);
664 String type = "String";
665 if (parameter.getAttribute("type") != null && (!parameter.getAttribute("type").equals(""))) {
666 type = parameter.getAttribute("type");
669 if (parameter.getAttribute("attributeName") == null || parameter.getAttribute("attributeName").equals("")) {
670 log.error("Statement Creator Parameter must reference an attribute by name.");
671 throw new JDBCStatementCreatorException(
672 "Statement Creator Parameter must reference an attribute by name.");
675 if (parameter.getAttribute("connectorId") != null && (!parameter.getAttribute("connectorId").equals(""))) {
676 parameters.add(new Parameter(type, parameter.getAttribute("attributeName"), parameter
677 .getAttribute("connectorId")));
679 parameters.add(new Parameter(type, parameter.getAttribute("attributeName")));
683 if (parameter.getAttribute("nullMissing") != null && (!parameter.getAttribute("nullMissing").equals(""))) {
684 if (parameter.getAttribute("nullMissing").equalsIgnoreCase("FALSE")) {
685 ((Parameter) parameters.get(i)).setNullMissing(false);
689 log.debug("Parameters configured: " + parameters.size());
692 public void create(PreparedStatement preparedStatement, Principal principal, String requester, String responder,
693 Dependencies depends) throws JDBCStatementCreatorException {
696 log.debug("Creating prepared statement. Substituting values from dependencies.");
697 for (int i = 0; i < parameters.size(); i++) {
698 ((Parameter) parameters.get(i)).setParameterValue(preparedStatement, i + 1, depends, principal,
702 } catch (Exception e) {
703 log.error("Encountered an error while creating prepared statement (principal=" + principal.getName()
705 throw new JDBCStatementCreatorException("Encountered an error while creating prepared statement: "
710 protected class Parameter {
713 private String attributeName;
714 private boolean referencesConnector = false;
715 private String connectorId;
716 private boolean nullMissing = true;
718 protected Parameter(String type, String attributeName) throws JDBCStatementCreatorException {
720 if ((!type.equalsIgnoreCase("String")) && (!type.equalsIgnoreCase("Integer"))
721 && (!type.equalsIgnoreCase("Byte")) && (!type.equalsIgnoreCase("Double"))
722 && (!type.equalsIgnoreCase("Float")) && (!type.equalsIgnoreCase("Long"))
723 && (!type.equalsIgnoreCase("Short")) && (!type.equalsIgnoreCase("Boolean"))
724 && (!type.equalsIgnoreCase("Date")) && (!type.equalsIgnoreCase("Blob"))
725 && (!type.equalsIgnoreCase("Clob"))) {
726 log.error("Unsupported type configured for Statement Creator Parameter.");
727 throw new JDBCStatementCreatorException("Unable to load Statement Creator Parameter.");
730 this.attributeName = attributeName;
732 if (attributeName == null) {
733 log.error("No (attributeName) attribute specified for Statement Creator Parameter.");
734 throw new JDBCStatementCreatorException("Unable to load Statement Creator Parameter.");
735 } else if ((attributeName.equals("%PRINCIPAL%") || attributeName.equals("%REQUESTER%"))
736 && !type.equalsIgnoreCase("String")) {
737 log.error("The (type) attribute must be set to \"String\" when \"%PRINCIPAL%\" or \"%REQUESTER%\" is "
738 + "used as the (attributeName) for a Statement Creator Parameter.");
739 throw new JDBCStatementCreatorException("Unable to load Statement Creator Parameter.");
743 protected Parameter(String type, String attributeName, String connectorId) throws JDBCStatementCreatorException {
745 this(type, attributeName);
746 referencesConnector = true;
747 this.connectorId = connectorId;
751 protected int getSQLType() {
753 if (type.equalsIgnoreCase("String")) {
754 return Types.VARCHAR;
755 } else if (type.equalsIgnoreCase("Integer")) {
756 return Types.INTEGER;
757 } else if (type.equalsIgnoreCase("Byte")) {
758 return Types.TINYINT;
759 } else if (type.equalsIgnoreCase("Double")) {
761 } else if (type.equalsIgnoreCase("Float")) {
763 } else if (type.equalsIgnoreCase("Long")) {
764 return Types.INTEGER;
765 } else if (type.equalsIgnoreCase("Short")) {
766 return Types.SMALLINT;
767 } else if (type.equalsIgnoreCase("Boolean")) {
768 return Types.BOOLEAN;
769 } else if (type.equalsIgnoreCase("Date")) {
771 } else if (type.equalsIgnoreCase("Blob")) {
773 } else if (type.equalsIgnoreCase("Clob")) {
776 return Types.VARCHAR;
780 protected void setParameterValue(PreparedStatement preparedStatement, int valueIndex, Dependencies depends,
781 Principal principal, String requester) throws JDBCStatementCreatorException {
783 // handle values from DataConnectors
784 if (referencesConnector) {
785 Attributes attributes = depends.getConnectorResolution(connectorId);
786 if (attributes == null) {
787 log.error("Statement Creator misconfiguration: Connector (" + connectorId
788 + ") is not a dependency of this JDBCDataConnector.");
789 throw new JDBCStatementCreatorException("Statement Creator misconfiguration: Connector ("
790 + connectorId + ") is not a dependency of this JDBCDataConnector.");
793 Attribute attribute = attributes.get(attributeName);
794 if (attribute == null || attribute.size() < 1) {
795 if (attributeName.equalsIgnoreCase("%REQUESTER%")) {
797 setSpecificParameter(preparedStatement, valueIndex, requester);
799 } catch (Exception e) {
800 log.error("Statement Creator encountered an error while adding the parameter 'Requester': "
802 throw new JDBCStatementCreatorException(
803 "Statement Creator encountered an error while parameter 'Requester': "
806 } else if (attributeName.equalsIgnoreCase("%PRINCIPAL%")) {
808 setSpecificParameter(preparedStatement, valueIndex, principal.toString());
810 } catch (Exception e) {
811 log.error("Statement Creator encountered an error while adding the parameter 'Requester': "
813 throw new JDBCStatementCreatorException(
814 "Statement Creator encountered an error while parameter 'Requester': "
817 } else if (nullMissing) {
819 preparedStatement.setNull(valueIndex, getSQLType());
821 } catch (SQLException e) {
823 .error("Encountered a problem while attempting to convert missing attribute value to null parameter.");
826 log.error("Cannot parameterize prepared statement: missing dependency value.");
827 throw new JDBCStatementCreatorException(
828 "Cannot parameterize prepared statement: missing dependency value.");
831 if (attribute.size() > 1) {
832 log.error("Statement Creator encountered a multivalued dependent attribute.");
833 throw new JDBCStatementCreatorException(
834 "Statement Creator encountered a multivalued dependent attribute.");
838 setSpecificParameter(preparedStatement, valueIndex, attribute.get());
840 } catch (NamingException e) {
841 log.error("Statement Creator encountered an error while extracting attributes "
842 + "from a Data Conector: " + e);
843 throw new JDBCStatementCreatorException(
844 "Statement Creator encountered an error while extracting attributes from a Data Conector: "
849 // handle values from AttributeDefinitons
850 ResolverAttribute attribute = depends.getAttributeResolution(attributeName);
851 if (attribute != null) {
852 Iterator iterator = attribute.getValues();
853 if (iterator.hasNext()) {
854 setSpecificParameter(preparedStatement, valueIndex, iterator.next());
855 if (iterator.hasNext()) {
856 log.error("Statement Creator encountered a multivalued dependent attribute.");
857 throw new JDBCStatementCreatorException(
858 "Statement Creator encountered a multivalued dependent attribute.");
865 preparedStatement.setNull(valueIndex, getSQLType());
867 } catch (SQLException e) {
868 log.error("Encountered a problem while attempting to convert missing attribute "
869 + "value to null parameter.");
872 log.error("Cannot parameterize prepared statement: missing dependency value.");
873 throw new JDBCStatementCreatorException("Cannot parameterize prepared statement: missing dependency value.");
876 protected void setNullMissing(boolean nullMissing) {
878 this.nullMissing = nullMissing;
881 private void setSpecificParameter(PreparedStatement preparedStatement, int valueIndex, Object object)
882 throws JDBCStatementCreatorException {
884 if (object == null) {
886 preparedStatement.setNull(valueIndex, getSQLType());
888 } catch (SQLException e) {
890 .error("Encountered a problem while attempting to convert missing attribute value to null parameter.");
891 throw new JDBCStatementCreatorException(
892 "Encountered a problem while attempting to convert missing attribute value to null parameter.");
894 } else if (type.equalsIgnoreCase("String")) {
895 setString(preparedStatement, valueIndex, object);
896 } else if (type.equalsIgnoreCase("Integer")) {
897 setInteger(preparedStatement, valueIndex, object);
898 } else if (type.equalsIgnoreCase("Byte")) {
899 setByte(preparedStatement, valueIndex, object);
900 } else if (type.equalsIgnoreCase("Double")) {
901 setDouble(preparedStatement, valueIndex, object);
902 } else if (type.equalsIgnoreCase("Float")) {
903 setFloat(preparedStatement, valueIndex, object);
904 } else if (type.equalsIgnoreCase("Long")) {
905 setLong(preparedStatement, valueIndex, object);
906 } else if (type.equalsIgnoreCase("Short")) {
907 setShort(preparedStatement, valueIndex, object);
908 } else if (type.equalsIgnoreCase("Boolean")) {
909 setBoolean(preparedStatement, valueIndex, object);
910 } else if (type.equalsIgnoreCase("Date")) {
911 setDate(preparedStatement, valueIndex, object);
912 } else if (type.equalsIgnoreCase("Blob")) {
913 setBlob(preparedStatement, valueIndex, object);
914 } else if (type.equalsIgnoreCase("Clob")) {
915 setClob(preparedStatement, valueIndex, object);
917 setString(preparedStatement, valueIndex, object);
921 private void setClob(PreparedStatement preparedStatement, int valueIndex, Object object)
922 throws JDBCStatementCreatorException {
924 if (object instanceof Clob) {
926 preparedStatement.setClob(valueIndex, (Clob) object);
928 } catch (SQLException e) {
929 log.error("Encountered an error while adding parameter to prepared statement: " + e);
930 throw new JDBCStatementCreatorException(
931 "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
934 log.error("Encountered a dependency with an invalid java type.");
935 throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");
938 private void setBlob(PreparedStatement preparedStatement, int valueIndex, Object object)
939 throws JDBCStatementCreatorException {
941 if (object instanceof Blob) {
943 preparedStatement.setBlob(valueIndex, (Blob) object);
945 } catch (SQLException e) {
946 log.error("Encountered an error while adding parameter to prepared statement: " + e);
947 throw new JDBCStatementCreatorException(
948 "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
951 log.error("Encountered a dependency with an invalid java type.");
952 throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");
955 private void setDate(PreparedStatement preparedStatement, int valueIndex, Object object)
956 throws JDBCStatementCreatorException {
958 if (object instanceof java.sql.Date) {
960 preparedStatement.setDate(valueIndex, (java.sql.Date) object);
962 } catch (SQLException e) {
963 log.error("Encountered an error while adding parameter to prepared statement: " + e);
964 throw new JDBCStatementCreatorException(
965 "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
967 } else if (object instanceof java.util.Date) {
969 // If you want to be frustrated by the java class library, look no further...
970 preparedStatement.setDate(valueIndex, new java.sql.Date(((java.util.Date) object).getTime()));
972 } catch (SQLException e) {
973 log.error("Encountered an error while adding parameter to prepared statement: " + e);
974 throw new JDBCStatementCreatorException(
975 "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
977 } else if (object instanceof Long) {
979 preparedStatement.setDate(valueIndex, new java.sql.Date(((Long) object).longValue()));
981 } catch (SQLException e) {
982 log.error("Encountered an error while adding parameter to prepared statement: " + e);
983 throw new JDBCStatementCreatorException(
984 "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
986 } else if (object instanceof String) {
988 preparedStatement.setDate(valueIndex, new java.sql.Date(new SimpleDateFormat().parse(
989 (String) object).getTime()));
991 } catch (Exception e) {
992 log.error("Encountered an error while adding parameter to prepared statement: " + e);
993 throw new JDBCStatementCreatorException(
994 "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
997 log.error("Encountered a dependency with an invalid java type.");
998 throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");
1001 private void setBoolean(PreparedStatement preparedStatement, int valueIndex, Object object)
1002 throws JDBCStatementCreatorException {
1004 if (object instanceof Boolean) {
1006 preparedStatement.setBoolean(valueIndex, ((Boolean) object).booleanValue());
1008 } catch (SQLException e) {
1009 log.error("Encountered an error while adding parameter to prepared statement: " + e);
1010 throw new JDBCStatementCreatorException(
1011 "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
1013 } else if (object instanceof String) {
1015 preparedStatement.setBoolean(valueIndex, new Boolean((String) object).booleanValue());
1017 } catch (Exception e) {
1018 log.error("Encountered an error while adding parameter to prepared statement: " + e);
1019 throw new JDBCStatementCreatorException(
1020 "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
1023 log.error("Encountered a dependency with an invalid java type.");
1024 throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");
1027 private void setShort(PreparedStatement preparedStatement, int valueIndex, Object object)
1028 throws JDBCStatementCreatorException {
1030 if (object instanceof Boolean) {
1032 preparedStatement.setShort(valueIndex, ((Short) object).shortValue());
1034 } catch (SQLException e) {
1035 log.error("Encountered an error while adding parameter to prepared statement: " + e);
1036 throw new JDBCStatementCreatorException(
1037 "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
1039 } else if (object instanceof String) {
1041 preparedStatement.setShort(valueIndex, new Short((String) object).shortValue());
1043 } catch (Exception e) {
1044 log.error("Encountered an error while adding parameter to prepared statement: " + e);
1045 throw new JDBCStatementCreatorException(
1046 "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
1049 log.error("Encountered a dependency with an invalid java type.");
1050 throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");
1053 private void setLong(PreparedStatement preparedStatement, int valueIndex, Object object)
1054 throws JDBCStatementCreatorException {
1056 if (object instanceof Long || object instanceof Integer || object instanceof Short) {
1058 preparedStatement.setLong(valueIndex, ((Number) object).longValue());
1060 } catch (SQLException e) {
1061 log.error("Encountered an error while adding parameter to prepared statement: " + e);
1062 throw new JDBCStatementCreatorException(
1063 "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
1065 } else if (object instanceof String) {
1067 preparedStatement.setLong(valueIndex, new Long((String) object).longValue());
1069 } catch (Exception e) {
1070 log.error("Encountered an error while adding parameter to prepared statement: " + e);
1071 throw new JDBCStatementCreatorException(
1072 "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
1075 log.error("Encountered a dependency with an invalid java type.");
1076 throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");
1079 private void setFloat(PreparedStatement preparedStatement, int valueIndex, Object object)
1080 throws JDBCStatementCreatorException {
1082 if (object instanceof Float) {
1084 preparedStatement.setFloat(valueIndex, ((Float) object).floatValue());
1086 } catch (SQLException e) {
1087 log.error("Encountered an error while adding parameter to prepared statement: " + e);
1088 throw new JDBCStatementCreatorException(
1089 "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
1091 } else if (object instanceof String) {
1093 preparedStatement.setFloat(valueIndex, new Float((String) object).floatValue());
1095 } catch (Exception e) {
1096 log.error("Encountered an error while adding parameter to prepared statement: " + e);
1097 throw new JDBCStatementCreatorException(
1098 "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
1101 log.error("Encountered a dependency with an invalid java type.");
1102 throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");
1105 private void setDouble(PreparedStatement preparedStatement, int valueIndex, Object object)
1106 throws JDBCStatementCreatorException {
1108 if (object instanceof Double || object instanceof Float) {
1110 preparedStatement.setDouble(valueIndex, ((Number) object).doubleValue());
1112 } catch (SQLException e) {
1113 log.error("Encountered an error while adding parameter to prepared statement: " + e);
1114 throw new JDBCStatementCreatorException(
1115 "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
1117 } else if (object instanceof String) {
1119 preparedStatement.setDouble(valueIndex, new Double((String) object).doubleValue());
1121 } catch (Exception e) {
1122 log.error("Encountered an error while adding parameter to prepared statement: " + e);
1123 throw new JDBCStatementCreatorException(
1124 "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
1127 log.error("Encountered a dependency with an invalid java type.");
1128 throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");
1131 private void setByte(PreparedStatement preparedStatement, int valueIndex, Object object)
1132 throws JDBCStatementCreatorException {
1134 if (object instanceof Byte) {
1136 preparedStatement.setByte(valueIndex, ((Byte) object).byteValue());
1138 } catch (SQLException e) {
1139 log.error("Encountered an error while adding parameter to prepared statement: " + e);
1140 throw new JDBCStatementCreatorException(
1141 "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
1143 } else if (object instanceof String) {
1145 preparedStatement.setByte(valueIndex, new Byte((String) object).byteValue());
1147 } catch (Exception e) {
1148 log.error("Encountered an error while adding parameter to prepared statement: " + e);
1149 throw new JDBCStatementCreatorException(
1150 "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
1153 log.error("Encountered a dependency with an invalid java type.");
1154 throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");
1157 private void setInteger(PreparedStatement preparedStatement, int valueIndex, Object object)
1158 throws JDBCStatementCreatorException {
1160 if (object instanceof Integer || object instanceof Short) {
1162 preparedStatement.setInt(valueIndex, ((Number) object).intValue());
1164 } catch (SQLException e) {
1165 log.error("Encountered an error while adding parameter to prepared statement: " + e);
1166 throw new JDBCStatementCreatorException(
1167 "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
1169 } else if (object instanceof String) {
1171 preparedStatement.setInt(valueIndex, new Integer((String) object).intValue());
1173 } catch (Exception e) {
1174 log.error("Encountered an error while adding parameter to prepared statement: " + e);
1175 throw new JDBCStatementCreatorException(
1176 "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
1179 log.error("Encountered a dependency with an invalid java type.");
1180 throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");
1183 private void setString(PreparedStatement preparedStatement, int valueIndex, Object object)
1184 throws JDBCStatementCreatorException {
1186 if (object instanceof String) {
1188 preparedStatement.setString(valueIndex, (String) object);
1190 } catch (SQLException e) {
1191 log.error("Encountered an error while adding parameter to prepared statement: " + e);
1192 throw new JDBCStatementCreatorException(
1193 "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
1196 log.error("Encountered a dependency with an invalid java type.");
1197 throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");