Fixed logic bug in JDBC Data Connector.
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / aa / attrresolv / provider / JDBCDataConnector.java
1 /*
2  * Copyright [2005] [University Corporation for Advanced Internet Development, Inc.]
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package edu.internet2.middleware.shibboleth.aa.attrresolv.provider;
18
19 import java.io.PrintWriter;
20 import java.lang.reflect.Constructor;
21 import java.security.Principal;
22 import java.sql.Blob;
23 import java.sql.Clob;
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;
34
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;
41
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;
53
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;
59
60 /*
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>.
66  */
67
68 /**
69  * Data Connector that uses JDBC to access user attributes stored in databases.
70  * 
71  * @author David Dearman (dearman@cs.dal.ca)
72  * @author Walter Hoehn (wassa@columbia.edu)
73  * @author Scott Cantor
74  */
75
76 public class JDBCDataConnector extends BaseDataConnector implements DataConnectorPlugIn {
77
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;
85
86         public JDBCDataConnector(Element e) throws ResolutionPlugInException {
87
88                 super(e);
89
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();
95                 }
96                 if (searchVal == null || searchVal.equals("")) {
97                         log.error("Database query must be specified.");
98                         throw new ResolutionPlugInException("Database query must be specified.");
99                 }
100
101                 // Load the supplied JDBC driver
102                 String dbDriverName = e.getAttribute("dbDriver");
103                 if (dbDriverName != null && (!dbDriverName.equals(""))) {
104                         loadDriver(dbDriverName);
105                 }
106
107                 String validationQuery = e.getAttribute("validationQuery");
108                 if (validationQuery == null || validationQuery.equals("")) {
109                         validationQuery = "select 1";
110                 }
111
112                 try {
113                         if (e.getAttributeNode("minResultSet") != null) {
114                                 minResultSet = Integer.parseInt(e.getAttribute("minResultSet"));
115                         }
116                         if (e.getAttributeNode("maxResultSet") != null) {
117                                 maxResultSet = Integer.parseInt(e.getAttribute("maxResultSet"));
118                         }
119                         if (e.getAttributeNode("retryInterval") != null) {
120                                 retryInterval = Integer.parseInt(e.getAttribute("retryInterval"));
121                         }
122                 } catch (NumberFormatException ex) {
123                         log.error("Malformed result set and retry limits: using defaults.");
124                 }
125
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));
131
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");
139
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 + ")");
145                         } else {
146                                 log.error("Property is malformed.");
147                                 throw new ResolutionPlugInException("Property is malformed.");
148                         }
149                 }
150
151                 // Initialize a pooling Data Source
152                 int maxActive = 5;
153                 int maxIdle = 5;
154                 int maxWait = 15;
155                 try {
156                         if (e.getAttributeNode("maxActive") != null) {
157                                 maxActive = Integer.parseInt(e.getAttribute("maxActive"));
158                         }
159                         if (e.getAttributeNode("maxIdle") != null) {
160                                 maxIdle = Integer.parseInt(e.getAttribute("maxIdle"));
161                         }
162                         if (e.getAttributeNode("maxWait") != null) {
163                                 maxWait = Integer.parseInt(e.getAttribute("maxWait"));
164                         }
165                 } catch (NumberFormatException ex) {
166                         log.error("Malformed pooling limits: using defaults.");
167                 }
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");
171                 }
172                 setupDataSource(e.getAttribute("dbURL"), props, maxActive, maxIdle, maxWait, validationQuery);
173         }
174
175         /**
176          * Initialize a Pooling Data Source
177          */
178         private void setupDataSource(String dbURL, Properties props, int maxActive, int maxIdle, int maxWait,
179                         String validationQuery) throws ResolutionPlugInException {
180
181                 GenericObjectPool objectPool = new GenericObjectPool(null);
182
183                 objectPool.setMaxActive(maxActive);
184                 objectPool.setMaxIdle(maxIdle);
185                 if (maxWait > 0) objectPool.setMaxWait(1000 * maxWait);
186                 else objectPool.setMaxWait(maxWait);
187
188                 objectPool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK);
189                 objectPool.setTestOnBorrow(true);
190
191                 ConnectionFactory connFactory = null;
192                 PoolableConnectionFactory poolConnFactory = null;
193
194                 try {
195                         connFactory = new DriverManagerConnectionFactory(dbURL, props);
196                         log.debug("Connection factory initialized.");
197                 } catch (Exception ex) {
198                         log
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());
201                 }
202
203                 try {
204                         poolConnFactory = new PoolableConnectionFactory(connFactory, objectPool, new StackKeyedObjectPoolFactory(),
205                                         validationQuery, true, true);
206                 } catch (Exception ex) {
207                         log.debug("Poolable connection factory error");
208                 }
209
210                 dataSource = new PoolingDataSource(objectPool);
211                 log.info("Data Source initialized.");
212                 try {
213                         dataSource.setLogWriter(new Log4jPrintWriter(Logger.getLogger(JDBCDataConnector.class.getName() + ".Pool"),
214                                         Priority.DEBUG));
215                 } catch (SQLException e) {
216                         log.error("Coudn't setup logger for database connection pool.");
217                 }
218         }
219
220         /**
221          * Instantiate an Attribute Extractor, using the default if none was configured
222          */
223         private void setupAttributeExtractor(Element config) throws ResolutionPlugInException {
224
225                 String className = null;
226                 if (config != null) {
227                         className = config.getAttribute("class");
228                 }
229                 if (className == null || className.equals("")) {
230                         log.debug("Using default Attribute Extractor.");
231                         className = DefaultAE.class.getName();
232                 }
233                 try {
234                         Class aeClass = Class.forName(className);
235                         extractor = (JDBCAttributeExtractor) aeClass.newInstance();
236                         log.debug("Attribute Extractor implementation loaded.");
237
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: "
241                                         + e.getMessage());
242                 } catch (Exception e) {
243                         log.error("Unable to instantiate Attribute Extractor implementation: " + e);
244                         throw new ResolutionPlugInException("Unable to instantiate Attribute Extractor implementation: "
245                                         + e.getMessage());
246                 }
247         }
248
249         /**
250          * Instantiate a Statement Creator, using the default if none was configured
251          */
252         private void setupStatementCreator(Element config) throws ResolutionPlugInException {
253
254                 String scClassName = null;
255                 if (config != null) {
256                         scClassName = config.getAttribute("class");
257                 }
258                 if (scClassName == null || scClassName.equals("")) {
259                         log.debug("Using default Statement Creator.");
260                         scClassName = DefaultStatementCreator.class.getName();
261                 }
262                 try {
263                         Class scClass = Class.forName(scClassName);
264
265                         Class[] params = new Class[1];
266                         params[0] = Class.forName("org.w3c.dom.Element");
267                         try {
268                                 Constructor implementorConstructor = scClass.getConstructor(params);
269                                 Object[] args = new Object[1];
270                                 args[0] = config;
271                                 log.debug("Initializing Statement Creator of type (" + scClass.getName() + ").");
272                                 statementCreator = (JDBCStatementCreator) implementorConstructor.newInstance(args);
273                         } catch (NoSuchMethodException nsme) {
274                                 log
275                                                 .debug("Implementation constructor does have a parameterized constructor, attempting to load default.");
276                                 statementCreator = (JDBCStatementCreator) scClass.newInstance();
277                         }
278                         log.debug("Statement Creator implementation loaded.");
279
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: "
283                                         + e.getMessage());
284                 } catch (Exception e) {
285                         log.error("Unable to instantiate Statement Creator implementation: " + e);
286                         throw new ResolutionPlugInException("Unable to instantiate Statement Creator implementation: "
287                                         + e.getMessage());
288                 }
289         }
290
291         /**
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)
294          */
295         public Attributes resolve(Principal principal, String requester, String responder, Dependencies depends)
296                         throws ResolutionPlugInException {
297
298                 log.debug("Resolving connector: (" + getId() + ")");
299
300                 // Are we alive?
301                 boolean alive = true;
302                 long now = System.currentTimeMillis();
303                 synchronized (this) {
304                         if (deadSince > 0 && now - deadSince < (1000 * retryInterval)) {
305                                 alive = false;
306                         } else {
307                                 deadSince = 0;
308                         }
309                 }
310
311                 if (!alive) {
312                         log.info("JDBC Connector (" + getId() + ") is dead, returning immediately");
313                         throw new ResolutionPlugInException("Connection is dead");
314                 }
315
316                 // Retrieve a connection from the connection pool
317                 Connection conn = null;
318                 try {
319                         conn = dataSource.getConnection();
320                         log.debug("Connection retrieved from pool");
321                 } catch (Exception e) {
322                         synchronized (this) {
323                                 deadSince = now;
324                         }
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: "
327                                         + e.getMessage());
328                 }
329                 if (conn == null) {
330                         log.error("Pool didn't return a properly initialized connection.");
331                         throw new ResolutionPlugInException("Pool didn't return a properly initialized connection.");
332                 }
333
334                 // Setup and execute a (pooled) prepared statement
335                 ResultSet rs = null;
336                 PreparedStatement preparedStatement = null;
337                 try {
338                         preparedStatement = conn.prepareStatement(searchVal);
339                         preparedStatement.clearParameters();
340                         statementCreator.create(preparedStatement, principal, requester, responder, depends);
341                         rs = preparedStatement.executeQuery();
342                         if (!rs.next()) {
343                                 if (minResultSet == 0) return new BasicAttributes();
344                                 else {
345                                         log.error("Statement returned no rows, violating minResultSet of " + minResultSet);
346                                         throw new ResolutionPlugInException("Statement didn't return any rows, violating minResultSet of "
347                                                         + minResultSet);
348                                 }
349                         }
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: "
357                                         + e.getMessage());
358                 } catch (SQLException e) {
359                         synchronized (this) {
360                                 deadSince = now;
361                         }
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: "
364                                         + e.getMessage());
365                 } finally {
366                         Exception e_save = null;
367                         try {
368                                 if (preparedStatement != null) {
369                                         preparedStatement.close();
370                                 }
371                         } catch (SQLException e) {
372                                 log.error("An error occured while closing the prepared statement: " + e.getMessage());
373                                 e_save = e;
374                         }
375                         try {
376                                 if (rs != null) {
377                                         rs.close();
378                                 }
379                         } catch (SQLException e) {
380                                 log.error("An error occured while closing the result set: " + e.getMessage());
381                                 e_save = e;
382                         }
383                         try {
384                                 conn.close();
385                         } catch (SQLException e) {
386                                 log.error("An error occured while closing the database connection: " + e.getMessage());
387                                 e_save = e;
388                         }
389                         if (e_save != null) { throw new ResolutionPlugInException(
390                                         "An error occured while closing database objects:" + e_save.getMessage()); }
391                 }
392         }
393
394         /**
395          * Loads the driver used to access the database
396          * 
397          * @param driver
398          *            The driver used to access the database
399          * @throws ResolutionPlugInException
400          *             If there is a failure to load the driver
401          */
402         public void loadDriver(String driver) throws ResolutionPlugInException {
403
404                 try {
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: "
410                                         + e.getMessage());
411                 }
412                 log.debug("Driver loaded.");
413         }
414
415         private class Log4jPrintWriter extends PrintWriter {
416
417                 private Priority level;
418                 private Logger logger;
419                 private StringBuffer text = new StringBuffer("");
420
421                 private Log4jPrintWriter(Logger logger, org.apache.log4j.Priority level) {
422
423                         super(System.err);
424                         this.level = level;
425                         this.logger = logger;
426                 }
427
428                 public void close() {
429
430                         flush();
431                 }
432
433                 public void flush() {
434
435                         if (!text.toString().equals("")) {
436                                 logger.log(level, text.toString());
437                                 text.setLength(0);
438                         }
439                 }
440
441                 public void print(boolean b) {
442
443                         text.append(b);
444                 }
445
446                 public void print(char c) {
447
448                         text.append(c);
449                 }
450
451                 public void print(char[] s) {
452
453                         text.append(s);
454                 }
455
456                 public void print(double d) {
457
458                         text.append(d);
459                 }
460
461                 public void print(float f) {
462
463                         text.append(f);
464                 }
465
466                 public void print(int i) {
467
468                         text.append(i);
469                 }
470
471                 public void print(long l) {
472
473                         text.append(l);
474                 }
475
476                 public void print(Object obj) {
477
478                         text.append(obj);
479                 }
480
481                 public void print(String s) {
482
483                         text.append(s);
484                 }
485
486                 public void println() {
487
488                         if (!text.toString().equals("")) {
489                                 logger.log(level, text.toString());
490                                 text.setLength(0);
491                         }
492                 }
493
494                 public void println(boolean x) {
495
496                         text.append(x);
497                         logger.log(level, text.toString());
498                         text.setLength(0);
499                 }
500
501                 public void println(char x) {
502
503                         text.append(x);
504                         logger.log(level, text.toString());
505                         text.setLength(0);
506                 }
507
508                 public void println(char[] x) {
509
510                         text.append(x);
511                         logger.log(level, text.toString());
512                         text.setLength(0);
513                 }
514
515                 public void println(double x) {
516
517                         text.append(x);
518                         logger.log(level, text.toString());
519                         text.setLength(0);
520                 }
521
522                 public void println(float x) {
523
524                         text.append(x);
525                         logger.log(level, text.toString());
526                         text.setLength(0);
527                 }
528
529                 public void println(int x) {
530
531                         text.append(x);
532                         logger.log(level, text.toString());
533                         text.setLength(0);
534                 }
535
536                 public void println(long x) {
537
538                         text.append(x);
539                         logger.log(level, text.toString());
540                         text.setLength(0);
541                 }
542
543                 public void println(Object x) {
544
545                         text.append(x);
546                         logger.log(level, text.toString());
547                         text.setLength(0);
548                 }
549
550                 public void println(String x) {
551
552                         text.append(x);
553                         logger.log(level, text.toString());
554                         text.setLength(0);
555                 }
556         }
557 }
558
559 /**
560  * The default attribute extractor.
561  */
562
563 class DefaultAE implements JDBCAttributeExtractor {
564
565         private static Logger log = Logger.getLogger(DefaultAE.class.getName());
566
567         public Attributes extractAttributes(ResultSet rs, int minResultSet, int maxResultSet)
568                         throws JDBCAttributeExtractorException {
569
570                 BasicAttributes attributes = new BasicAttributes(true);
571                 int row = 0;
572
573                 try {
574                         // Get metadata about result set.
575                         ResultSetMetaData rsmd = rs.getMetaData();
576                         int numColumns = rsmd.getColumnCount();
577                         log.debug("Number of returned columns: " + numColumns);
578
579                         do {
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);
584                                 }
585
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)"));
592                                         }
593                                         if (row == 0) {
594                                                 BasicAttribute ba = new BasicAttribute(columnName, true);
595                                                 ba.add(row, columnValue);
596                                                 attributes.put(ba);
597                                         } else {
598                                                 attributes.get(columnName).add(row, columnValue);
599                                         }
600                                 }
601                                 row++;
602                         } while (rs.next());
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());
606                 }
607
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 "
611                                         + minResultSet);
612                 }
613                 return attributes;
614         }
615 }
616
617 class DefaultStatementCreator implements JDBCStatementCreator {
618
619         private static Logger log = Logger.getLogger(DefaultStatementCreator.class.getName());
620         private int numberOfParams = 1;
621
622         public DefaultStatementCreator(Element conf) throws JDBCStatementCreatorException {
623
624                 if (conf != null && conf.getAttribute("numberOfParams") != null
625                                 && !(conf.getAttribute("numberOfParams").equals(""))) {
626                         try {
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.");
633                         }
634                 }
635
636                 log.debug("Parameters configured: " + numberOfParams);
637         }
638
639         public void create(PreparedStatement preparedStatement, Principal principal, String requester, String responder,
640                         Dependencies depends) throws JDBCStatementCreatorException {
641
642                 log.debug("Creating prepared statement.  Substituting principal: (" + principal.getName() + ")");
643                 try {
644                         for (int i = 1; i <= numberOfParams; i++) {
645                                 preparedStatement.setString(i, principal.getName());
646                         }
647                 } catch (SQLException e) {
648                         // Ignore any additional exceptions, assume parameters simply don't exist.
649                 }
650         }
651 }
652
653 class DependencyStatementCreator implements JDBCStatementCreator {
654
655         private static Logger log = Logger.getLogger(DependencyStatementCreator.class.getName());
656         private ArrayList parameters = new ArrayList();
657
658         public DependencyStatementCreator(Element conf) throws JDBCStatementCreatorException {
659
660                 NodeList nodes = conf.getElementsByTagName("Parameter");
661                 for (int i = 0; i < nodes.getLength(); i++) {
662                         Element parameter = (Element) nodes.item(i);
663                         String type = "String";
664                         if (parameter.getAttribute("type") != null && (!parameter.getAttribute("type").equals(""))) {
665                                 type = parameter.getAttribute("type");
666                         }
667
668                         if (parameter.getAttribute("attributeName") == null || parameter.getAttribute("attributeName").equals("")) {
669                                 log.error("Statement Creator Parameter must reference an attribute by name.");
670                                 throw new JDBCStatementCreatorException(
671                                                 "Statement Creator Parameter must reference an attribute by name.");
672                         }
673
674                         if (parameter.getAttribute("connectorId") != null && (!parameter.getAttribute("connectorId").equals(""))) {
675                                 parameters.add(new Parameter(type, parameter.getAttribute("attributeName"), parameter
676                                                 .getAttribute("connectorId")));
677                         } else {
678                                 parameters.add(new Parameter(type, parameter.getAttribute("attributeName")));
679
680                         }
681
682                         if (parameter.getAttribute("nullMissing") != null && (!parameter.getAttribute("nullMissing").equals(""))) {
683                                 if (parameter.getAttribute("nullMissing").equalsIgnoreCase("FALSE")) {
684                                         ((Parameter) parameters.get(i)).setNullMissing(false);
685                                 }
686                         }
687                 }
688                 log.debug("Parameters configured: " + parameters.size());
689         }
690
691         public void create(PreparedStatement preparedStatement, Principal principal, String requester, String responder,
692                         Dependencies depends) throws JDBCStatementCreatorException {
693
694                 try {
695                         log.debug("Creating prepared statement.  Substituting values from dependencies.");
696                         for (int i = 0; i < parameters.size(); i++) {
697                                 ((Parameter) parameters.get(i)).setParameterValue(preparedStatement, i + 1, depends, principal,
698                                                 requester);
699                         }
700
701                 } catch (Exception e) {
702                         log.error("Encountered an error while creating prepared statement (principal=" + principal.getName()
703                                         + "): " + e);
704                         throw new JDBCStatementCreatorException("Encountered an error while creating prepared statement: "
705                                         + e.getMessage());
706                 }
707         }
708
709         protected class Parameter {
710
711                 private String type;
712                 private String attributeName;
713                 private boolean referencesConnector = false;
714                 private String connectorId;
715                 private boolean nullMissing = true;
716
717                 protected Parameter(String type, String attributeName) throws JDBCStatementCreatorException {
718
719                         if ((!type.equalsIgnoreCase("String")) && (!type.equalsIgnoreCase("Integer"))
720                                         && (!type.equalsIgnoreCase("Byte")) && (!type.equalsIgnoreCase("Double"))
721                                         && (!type.equalsIgnoreCase("Float")) && (!type.equalsIgnoreCase("Long"))
722                                         && (!type.equalsIgnoreCase("Short")) && (!type.equalsIgnoreCase("Boolean"))
723                                         && (!type.equalsIgnoreCase("Date")) && (!type.equalsIgnoreCase("Blob"))
724                                         && (!type.equalsIgnoreCase("Clob"))) {
725                                 log.error("Unsupported type configured for Statement Creator Parameter.");
726                                 throw new JDBCStatementCreatorException("Unable to load Statement Creator Parameter.");
727                         }
728                         this.type = type;
729                         this.attributeName = attributeName;
730
731                         if (attributeName == null) {
732                                 log.error("No (attributeName) attribute specified for Statement Creator Parameter.");
733                                 throw new JDBCStatementCreatorException("Unable to load Statement Creator Parameter.");
734                         } else if ((attributeName.equals("%PRINCIPAL%") || attributeName.equals("%REQUESTER%"))
735                                         && !type.equalsIgnoreCase("String")) {
736                                 log.error("The (type) attribute must be set to \"String\" when \"%PRINCIPAL%\" or \"%REQUESTER%\" is "
737                                                 + "used as the (attributeName) for a Statement Creator Parameter.");
738                                 throw new JDBCStatementCreatorException("Unable to load Statement Creator Parameter.");
739                         }
740                 }
741
742                 protected Parameter(String type, String attributeName, String connectorId) throws JDBCStatementCreatorException {
743
744                         this(type, attributeName);
745                         referencesConnector = true;
746                         this.connectorId = connectorId;
747
748                 }
749
750                 protected int getSQLType() {
751
752                         if (type.equalsIgnoreCase("String")) {
753                                 return Types.VARCHAR;
754                         } else if (type.equalsIgnoreCase("Integer")) {
755                                 return Types.INTEGER;
756                         } else if (type.equalsIgnoreCase("Byte")) {
757                                 return Types.TINYINT;
758                         } else if (type.equalsIgnoreCase("Double")) {
759                                 return Types.DOUBLE;
760                         } else if (type.equalsIgnoreCase("Float")) {
761                                 return Types.FLOAT;
762                         } else if (type.equalsIgnoreCase("Long")) {
763                                 return Types.INTEGER;
764                         } else if (type.equalsIgnoreCase("Short")) {
765                                 return Types.SMALLINT;
766                         } else if (type.equalsIgnoreCase("Boolean")) {
767                                 return Types.BOOLEAN;
768                         } else if (type.equalsIgnoreCase("Date")) {
769                                 return Types.DATE;
770                         } else if (type.equalsIgnoreCase("Blob")) {
771                                 return Types.BLOB;
772                         } else if (type.equalsIgnoreCase("Clob")) {
773                                 return Types.CLOB;
774                         } else {
775                                 return Types.VARCHAR;
776                         }
777                 }
778
779                 protected void setParameterValue(PreparedStatement preparedStatement, int valueIndex, Dependencies depends,
780                                 Principal principal, String requester) throws JDBCStatementCreatorException {
781
782                         // handle values from DataConnectors
783                         if (referencesConnector) {
784                                 Attributes attributes = depends.getConnectorResolution(connectorId);
785                                 if (attributes == null) {
786                                         log.error("Statement Creator misconfiguration: Connector (" + connectorId
787                                                         + ") is not a dependency of this JDBCDataConnector.");
788                                         throw new JDBCStatementCreatorException("Statement Creator misconfiguration: Connector ("
789                                                         + connectorId + ") is not a dependency of this JDBCDataConnector.");
790                                 }
791
792                                 Attribute attribute = attributes.get(attributeName);
793                                 if (attribute == null || attribute.size() < 1) {
794                                         if (attributeName.equalsIgnoreCase("%REQUESTER%")) {
795                                                 try {
796                                                         setSpecificParameter(preparedStatement, valueIndex, requester);
797                                                         return;
798                                                 } catch (Exception e) {
799                                                         log.error("Statement Creator encountered an error while adding the parameter 'Requester': "
800                                                                         + e);
801                                                         throw new JDBCStatementCreatorException(
802                                                                         "Statement Creator encountered an error while parameter 'Requester': "
803                                                                                         + e.getMessage());
804                                                 }
805                                         } else if (attributeName.equalsIgnoreCase("%PRINCIPAL%")) {
806                                                 try {
807                                                         setSpecificParameter(preparedStatement, valueIndex, principal.toString());
808                                                         return;
809                                                 } catch (Exception e) {
810                                                         log.error("Statement Creator encountered an error while adding the parameter 'Requester': "
811                                                                         + e);
812                                                         throw new JDBCStatementCreatorException(
813                                                                         "Statement Creator encountered an error while parameter 'Requester': "
814                                                                                         + e.getMessage());
815                                                 }
816                                         } else if (nullMissing) {
817                                                 try {
818                                                         preparedStatement.setNull(valueIndex, getSQLType());
819                                                         return;
820                                                 } catch (SQLException e) {
821                                                         log
822                                                                         .error("Encountered a problem while attempting to convert missing attribute value to null parameter.");
823                                                 }
824                                         }
825                                         log.error("Cannot parameterize prepared statement: missing dependency value.");
826                                         throw new JDBCStatementCreatorException(
827                                                         "Cannot parameterize prepared statement: missing dependency value.");
828                                 }
829
830                                 if (attribute.size() > 1) {
831                                         log.error("Statement Creator encountered a multivalued dependent attribute.");
832                                         throw new JDBCStatementCreatorException(
833                                                         "Statement Creator encountered a multivalued dependent attribute.");
834                                 }
835
836                                 try {
837                                         setSpecificParameter(preparedStatement, valueIndex, attribute.get());
838                                         return;
839                                 } catch (NamingException e) {
840                                         log.error("Statement Creator encountered an error while extracting attributes "
841                                                         + "from a Data Conector: " + e);
842                                         throw new JDBCStatementCreatorException(
843                                                         "Statement Creator encountered an error while extracting attributes from a Data Conector: "
844                                                                         + e.getMessage());
845                                 }
846                         }
847
848                         // handle values from AttributeDefinitons
849                         ResolverAttribute attribute = depends.getAttributeResolution(attributeName);
850                         if (attribute != null) {
851                                 Iterator iterator = attribute.getValues();
852                                 if (iterator.hasNext()) {
853                                         setSpecificParameter(preparedStatement, valueIndex, iterator.next());
854                                         if (iterator.hasNext()) {
855                                                 log.error("Statement Creator encountered a multivalued dependent attribute.");
856                                                 throw new JDBCStatementCreatorException(
857                                                                 "Statement Creator encountered a multivalued dependent attribute.");
858                                         }
859                                         return;
860                                 }
861                         }
862                         if (nullMissing) {
863                                 try {
864                                         preparedStatement.setNull(valueIndex, getSQLType());
865                                         return;
866                                 } catch (SQLException e) {
867                                         log.error("Encountered a problem while attempting to convert missing attribute "
868                                                         + "value to null parameter.");
869                                 }
870                         }
871                         log.error("Cannot parameterize prepared statement: missing dependency value.");
872                         throw new JDBCStatementCreatorException("Cannot parameterize prepared statement: missing dependency value.");
873                 }
874
875                 protected void setNullMissing(boolean nullMissing) {
876
877                         this.nullMissing = nullMissing;
878                 }
879
880                 private void setSpecificParameter(PreparedStatement preparedStatement, int valueIndex, Object object)
881                                 throws JDBCStatementCreatorException {
882
883                         if (object == null) {
884                                 try {
885                                         preparedStatement.setNull(valueIndex, getSQLType());
886                                         return;
887                                 } catch (SQLException e) {
888                                         log
889                                                         .error("Encountered a problem while attempting to convert missing attribute value to null parameter.");
890                                         throw new JDBCStatementCreatorException(
891                                                         "Encountered a problem while attempting to convert missing attribute value to null parameter.");
892                                 }
893                         } else if (type.equalsIgnoreCase("String")) {
894                                 setString(preparedStatement, valueIndex, object);
895                         } else if (type.equalsIgnoreCase("Integer")) {
896                                 setInteger(preparedStatement, valueIndex, object);
897                         } else if (type.equalsIgnoreCase("Byte")) {
898                                 setByte(preparedStatement, valueIndex, object);
899                         } else if (type.equalsIgnoreCase("Double")) {
900                                 setDouble(preparedStatement, valueIndex, object);
901                         } else if (type.equalsIgnoreCase("Float")) {
902                                 setFloat(preparedStatement, valueIndex, object);
903                         } else if (type.equalsIgnoreCase("Long")) {
904                                 setLong(preparedStatement, valueIndex, object);
905                         } else if (type.equalsIgnoreCase("Short")) {
906                                 setShort(preparedStatement, valueIndex, object);
907                         } else if (type.equalsIgnoreCase("Boolean")) {
908                                 setBoolean(preparedStatement, valueIndex, object);
909                         } else if (type.equalsIgnoreCase("Date")) {
910                                 setDate(preparedStatement, valueIndex, object);
911                         } else if (type.equalsIgnoreCase("Blob")) {
912                                 setBlob(preparedStatement, valueIndex, object);
913                         } else if (type.equalsIgnoreCase("Clob")) {
914                                 setClob(preparedStatement, valueIndex, object);
915                         } else {
916                                 setString(preparedStatement, valueIndex, object);
917                         }
918                 }
919
920                 private void setClob(PreparedStatement preparedStatement, int valueIndex, Object object)
921                                 throws JDBCStatementCreatorException {
922
923                         if (object instanceof Clob) {
924                                 try {
925                                         preparedStatement.setClob(valueIndex, (Clob) object);
926                                         return;
927                                 } catch (SQLException e) {
928                                         log.error("Encountered an error while adding parameter to prepared statement: " + e);
929                                         throw new JDBCStatementCreatorException(
930                                                         "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
931                                 }
932                         }
933                         log.error("Encountered a dependency with an invalid java type.");
934                         throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");
935                 }
936
937                 private void setBlob(PreparedStatement preparedStatement, int valueIndex, Object object)
938                                 throws JDBCStatementCreatorException {
939
940                         if (object instanceof Blob) {
941                                 try {
942                                         preparedStatement.setBlob(valueIndex, (Blob) object);
943                                         return;
944                                 } catch (SQLException e) {
945                                         log.error("Encountered an error while adding parameter to prepared statement: " + e);
946                                         throw new JDBCStatementCreatorException(
947                                                         "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
948                                 }
949                         }
950                         log.error("Encountered a dependency with an invalid java type.");
951                         throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");
952                 }
953
954                 private void setDate(PreparedStatement preparedStatement, int valueIndex, Object object)
955                                 throws JDBCStatementCreatorException {
956
957                         if (object instanceof java.sql.Date) {
958                                 try {
959                                         preparedStatement.setDate(valueIndex, (java.sql.Date) object);
960                                         return;
961                                 } catch (SQLException e) {
962                                         log.error("Encountered an error while adding parameter to prepared statement: " + e);
963                                         throw new JDBCStatementCreatorException(
964                                                         "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
965                                 }
966                         } else if (object instanceof java.util.Date) {
967                                 try {
968                                         // If you want to be frustrated by the java class library, look no further...
969                                         preparedStatement.setDate(valueIndex, new java.sql.Date(((java.util.Date) object).getTime()));
970                                         return;
971                                 } catch (SQLException e) {
972                                         log.error("Encountered an error while adding parameter to prepared statement: " + e);
973                                         throw new JDBCStatementCreatorException(
974                                                         "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
975                                 }
976                         } else if (object instanceof Long) {
977                                 try {
978                                         preparedStatement.setDate(valueIndex, new java.sql.Date(((Long) object).longValue()));
979                                         return;
980                                 } catch (SQLException e) {
981                                         log.error("Encountered an error while adding parameter to prepared statement: " + e);
982                                         throw new JDBCStatementCreatorException(
983                                                         "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
984                                 }
985                         } else if (object instanceof String) {
986                                 try {
987                                         preparedStatement.setDate(valueIndex, new java.sql.Date(new SimpleDateFormat().parse(
988                                                         (String) object).getTime()));
989                                         return;
990                                 } catch (Exception e) {
991                                         log.error("Encountered an error while adding parameter to prepared statement: " + e);
992                                         throw new JDBCStatementCreatorException(
993                                                         "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
994                                 }
995                         }
996                         log.error("Encountered a dependency with an invalid java type.");
997                         throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");
998                 }
999
1000                 private void setBoolean(PreparedStatement preparedStatement, int valueIndex, Object object)
1001                                 throws JDBCStatementCreatorException {
1002
1003                         if (object instanceof Boolean) {
1004                                 try {
1005                                         preparedStatement.setBoolean(valueIndex, ((Boolean) object).booleanValue());
1006                                         return;
1007                                 } catch (SQLException e) {
1008                                         log.error("Encountered an error while adding parameter to prepared statement: " + e);
1009                                         throw new JDBCStatementCreatorException(
1010                                                         "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
1011                                 }
1012                         } else if (object instanceof String) {
1013                                 try {
1014                                         preparedStatement.setBoolean(valueIndex, new Boolean((String) object).booleanValue());
1015                                         return;
1016                                 } catch (Exception e) {
1017                                         log.error("Encountered an error while adding parameter to prepared statement: " + e);
1018                                         throw new JDBCStatementCreatorException(
1019                                                         "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
1020                                 }
1021                         }
1022                         log.error("Encountered a dependency with an invalid java type.");
1023                         throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");
1024                 }
1025
1026                 private void setShort(PreparedStatement preparedStatement, int valueIndex, Object object)
1027                                 throws JDBCStatementCreatorException {
1028
1029                         if (object instanceof Boolean) {
1030                                 try {
1031                                         preparedStatement.setShort(valueIndex, ((Short) object).shortValue());
1032                                         return;
1033                                 } catch (SQLException e) {
1034                                         log.error("Encountered an error while adding parameter to prepared statement: " + e);
1035                                         throw new JDBCStatementCreatorException(
1036                                                         "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
1037                                 }
1038                         } else if (object instanceof String) {
1039                                 try {
1040                                         preparedStatement.setShort(valueIndex, new Short((String) object).shortValue());
1041                                         return;
1042                                 } catch (Exception e) {
1043                                         log.error("Encountered an error while adding parameter to prepared statement: " + e);
1044                                         throw new JDBCStatementCreatorException(
1045                                                         "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
1046                                 }
1047                         }
1048                         log.error("Encountered a dependency with an invalid java type.");
1049                         throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");
1050                 }
1051
1052                 private void setLong(PreparedStatement preparedStatement, int valueIndex, Object object)
1053                                 throws JDBCStatementCreatorException {
1054
1055                         if (object instanceof Long || object instanceof Integer || object instanceof Short) {
1056                                 try {
1057                                         preparedStatement.setLong(valueIndex, ((Number) object).longValue());
1058                                         return;
1059                                 } catch (SQLException e) {
1060                                         log.error("Encountered an error while adding parameter to prepared statement: " + e);
1061                                         throw new JDBCStatementCreatorException(
1062                                                         "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
1063                                 }
1064                         } else if (object instanceof String) {
1065                                 try {
1066                                         preparedStatement.setLong(valueIndex, new Long((String) object).longValue());
1067                                         return;
1068                                 } catch (Exception e) {
1069                                         log.error("Encountered an error while adding parameter to prepared statement: " + e);
1070                                         throw new JDBCStatementCreatorException(
1071                                                         "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
1072                                 }
1073                         }
1074                         log.error("Encountered a dependency with an invalid java type.");
1075                         throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");
1076                 }
1077
1078                 private void setFloat(PreparedStatement preparedStatement, int valueIndex, Object object)
1079                                 throws JDBCStatementCreatorException {
1080
1081                         if (object instanceof Float) {
1082                                 try {
1083                                         preparedStatement.setFloat(valueIndex, ((Float) object).floatValue());
1084                                         return;
1085                                 } catch (SQLException e) {
1086                                         log.error("Encountered an error while adding parameter to prepared statement: " + e);
1087                                         throw new JDBCStatementCreatorException(
1088                                                         "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
1089                                 }
1090                         } else if (object instanceof String) {
1091                                 try {
1092                                         preparedStatement.setFloat(valueIndex, new Float((String) object).floatValue());
1093                                         return;
1094                                 } catch (Exception e) {
1095                                         log.error("Encountered an error while adding parameter to prepared statement: " + e);
1096                                         throw new JDBCStatementCreatorException(
1097                                                         "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
1098                                 }
1099                         }
1100                         log.error("Encountered a dependency with an invalid java type.");
1101                         throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");
1102                 }
1103
1104                 private void setDouble(PreparedStatement preparedStatement, int valueIndex, Object object)
1105                                 throws JDBCStatementCreatorException {
1106
1107                         if (object instanceof Double || object instanceof Float) {
1108                                 try {
1109                                         preparedStatement.setDouble(valueIndex, ((Number) object).doubleValue());
1110                                         return;
1111                                 } catch (SQLException e) {
1112                                         log.error("Encountered an error while adding parameter to prepared statement: " + e);
1113                                         throw new JDBCStatementCreatorException(
1114                                                         "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
1115                                 }
1116                         } else if (object instanceof String) {
1117                                 try {
1118                                         preparedStatement.setDouble(valueIndex, new Double((String) object).doubleValue());
1119                                         return;
1120                                 } catch (Exception e) {
1121                                         log.error("Encountered an error while adding parameter to prepared statement: " + e);
1122                                         throw new JDBCStatementCreatorException(
1123                                                         "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
1124                                 }
1125                         }
1126                         log.error("Encountered a dependency with an invalid java type.");
1127                         throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");
1128                 }
1129
1130                 private void setByte(PreparedStatement preparedStatement, int valueIndex, Object object)
1131                                 throws JDBCStatementCreatorException {
1132
1133                         if (object instanceof Byte) {
1134                                 try {
1135                                         preparedStatement.setByte(valueIndex, ((Byte) object).byteValue());
1136                                         return;
1137                                 } catch (SQLException e) {
1138                                         log.error("Encountered an error while adding parameter to prepared statement: " + e);
1139                                         throw new JDBCStatementCreatorException(
1140                                                         "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
1141                                 }
1142                         } else if (object instanceof String) {
1143                                 try {
1144                                         preparedStatement.setByte(valueIndex, new Byte((String) object).byteValue());
1145                                         return;
1146                                 } catch (Exception e) {
1147                                         log.error("Encountered an error while adding parameter to prepared statement: " + e);
1148                                         throw new JDBCStatementCreatorException(
1149                                                         "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
1150                                 }
1151                         }
1152                         log.error("Encountered a dependency with an invalid java type.");
1153                         throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");
1154                 }
1155
1156                 private void setInteger(PreparedStatement preparedStatement, int valueIndex, Object object)
1157                                 throws JDBCStatementCreatorException {
1158
1159                         if (object instanceof Integer || object instanceof Short) {
1160                                 try {
1161                                         preparedStatement.setInt(valueIndex, ((Number) object).intValue());
1162                                         return;
1163                                 } catch (SQLException e) {
1164                                         log.error("Encountered an error while adding parameter to prepared statement: " + e);
1165                                         throw new JDBCStatementCreatorException(
1166                                                         "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
1167                                 }
1168                         } else if (object instanceof String) {
1169                                 try {
1170                                         preparedStatement.setInt(valueIndex, new Integer((String) object).intValue());
1171                                         return;
1172                                 } catch (Exception e) {
1173                                         log.error("Encountered an error while adding parameter to prepared statement: " + e);
1174                                         throw new JDBCStatementCreatorException(
1175                                                         "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
1176                                 }
1177                         }
1178                         log.error("Encountered a dependency with an invalid java type.");
1179                         throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");
1180                 }
1181
1182                 private void setString(PreparedStatement preparedStatement, int valueIndex, Object object)
1183                                 throws JDBCStatementCreatorException {
1184
1185                         if (object instanceof String) {
1186                                 try {
1187                                         preparedStatement.setString(valueIndex, (String) object);
1188                                         return;
1189                                 } catch (SQLException e) {
1190                                         log.error("Encountered an error while adding parameter to prepared statement: " + e);
1191                                         throw new JDBCStatementCreatorException(
1192                                                         "Encountered an error while adding parameter to prepared statement: " + e.getMessage());
1193                                 }
1194                         }
1195                         log.error("Encountered a dependency with an invalid java type.");
1196                         throw new JDBCStatementCreatorException("Encountered a dependency with an invalid java type.");
1197                 }
1198         }
1199 }