View Javadoc
1   /*
2    * Copyright (C) 2003-2012 David E. Berry
3    *
4    * This library is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Lesser General Public
6    * License as published by the Free Software Foundation; either
7    * version 2.1 of the License, or (at your option) any later version.
8    *
9    * This library is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   * Lesser General Public License for more details.
13   *
14   * You should have received a copy of the GNU Lesser General Public
15   * License along with this library; if not, write to the Free Software
16   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17   *
18   * A copy of the GNU Lesser General Public License may also be found at
19   * http://www.gnu.org/licenses/lgpl.txt
20   */
21  package org.synchronoss.cpo.jdbc;
22  
23  import org.slf4j.*;
24  import org.synchronoss.cpo.*;
25  import org.synchronoss.cpo.helper.ExceptionHelper;
26  import org.synchronoss.cpo.jdbc.meta.JdbcCpoMetaDescriptor;
27  import org.synchronoss.cpo.jdbc.meta.JdbcMethodMapper;
28  import org.synchronoss.cpo.meta.CpoMetaDescriptor;
29  import org.synchronoss.cpo.meta.DataTypeMapEntry;
30  import org.synchronoss.cpo.meta.ResultSetCpoData;
31  import org.synchronoss.cpo.meta.domain.*;
32  
33  import javax.naming.*;
34  import javax.sql.DataSource;
35  import java.sql.*;
36  import java.util.*;
37  
38  /**
39   * JdbcCpoAdapter is an interface for a set of routines that are responsible for managing value objects from a
40   * datasource.
41   *
42   * @author david berry
43   */
44  public class JdbcCpoAdapter extends CpoBaseAdapter<DataSource> {
45  
46    /**
47     * Version Id for this class.
48     */
49    private static final long serialVersionUID = 1L;
50    /**
51     * DOCUMENT ME!
52     */
53    private static final Logger logger = LoggerFactory.getLogger(JdbcCpoAdapter.class);
54  
55    /**
56     * DOCUMENT ME!
57     */
58    private Context context_ = null;
59  
60    /**
61     * DOCUMENT ME!
62     */
63    private boolean invalidReadConnection_ = false;
64    private boolean batchUpdatesSupported_ = false;
65    /**
66     * CpoMetaDescriptor allows you to get the meta data for a class.
67     */
68    private JdbcCpoMetaDescriptor metaDescriptor = null;
69  
70    protected JdbcCpoAdapter() {
71    }
72  
73    /**
74     * Creates a JdbcCpoAdapter.
75     *
76     * @param metaDescriptor This datasource that identifies the cpo metadata datasource
77     * @param jdsiTrx        The datasoruce that identifies the transaction database.
78     * @throws org.synchronoss.cpo.CpoException
79     *          exception
80     */
81    protected JdbcCpoAdapter(JdbcCpoMetaDescriptor metaDescriptor, DataSourceInfo<DataSource> jdsiTrx) throws CpoException {
82  
83      this.metaDescriptor = metaDescriptor;
84      setWriteDataSource(jdsiTrx.getDataSource());
85      setReadDataSource(jdsiTrx.getDataSource());
86      setDataSourceName(jdsiTrx.getDataSourceName());
87      processDatabaseMetaData();
88    }
89  
90    /**
91     * Creates a JdbcCpoAdapter.
92     *
93     * @param metaDescriptor This datasource that identifies the cpo metadata datasource
94     * @param jdsiWrite      The datasource that identifies the transaction database for write transactions.
95     * @param jdsiRead       The datasource that identifies the transaction database for read-only transactions.
96     * @throws org.synchronoss.cpo.CpoException
97     *          exception
98     */
99    protected JdbcCpoAdapter(JdbcCpoMetaDescriptor metaDescriptor, DataSourceInfo<DataSource> jdsiWrite, DataSourceInfo<DataSource> jdsiRead) throws CpoException {
100     this.metaDescriptor = metaDescriptor;
101     setWriteDataSource(jdsiWrite.getDataSource());
102     setReadDataSource(jdsiRead.getDataSource());
103     setDataSourceName(jdsiWrite.getDataSourceName());
104     processDatabaseMetaData();
105   }
106 
107   /**
108    * This constructor is used specifically to create a JdbcCpoTrxAdapter.
109    *
110    * @param metaDescriptor
111    * @param batchSupported
112    * @param dataSourceName
113    * @throws CpoException
114    */
115   protected JdbcCpoAdapter(JdbcCpoMetaDescriptor metaDescriptor, boolean batchSupported, String dataSourceName) throws CpoException {
116     this.metaDescriptor = metaDescriptor;
117     batchUpdatesSupported_ = batchSupported;
118     setDataSourceName(dataSourceName);
119   }
120 
121   private void processDatabaseMetaData() throws CpoException {
122     Connection c = null;
123     try {
124       c = getWriteConnection();
125       DatabaseMetaData dmd = c.getMetaData();
126 
127       // do all the tests here
128       batchUpdatesSupported_ = dmd.supportsBatchUpdates();
129 
130       this.closeConnection(c);
131     } catch (Throwable t) {
132       logger.error(ExceptionHelper.getLocalizedMessage(t), t);
133       throw new CpoException("Could Not Retrieve Database Meta Data", t);
134     } finally {
135       closeConnection(c);
136     }
137   }
138 
139   public static JdbcCpoAdapter getInstance(JdbcCpoMetaDescriptor metaDescriptor, DataSourceInfo<DataSource> jdsiTrx) throws CpoException {
140     String adapterKey = metaDescriptor + ":" + jdsiTrx.getDataSourceName();
141     JdbcCpoAdapter adapter = (JdbcCpoAdapter) findCpoAdapter(adapterKey);
142     if (adapter == null) {
143       adapter = new JdbcCpoAdapter(metaDescriptor, jdsiTrx);
144       addCpoAdapter(adapterKey, adapter);
145     }
146     return adapter;
147   }
148 
149   /**
150    * Creates a JdbcCpoAdapter.
151    *
152    * @param metaDescriptor This datasource that identifies the cpo metadata datasource
153    * @param jdsiWrite      The datasource that identifies the transaction database for write transactions.
154    * @param jdsiRead       The datasource that identifies the transaction database for read-only transactions.
155    * @throws org.synchronoss.cpo.CpoException
156    *          exception
157    */
158   public static JdbcCpoAdapter getInstance(JdbcCpoMetaDescriptor metaDescriptor, DataSourceInfo<DataSource> jdsiWrite, DataSourceInfo<DataSource> jdsiRead) throws CpoException {
159     String adapterKey = metaDescriptor + ":" + jdsiWrite.getDataSourceName() + ":" + jdsiRead.getDataSourceName();
160     JdbcCpoAdapter adapter = (JdbcCpoAdapter) findCpoAdapter(adapterKey);
161     if (adapter == null) {
162       adapter = new JdbcCpoAdapter(metaDescriptor, jdsiWrite, jdsiRead);
163       addCpoAdapter(adapterKey, adapter);
164     }
165     return adapter;
166   }
167 
168   /**
169    * Creates the Object in the datasource. The assumption is that the object does not exist in the datasource. This
170    * method creates and stores the object in the datasource.
171    * <p/>
172    * <pre>Example:
173    * <code>
174    * <p/>
175    * class SomeObject so = new SomeObject();
176    * class CpoAdapter cpo = null;
177    * <p/>
178    * try {
179    * 	cpo = new JdbcCpoAdapter(new JdbcDataSourceInfo(driver, url, user, password,1,1,false));
180    * } catch (CpoException ce) {
181    * 	// Handle the error
182    * 	cpo = null;
183    * }
184    * <p/>
185    * if (cpo!=null) {
186    * 	so.setId(1);
187    * 	so.setName("SomeName");
188    * 	try{
189    * 		cpo.insertObject(so);
190    *  } catch (CpoException ce) {
191    * 		// Handle the error
192    * <p/>
193    *  }
194    * }
195    * </code>
196    * </pre>
197    *
198    * @param obj This is an object that has been defined within the metadata of the datasource. If the class is not
199    *            defined an exception will be thrown.
200    * @return The number of objects created in the datasource
201    * @throws CpoException Thrown if there are errors accessing the datasource
202    */
203   @Override
204   public <T> long insertObject(T obj) throws CpoException {
205     return processUpdateGroup(obj, JdbcCpoAdapter.CREATE_GROUP, null, null, null, null);
206   }
207 
208   /**
209    * Creates the Object in the datasource. The assumption is that the object does not exist in the datasource. This
210    * method creates and stores the object in the datasource
211    * <p/>
212    * <pre>Example:
213    * <code>
214    * <p/>
215    * class SomeObject so = new SomeObject();
216    * class CpoAdapter cpo = null;
217    * <p/>
218    * try {
219    * 	cpo = new JdbcCpoAdapter(new JdbcDataSourceInfo(driver, url, user, password,1,1,false));
220    * } catch (CpoException ce) {
221    * 	// Handle the error
222    * 	cpo = null;
223    * }
224    * <p/>
225    * if (cpo!=null) {
226    * 	so.setId(1);
227    * 	so.setName("SomeName");
228    * 	try{
229    * 		cpo.insertObject("IDNameInsert",so);
230    *  } catch (CpoException ce) {
231    * 		// Handle the error
232    *  }
233    * }
234    * </code>
235    * </pre>
236    *
237    * @param name The String name of the CREATE Function Group that will be used to create the object in the datasource.
238    *             null signifies that the default rules will be used which is equivalent to insertObject(Object obj);
239    * @param obj  This is an object that has been defined within the metadata of the datasource. If the class is not
240    *             defined an exception will be thrown.
241    * @return The number of objects created in the datasource
242    * @throws CpoException Thrown if there are errors accessing the datasource
243    */
244   @Override
245   public <T> long insertObject(String name, T obj) throws CpoException {
246     return processUpdateGroup(obj, JdbcCpoAdapter.CREATE_GROUP, name, null, null, null);
247   }
248 
249   /**
250    * Creates the Object in the datasource. The assumption is that the object does not exist in the datasource. This
251    * method creates and stores the object in the datasource
252    * <p/>
253    * <pre>Example:
254    * <code>
255    * <p/>
256    * class SomeObject so = new SomeObject();
257    * class CpoAdapter cpo = null;
258    * <p/>
259    * try {
260    * 	cpo = new JdbcCpoAdapter(new JdbcDataSourceInfo(driver, url, user, password,1,1,false));
261    * } catch (CpoException ce) {
262    * 	// Handle the error
263    * 	cpo = null;
264    * }
265    * <p/>
266    * if (cpo!=null) {
267    * 	so.setId(1);
268    * 	so.setName("SomeName");
269    * 	try{
270    * 		cpo.insertObject("IDNameInsert",so);
271    *  } catch (CpoException ce) {
272    * 		// Handle the error
273    *  }
274    * }
275    * </code>
276    * </pre>
277    *
278    * @param name              The String name of the CREATE Function Group that will be used to create the object in the datasource.
279    *                          null signifies that the default rules will be used which is equivalent to insertObject(Object obj);
280    * @param obj               This is an object that has been defined within the metadata of the datasource. If the class is not
281    *                          defined an exception will be thrown.
282    * @param wheres            A collection of CpoWhere beans that define the constraints that should be used when retrieving beans
283    * @param orderBy           The CpoOrderBy bean that defines the order in which beans should be returned
284    * @param nativeExpressions Native expression that will be used to augment the expression stored in the meta data. This
285    *                          text will be embedded at run-time
286    * @return The number of objects created in the datasource
287    * @throws CpoException Thrown if there are errors accessing the datasource
288    */
289   @Override
290   public <T> long insertObject(String name, T obj, Collection<CpoWhere> wheres, Collection<CpoOrderBy> orderBy, Collection<CpoNativeFunction> nativeExpressions) throws CpoException {
291     return processUpdateGroup(obj, JdbcCpoAdapter.CREATE_GROUP, name, wheres, orderBy, nativeExpressions);
292   }
293 
294   /**
295    * Iterates through a collection of Objects, creates and stores them in the datasource. The assumption is that the
296    * objects contained in the collection do not exist in the datasource.
297    * <p/>
298    * This method creates and stores the objects in the datasource. The objects in the collection will be treated as one
299    * transaction, assuming the datasource supports transactions.
300    * <p/>
301    * This means that if one of the objects fail being created in the datasource then the CpoAdapter will stop processing
302    * the remainder of the collection and rollback all the objects created thus far. Rollback is on the underlying
303    * datasource's support of rollback.
304    * <p/>
305    * <pre>Example:
306    * <code>
307    * <p/>
308    * class SomeObject so = null;
309    * class CpoAdapter cpo = null;
310    * <p/>
311    * try {
312    * 	cpo = new JdbcCpoAdapter(new JdbcDataSourceInfo(driver, url, user, password,1,1,false));
313    * } catch (CpoException ce) {
314    * 	// Handle the error
315    * 	cpo = null;
316    * }
317    * <p/>
318    * if (cpo!=null) {
319    * 	ArrayList al = new ArrayList();
320    * 	for (int i=0; i<3; i++){
321    * 		so = new SomeObject();
322    * 		so.setId(1);
323    * 		so.setName("SomeName");
324    * 		al.add(so);
325    *  }
326    * 	try{
327    * 		cpo.insertObjects(al);
328    *  } catch (CpoException ce) {
329    * 		// Handle the error
330    *  }
331    * }
332    * </code>
333    * </pre>
334    *
335    * @param coll This is a collection of objects that have been defined within the metadata of the datasource. If the
336    *             class is not defined an exception will be thrown.
337    * @return The number of objects created in the datasource
338    * @throws CpoException Thrown if there are errors accessing the datasource
339    */
340   @Override
341   public <T> long insertObjects(Collection<T> coll) throws CpoException {
342     return processUpdateGroup(coll, JdbcCpoAdapter.CREATE_GROUP, null, null, null, null);
343   }
344 
345   /**
346    * Iterates through a collection of Objects, creates and stores them in the datasource. The assumption is that the
347    * objects contained in the collection do not exist in the datasource.
348    * <p/>
349    * This method creates and stores the objects in the datasource. The objects in the collection will be treated as one
350    * transaction, assuming the datasource supports transactions.
351    * <p/>
352    * This means that if one of the objects fail being created in the datasource then the CpoAdapter should stop
353    * processing the remainder of the collection, and if supported, rollback all the objects created thus far.
354    * <p/>
355    * <pre>Example:
356    * <code>
357    * <p/>
358    * class SomeObject so = null;
359    * class CpoAdapter cpo = null;
360    * <p/>
361    * try {
362    * 	cpo = new JdbcCpoAdapter(new JdbcDataSourceInfo(driver, url, user, password,1,1,false));
363    * } catch (CpoException ce) {
364    * 	// Handle the error
365    * 	cpo = null;
366    * }
367    * if (cpo!=null) {
368    * 	ArrayList al = new ArrayList();
369    * 	for (int i=0; i<3; i++){
370    * 		so = new SomeObject();
371    * 		so.setId(1);
372    * 		so.setName("SomeName");
373    * 		al.add(so);
374    *  }
375    * 	try{
376    * 		cpo.insertObjects("IdNameInsert",al);
377    *  } catch (CpoException ce) {
378    * 		// Handle the error
379    *  }
380    * }
381    * </code>
382    * </pre>
383    *
384    * @param name The String name of the CREATE Function Group that will be used to create the object in the datasource.
385    *             null signifies that the default rules will be used.
386    * @param coll This is a collection of objects that have been defined within the metadata of the datasource. If the
387    *             class is not defined an exception will be thrown.
388    * @return The number of objects created in the datasource
389    * @throws CpoException Thrown if there are errors accessing the datasource
390    */
391   @Override
392   public <T> long insertObjects(String name, Collection<T> coll) throws CpoException {
393     return processUpdateGroup(coll, JdbcCpoAdapter.CREATE_GROUP, name, null, null, null);
394   }
395 
396   /**
397    * Iterates through a collection of Objects, creates and stores them in the datasource. The assumption is that the
398    * objects contained in the collection do not exist in the datasource.
399    * <p/>
400    * This method creates and stores the objects in the datasource. The objects in the collection will be treated as one
401    * transaction, assuming the datasource supports transactions.
402    * <p/>
403    * This means that if one of the objects fail being created in the datasource then the CpoAdapter should stop
404    * processing the remainder of the collection, and if supported, rollback all the objects created thus far.
405    * <p/>
406    * <pre>Example:
407    * <code>
408    * <p/>
409    * class SomeObject so = null;
410    * class CpoAdapter cpo = null;
411    * <p/>
412    * try {
413    * 	cpo = new JdbcCpoAdapter(new JdbcDataSourceInfo(driver, url, user, password,1,1,false));
414    * } catch (CpoException ce) {
415    * 	// Handle the error
416    * 	cpo = null;
417    * }
418    * if (cpo!=null) {
419    * 	ArrayList al = new ArrayList();
420    * 	for (int i=0; i<3; i++){
421    * 		so = new SomeObject();
422    * 		so.setId(1);
423    * 		so.setName("SomeName");
424    * 		al.add(so);
425    *  }
426    * 	try{
427    * 		cpo.insertObjects("IdNameInsert",al);
428    *  } catch (CpoException ce) {
429    * 		// Handle the error
430    *  }
431    * }
432    * </code>
433    * </pre>
434    *
435    * @param name              The String name of the CREATE Function Group that will be used to create the object in the datasource.
436    *                          null signifies that the default rules will be used.
437    * @param coll              This is a collection of objects that have been defined within the metadata of the datasource. If the
438    *                          class is not defined an exception will be thrown.
439    * @param wheres            A collection of CpoWhere beans that define the constraints that should be used when retrieving beans
440    * @param orderBy           The CpoOrderBy bean that defines the order in which beans should be returned
441    * @param nativeExpressions Native expression that will be used to augment the expression stored in the meta data. This
442    *                          text will be embedded at run-time
443    * @return The number of objects created in the datasource
444    * @throws CpoException Thrown if there are errors accessing the datasource
445    */
446   @Override
447   public <T> long insertObjects(String name, Collection<T> coll, Collection<CpoWhere> wheres, Collection<CpoOrderBy> orderBy, Collection<CpoNativeFunction> nativeExpressions) throws CpoException {
448     return processUpdateGroup(coll, JdbcCpoAdapter.CREATE_GROUP, name, wheres, orderBy, nativeExpressions);
449   }
450 
451   /**
452    * Removes the Object from the datasource. The assumption is that the object exists in the datasource. This method
453    * stores the object in the datasource
454    * <p/>
455    * <pre>Example:
456    * <code>
457    * <p/>
458    * class SomeObject so = new SomeObject();
459    * class CpoAdapter cpo = null;
460    * <p/>
461    * try {
462    * 	cpo = new JdbcCpoAdapter(new JdbcDataSourceInfo(driver, url, user, password,1,1,false));
463    * } catch (CpoException ce) {
464    * 	// Handle the error
465    * 	cpo = null;
466    * }
467    * <p/>
468    * if (cpo!=null) {
469    * 	so.setId(1);
470    * 	so.setName("SomeName");
471    * 	try{
472    * 		cpo.deleteObject(so);
473    *  } catch (CpoException ce) {
474    * 		// Handle the error
475    *  }
476    * }
477    * </code>
478    * </pre>
479    *
480    * @param obj This is an object that has been defined within the metadata of the datasource. If the class is not
481    *            defined an exception will be thrown. If the object does not exist in the datasource an exception will be thrown.
482    * @return The number of objects deleted from the datasource
483    * @throws CpoException Thrown if there are errors accessing the datasource
484    */
485   @Override
486   public <T> long deleteObject(T obj) throws CpoException {
487     return processUpdateGroup(obj, JdbcCpoAdapter.DELETE_GROUP, null, null, null, null);
488   }
489 
490   /**
491    * Removes the Object from the datasource. The assumption is that the object exists in the datasource. This method
492    * stores the object in the datasource
493    * <p/>
494    * <pre>Example:
495    * <code>
496    * <p/>
497    * class SomeObject so = new SomeObject();
498    * class CpoAdapter cpo = null;
499    * <p/>
500    * try {
501    * 	cpo = new JdbcCpoAdapter(new JdbcDataSourceInfo(driver, url, user, password,1,1,false));
502    * } catch (CpoException ce) {
503    * 	// Handle the error
504    * 	cpo = null;
505    * }
506    * <p/>
507    * if (cpo!=null) {
508    * 	so.setId(1);
509    * 	so.setName("SomeName");
510    * 	try{
511    * 		cpo.deleteObject("DeleteById",so);
512    *  } catch (CpoException ce) {
513    * 	// Handle the error
514    *  }
515    * }
516    * </code>
517    * </pre>
518    *
519    * @param name The String name of the DELETE Function Group that will be used to create the object in the datasource.
520    *             null signifies that the default rules will be used.
521    * @param obj  This is an object that has been defined within the metadata of the datasource. If the class is not
522    *             defined an exception will be thrown. If the object does not exist in the datasource an exception will be thrown.
523    * @return The number of objects deleted from the datasource
524    * @throws CpoException Thrown if there are errors accessing the datasource
525    */
526   @Override
527   public <T> long deleteObject(String name, T obj) throws CpoException {
528     return processUpdateGroup(obj, JdbcCpoAdapter.DELETE_GROUP, name, null, null, null);
529   }
530 
531   /**
532    * Removes the Object from the datasource. The assumption is that the object exists in the datasource. This method
533    * stores the object in the datasource
534    * <p/>
535    * <pre>Example:
536    * <code>
537    * <p/>
538    * class SomeObject so = new SomeObject();
539    * class CpoAdapter cpo = null;
540    * <p/>
541    * try {
542    * 	cpo = new JdbcCpoAdapter(new JdbcDataSourceInfo(driver, url, user, password,1,1,false));
543    * } catch (CpoException ce) {
544    * 	// Handle the error
545    * 	cpo = null;
546    * }
547    * <p/>
548    * if (cpo!=null) {
549    * 	so.setId(1);
550    * 	so.setName("SomeName");
551    * 	try{
552    * 		cpo.deleteObject("DeleteById",so);
553    *  } catch (CpoException ce) {
554    * 	// Handle the error
555    *  }
556    * }
557    * </code>
558    * </pre>
559    *
560    * @param name              The String name of the DELETE Function Group that will be used to create the object in the datasource.
561    *                          null signifies that the default rules will be used.
562    * @param obj               This is an object that has been defined within the metadata of the datasource. If the class is not
563    *                          defined an exception will be thrown. If the object does not exist in the datasource an exception will be thrown.
564    * @param wheres            A collection of CpoWhere beans that define the constraints that should be used when retrieving beans
565    * @param orderBy           The CpoOrderBy bean that defines the order in which beans should be returned
566    * @param nativeExpressions Native expression that will be used to augment the expression stored in the meta data. This
567    *                          text will be embedded at run-time
568    * @return The number of objects deleted from the datasource
569    * @throws CpoException Thrown if there are errors accessing the datasource
570    */
571   @Override
572   public <T> long deleteObject(String name, T obj, Collection<CpoWhere> wheres, Collection<CpoOrderBy> orderBy, Collection<CpoNativeFunction> nativeExpressions) throws CpoException {
573     return processUpdateGroup(obj, JdbcCpoAdapter.DELETE_GROUP, name, wheres, orderBy, nativeExpressions);
574   }
575 
576   /**
577    * Removes the Objects contained in the collection from the datasource. The assumption is that the object exists in
578    * the datasource. This method stores the objects contained in the collection in the datasource. The objects in the
579    * collection will be treated as one transaction, assuming the datasource supports transactions.
580    * <p/>
581    * This means that if one of the objects fail being deleted in the datasource then the CpoAdapter should stop
582    * processing the remainder of the collection, and if supported, rollback all the objects deleted thus far.
583    * <p/>
584    * <pre>Example:
585    * <code>
586    * <p/>
587    * class SomeObject so = null;
588    * class CpoAdapter cpo = null;
589    * <p/>
590    * try {
591    * 	cpo = new JdbcCpoAdapter(new JdbcDataSourceInfo(driver, url, user, password,1,1,false));
592    * } catch (CpoException ce) {
593    * 	// Handle the error
594    * 	cpo = null;
595    * }
596    * <p/>
597    * if (cpo!=null) {
598    * 	ArrayList al = new ArrayList();
599    * 	for (int i=0; i<3; i++){
600    * 		so = new SomeObject();
601    * 		so.setId(1);
602    * 		so.setName("SomeName");
603    * 		al.add(so);
604    *  }
605    * 	try{
606    * 		cpo.deleteObjects(al);
607    *  } catch (CpoException ce) {
608    * 		// Handle the error
609    *  }
610    * }
611    * </code>
612    * </pre>
613    *
614    * @param coll This is a collection of objects that have been defined within the metadata of the datasource. If the
615    *             class is not defined an exception will be thrown.
616    * @return The number of objects deleted from the datasource
617    * @throws CpoException Thrown if there are errors accessing the datasource
618    */
619   @Override
620   public <T> long deleteObjects(Collection<T> coll) throws CpoException {
621     return processUpdateGroup(coll, JdbcCpoAdapter.DELETE_GROUP, null, null, null, null);
622   }
623 
624   /**
625    * Removes the Objects contained in the collection from the datasource. The assumption is that the object exists in
626    * the datasource. This method stores the objects contained in the collection in the datasource. The objects in the
627    * collection will be treated as one transaction, assuming the datasource supports transactions.
628    * <p/>
629    * This means that if one of the objects fail being deleted in the datasource then the CpoAdapter should stop
630    * processing the remainder of the collection, and if supported, rollback all the objects deleted thus far.
631    * <p/>
632    * <pre>Example:
633    * <code>
634    * <p/>
635    * class SomeObject so = null;
636    * class CpoAdapter cpo = null;
637    * <p/>
638    * try {
639    * 	cpo = new JdbcCpoAdapter(new JdbcDataSourceInfo(driver, url, user, password,1,1,false));
640    * } catch (CpoException ce) {
641    * 	// Handle the error
642    * 	cpo = null;
643    * }
644    * <p/>
645    * if (cpo!=null) {
646    * 	ArrayList al = new ArrayList();
647    * 	for (int i=0; i<3; i++){
648    * 		so = new SomeObject();
649    * 		so.setId(1);
650    * 		so.setName("SomeName");
651    * 		al.add(so);
652    *  }
653    * <p/>
654    * 	try{
655    * 		cpo.deleteObjects("IdNameDelete",al);
656    *  } catch (CpoException ce) {
657    * 		// Handle the error
658    *  }
659    * }
660    * </code>
661    * </pre>
662    *
663    * @param name The String name of the DELETE Function Group that will be used to create the object in the datasource.
664    *             null signifies that the default rules will be used.
665    * @param coll This is a collection of objects that have been defined within the metadata of the datasource. If the
666    *             class is not defined an exception will be thrown.
667    * @return The number of objects deleted from the datasource
668    * @throws CpoException Thrown if there are errors accessing the datasource
669    */
670   @Override
671   public <T> long deleteObjects(String name, Collection<T> coll) throws CpoException {
672     return processUpdateGroup(coll, JdbcCpoAdapter.DELETE_GROUP, name, null, null, null);
673   }
674 
675   /**
676    * Removes the Objects contained in the collection from the datasource. The assumption is that the object exists in
677    * the datasource. This method stores the objects contained in the collection in the datasource. The objects in the
678    * collection will be treated as one transaction, assuming the datasource supports transactions.
679    * <p/>
680    * This means that if one of the objects fail being deleted in the datasource then the CpoAdapter should stop
681    * processing the remainder of the collection, and if supported, rollback all the objects deleted thus far.
682    * <p/>
683    * <pre>Example:
684    * <code>
685    * <p/>
686    * class SomeObject so = null;
687    * class CpoAdapter cpo = null;
688    * <p/>
689    * try {
690    * 	cpo = new JdbcCpoAdapter(new JdbcDataSourceInfo(driver, url, user, password,1,1,false));
691    * } catch (CpoException ce) {
692    * 	// Handle the error
693    * 	cpo = null;
694    * }
695    * <p/>
696    * if (cpo!=null) {
697    * 	ArrayList al = new ArrayList();
698    * 	for (int i=0; i<3; i++){
699    * 		so = new SomeObject();
700    * 		so.setId(1);
701    * 		so.setName("SomeName");
702    * 		al.add(so);
703    *  }
704    * <p/>
705    * 	try{
706    * 		cpo.deleteObjects("IdNameDelete",al);
707    *  } catch (CpoException ce) {
708    * 		// Handle the error
709    *  }
710    * }
711    * </code>
712    * </pre>
713    *
714    * @param name              The String name of the DELETE Function Group that will be used to create the object in the datasource.
715    *                          null signifies that the default rules will be used.
716    * @param coll              This is a collection of objects that have been defined within the metadata of the datasource. If the
717    *                          class is not defined an exception will be thrown.
718    * @param wheres            A collection of CpoWhere beans that define the constraints that should be used when retrieving beans
719    * @param orderBy           The CpoOrderBy bean that defines the order in which beans should be returned
720    * @param nativeExpressions Native expression that will be used to augment the expression stored in the meta data. This
721    *                          text will be embedded at run-time
722    * @return The number of objects deleted from the datasource
723    * @throws CpoException Thrown if there are errors accessing the datasource
724    */
725   @Override
726   public <T> long deleteObjects(String name, Collection<T> coll, Collection<CpoWhere> wheres, Collection<CpoOrderBy> orderBy, Collection<CpoNativeFunction> nativeExpressions) throws CpoException {
727     return processUpdateGroup(coll, JdbcCpoAdapter.DELETE_GROUP, name, wheres, orderBy, nativeExpressions);
728   }
729 
730   /**
731    * Executes an Object whose metadata will call an executable within the datasource. It is assumed that the executable
732    * object exists in the metadatasource. If the executable does not exist, an exception will be thrown.
733    * <p/>
734    * <pre>Example:
735    * <code>
736    * <p/>
737    * class SomeObject so = new SomeObject();
738    * class CpoAdapter cpo = null;
739    * <p/>
740    * try {
741    * 	cpo = new JdbcCpoAdapter(new JdbcDataSourceInfo(driver, url, user, password,1,1,false));
742    * } catch (CpoException ce) {
743    * 	// Handle the error
744    * 	cpo = null;
745    * }
746    * <p/>
747    * if (cpo!=null) {
748    * 	so.setId(1);
749    * 	so.setName("SomeName");
750    * 	try{
751    * 		cpo.executeObject(so);
752    *  } catch (CpoException ce) {
753    * 		// Handle the error
754    *  }
755    * }
756    * </code>
757    * </pre>
758    *
759    * @param object This is an Object that has been defined within the metadata of the datasource. If the class is not
760    *               defined an exception will be thrown. If the object does not exist in the datasource, an exception will be thrown.
761    *               This object is used to populate the IN arguments used to executed the datasource object.
762    *               <p/>
763    *               An object of this type will be created and filled with the returned data from the value_object. This newly created
764    *               object will be returned from this method.
765    * @return An object populated with the OUT arguments returned from the executable object
766    * @throws CpoException Thrown if there are errors accessing the datasource
767    */
768   @Override
769   public <T> T executeObject(T object) throws CpoException {
770     return processExecuteGroup(null, object, object);
771   }
772 
773   /**
774    * Executes an Object whose metadata will call an executable within the datasource. It is assumed that the executable
775    * object exists in the metadatasource. If the executable does not exist, an exception will be thrown.
776    * <p/>
777    * <pre>Example:
778    * <code>
779    * <p/>
780    * class SomeObject so = new SomeObject();
781    * class CpoAdapter cpo = null;
782    * <p/>
783    * try {
784    * 	cpo = new JdbcCpoAdapter(new JdbcDataSourceInfo(driver, url, user, password,1,1,false));
785    * } catch (CpoException ce) {
786    * 	// Handle the error
787    * 	cpo = null;
788    * }
789    * <p/>
790    * if (cpo!=null) {
791    * 	so.setId(1);
792    * 	so.setName("SomeName");
793    * 	try{
794    * 		cpo.executeObject("execNotifyProc",so);
795    *  } catch (CpoException ce) {
796    * 	// Handle the error
797    *  }
798    * }
799    * </code>
800    * </pre>
801    *
802    * @param name   The filter name which tells the datasource which objects should be returned. The name also signifies
803    *               what data in the object will be populated.
804    * @param object This is an object that has been defined within the metadata of the datasource. If the class is not
805    *               defined an exception will be thrown. If the object does not exist in the datasource, an exception will be thrown.
806    *               This object is used to populate the IN arguments used to retrieve the collection of objects. This object defines
807    *               the object type that will be returned in the collection and contain the result set data or the OUT Parameters.
808    * @return A result object populate with the OUT arguments
809    * @throws CpoException if there are errors accessing the datasource
810    */
811   @Override
812   public <T> T executeObject(String name, T object) throws CpoException {
813     return processExecuteGroup(name, object, object);
814   }
815 
816   /**
817    * Executes an Object that represents an executable object within the datasource. It is assumed that the object exists
818    * in the datasource. If the object does not exist, an exception will be thrown
819    * <p/>
820    * <pre>Example:
821    * <code>
822    * <p/>
823    * class SomeObject so = new SomeObject();
824    * class SomeResult sr = new SomeResult();
825    * class CpoAdapter cpo = null;
826    * <p/>
827    * try {
828    * 	cpo = new JdbcCpoAdapter(new JdbcDataSourceInfo(driver, url, user, password,1,1,false));
829    * } catch (CpoException ce) {
830    * 	// Handle the error
831    * 	cpo = null;
832    * }
833    * <p/>
834    * if (cpo!=null) {
835    * 	so.setId(1);
836    * 	so.setName("SomeName");
837    * 	try{
838    * 		sr = (SomeResult)cpo.executeObject("execNotifyProc",so, sr);
839    *  } catch (CpoException ce) {
840    * 		// Handle the error
841    *  }
842    * }
843    * </code>
844    * </pre>
845    *
846    * @param name     The String name of the EXECUTE Function Group that will be used to create the object in the datasource.
847    *                 null signifies that the default rules will be used.
848    * @param criteria This is an object that has been defined within the metadata of the datasource. If the class is not
849    *                 defined an exception will be thrown. If the object does not exist in the datasource, an exception will be thrown.
850    *                 This object is used to populate the IN arguments used to retrieve the collection of objects.
851    * @param result   This is an object that has been defined within the metadata of the datasource. If the class is not
852    *                 defined an exception will be thrown. If the object does not exist in the datasource, an exception will be thrown.
853    *                 This object defines the object type that will be created, filled with the return data and returned from this
854    *                 method.
855    * @return An object populated with the out arguments
856    * @throws CpoException Thrown if there are errors accessing the datasource
857    */
858   @Override
859   public <T, C> T executeObject(String name, C criteria, T result) throws CpoException {
860     return processExecuteGroup(name, criteria, result);
861   }
862 
863   /**
864    * The CpoAdapter will check to see if this object exists in the datasource.
865    * <p/>
866    * <pre>Example:
867    * <code>
868    * <p/>
869    * class SomeObject so = new SomeObject();
870    * long count = 0;
871    * class CpoAdapter cpo = null;
872    * <p/>
873    * try {
874    * 	cpo = new JdbcCpoAdapter(new JdbcDataSourceInfo(driver, url, user, password,1,1,false));
875    * } catch (CpoException ce) {
876    * 	// Handle the error
877    * 	cpo = null;
878    * }
879    * <p/>
880    * if (cpo!=null) {
881    * 	so.setId(1);
882    * 	so.setName("SomeName");
883    * 	try{
884    * 		count = cpo.existsObject(so);
885    * 		if (count>0) {
886    * 			// object exists
887    *    } else {
888    * 			// object does not exist
889    *    }
890    *  } catch (CpoException ce) {
891    * 		// Handle the error
892    *  }
893    * }
894    * </code>
895    * </pre>
896    *
897    * @param obj This is an object that has been defined within the metadata of the datasource. If the class is not
898    *            defined an exception will be thrown. This object will be searched for inside the datasource.
899    * @return The number of objects that exist in the datasource that match the specified object
900    * @throws CpoException Thrown if there are errors accessing the datasource
901    */
902   @Override
903   public <T> long existsObject(T obj) throws CpoException {
904     return this.existsObject(null, obj);
905   }
906 
907   /**
908    * The CpoAdapter will check to see if this object exists in the datasource.
909    * <p/>
910    * <pre>Example:
911    * <code>
912    * <p/>
913    * class SomeObject so = new SomeObject();
914    * long count = 0;
915    * class CpoAdapter cpo = null;
916    * <p/>
917    * try {
918    * 	cpo = new JdbcCpoAdapter(new JdbcDataSourceInfo(driver, url, user, password,1,1,false));
919    * } catch (CpoException ce) {
920    * 	// Handle the error
921    * 	cpo = null;
922    * }
923    * <p/>
924    * if (cpo!=null) {
925    * 	so.setId(1);
926    * 	so.setName("SomeName");
927    * 	try{
928    * 		count = cpo.existsObject("SomeExistCheck",so);
929    * 		if (count>0) {
930    * 			// object exists
931    *    } else {
932    * 			// object does not exist
933    *    }
934    *  } catch (CpoException ce) {
935    * 		// Handle the error
936    *  }
937    * }
938    * </code>
939    * </pre>
940    *
941    * @param name The String name of the EXISTS Function Group that will be used to create the object in the datasource.
942    *             null signifies that the default rules will be used.
943    * @param obj  This is an object that has been defined within the metadata of the datasource. If the class is not
944    *             defined an exception will be thrown. This object will be searched for inside the datasource.
945    * @return The number of objects that exist in the datasource that match the specified object
946    * @throws CpoException Thrown if there are errors accessing the datasource
947    */
948   @Override
949   public <T> long existsObject(String name, T obj) throws CpoException {
950     return this.existsObject(name, obj, null);
951   }
952 
953   /**
954    * The CpoAdapter will check to see if this object exists in the datasource.
955    * <p/>
956    * <pre>Example:
957    * <code>
958    * <p/>
959    * class SomeObject so = new SomeObject();
960    * long count = 0;
961    * class CpoAdapter cpo = null;
962    * <p/>
963    * <p/>
964    *  try {
965    *    cpo = new JdbcCpoAdapter(new JdbcDataSourceInfo(driver, url, user, password,1,1,false));
966    *  } catch (CpoException ce) {
967    *    // Handle the error
968    *    cpo = null;
969    *  }
970    * <p/>
971    *  if (cpo!=null) {
972    *    so.setId(1);
973    *    so.setName("SomeName");
974    *    try{
975    *      CpoWhere where = cpo.newCpoWhere(CpoWhere.LOGIC_NONE, id, CpoWhere.COMP_EQ);
976    *      count = cpo.existsObject("SomeExistCheck",so, where);
977    *      if (count>0) {
978    *        // object exists
979    *      } else {
980    *        // object does not exist
981    *      }
982    *    } catch (CpoException ce) {
983    *      // Handle the error
984    *    }
985    *  }
986    * </code>
987    * </pre>
988    *
989    * @param name   The String name of the EXISTS Function Group that will be used to create the object in the datasource.
990    *               null signifies that the default rules will be used.
991    * @param obj    This is an object that has been defined within the metadata of the datasource. If the class is not
992    *               defined an exception will be thrown. This object will be searched for inside the datasource.
993    * @param wheres A CpoWhere object that passes in run-time constraints to the function that performs the the exist
994    * @return The number of objects that exist in the datasource that match the specified object
995    * @throws CpoException Thrown if there are errors accessing the datasource
996    */
997   @Override
998   public <T> long existsObject(String name, T obj, Collection<CpoWhere> wheres) throws CpoException {
999     Connection c = null;
1000     long objCount = -1;
1001 
1002     try {
1003       c = getReadConnection();
1004 
1005       objCount = existsObject(name, obj, c, wheres);
1006     } catch (Exception e) {
1007       throw new CpoException("existsObjects(String, Object) failed", e);
1008     } finally {
1009       closeConnection(c);
1010     }
1011 
1012     return objCount;
1013   }
1014 
1015   /**
1016    * The CpoAdapter will check to see if this object exists in the datasource.
1017    *
1018    * @param name The name which identifies which EXISTS, INSERT, and UPDATE Function Groups to execute to persist the
1019    *             object.
1020    * @param obj  This is an object that has been defined within the metadata of the datasource. If the class is not
1021    *             defined an exception will be thrown.
1022    * @param con  The datasource Connection with which to check if the object exists
1023    * @return The int value of the first column returned in the record set
1024    * @throws CpoException exception will be thrown if the Function Group has a function count != 1
1025    */
1026   protected <T> long existsObject(String name, T obj, Connection con, Collection<CpoWhere> wheres) throws CpoException {
1027     PreparedStatement ps = null;
1028     ResultSet rs = null;
1029     ResultSetMetaData rsmd;
1030     CpoClass cpoClass;
1031     long objCount = 0;
1032     Logger localLogger = logger;
1033 
1034     if (obj == null) {
1035       throw new CpoException("NULL Object passed into existsObject");
1036     }
1037 
1038     try {
1039       cpoClass = metaDescriptor.getMetaClass(obj);
1040       List<CpoFunction> cpoFunctions = cpoClass.getFunctionGroup(JdbcCpoAdapter.EXIST_GROUP, name).getFunctions();
1041       localLogger = LoggerFactory.getLogger(cpoClass.getMetaClass());
1042 
1043       for (CpoFunction cpoFunction : cpoFunctions) {
1044         localLogger.info(cpoFunction.getExpression());
1045         JdbcPreparedStatementFactory jpsf = new JdbcPreparedStatementFactory(con, this, cpoClass, cpoFunction, obj, wheres, null, null);
1046         ps = jpsf.getPreparedStatement();
1047 
1048         long qCount = 0; // set the results for this function to 0
1049 
1050         rs = ps.executeQuery();
1051         jpsf.release();
1052         rsmd = rs.getMetaData();
1053 
1054         // see if they are using the count(*) logic
1055         if (rsmd.getColumnCount() == 1) {
1056           if (rs.next()) {
1057             try {
1058               qCount = rs.getLong(1); // get the number of objects
1059               // that exist
1060             } catch (Exception e) {
1061               // Exists result not an int so bail to record counter
1062               qCount = 1;
1063             }
1064             if (rs.next()) {
1065               // EXIST function has more than one record so not a count(*)
1066               qCount = 2;
1067             }
1068           }
1069         }
1070 
1071         while (rs.next()) {
1072           qCount++;
1073         }
1074 
1075         objCount += qCount;
1076 
1077         rs.close();
1078         ps.close();
1079         rs = null;
1080         ps = null;
1081       }
1082     } catch (SQLException e) {
1083       String msg = "existsObject(name, obj, con) failed:";
1084       localLogger.error(msg, e);
1085       throw new CpoException(msg, e);
1086     } finally {
1087       resultSetClose(rs);
1088       statementClose(ps);
1089     }
1090 
1091     return objCount;
1092   }
1093 
1094   /**
1095    * newOrderBy allows you to dynamically change the order of the objects in the resulting collection. This allows you
1096    * to apply user input in determining the order of the collection
1097    *
1098    * @param attribute The name of the attribute from the pojo that will be sorted.
1099    * @param ascending If true, sort ascending. If false sort descending.
1100    * @return A CpoOrderBy object to be passed into retrieveBeans.
1101    * @throws CpoException Thrown if there are errors accessing the datasource
1102    */
1103   @Override
1104   public CpoOrderBy newOrderBy(String attribute, boolean ascending) throws CpoException {
1105     return new BindableCpoOrderBy(attribute, ascending);
1106   }
1107 
1108   /**
1109    * newOrderBy allows you to dynamically change the order of the objects in the resulting collection. This allows you
1110    * to apply user input in determining the order of the collection
1111    *
1112    * @param marker    the marker that will be replaced in the expression with the string representation of this orderBy
1113    * @param attribute The name of the attribute from the pojo that will be sorted.
1114    * @param ascending If true, sort ascending. If false sort descending.
1115    * @return A CpoOrderBy object to be passed into retrieveBeans.
1116    * @throws CpoException Thrown if there are errors accessing the datasource
1117    */
1118   @Override
1119   public CpoOrderBy newOrderBy(String marker, String attribute, boolean ascending) throws CpoException {
1120     return new BindableCpoOrderBy(marker, attribute, ascending);
1121   }
1122 
1123   /**
1124    * newOrderBy allows you to dynamically change the order of the objects in the resulting collection. This allows you
1125    * to apply user input in determining the order of the collection
1126    *
1127    * @param attribute The name of the attribute from the pojo that will be sorted.
1128    * @param ascending If true, sort ascending. If false sort descending.
1129    * @param function  A string which represents a datasource function that will be called on the attribute. must be
1130    *                  contained in the function string. The attribute name will be replaced at run-time with its datasource counterpart
1131    * @return A CpoOrderBy object to be passed into retrieveBeans.
1132    * @throws CpoException Thrown if there are errors accessing the datasource
1133    */
1134   @Override
1135   public CpoOrderBy newOrderBy(String attribute, boolean ascending, String function) throws CpoException {
1136     return new BindableCpoOrderBy(attribute, ascending, function);
1137   }
1138 
1139   /**
1140    * newOrderBy allows you to dynamically change the order of the objects in the resulting collection. This allows you
1141    * to apply user input in determining the order of the collection
1142    *
1143    * @param marker    the marker that will be replaced in the expression with the string representation of this orderBy
1144    * @param attribute The name of the attribute from the pojo that will be sorted.
1145    * @param ascending If true, sort ascending. If false sort descending.
1146    * @param function  A string which represents a datasource function that will be called on the attribute. must be
1147    *                  contained in the function string. The attribute name will be replaced at run-time with its datasource counterpart
1148    * @return A CpoOrderBy object to be passed into retrieveBeans.
1149    * @throws CpoException Thrown if there are errors accessing the datasource
1150    */
1151   @Override
1152   public CpoOrderBy newOrderBy(String marker, String attribute, boolean ascending, String function) throws CpoException {
1153     return new BindableCpoOrderBy(marker, attribute, ascending, function);
1154   }
1155 
1156   /**
1157    * DOCUMENT ME!
1158    *
1159    * @return DOCUMENT ME!
1160    * @throws CpoException DOCUMENT ME!
1161    */
1162   @Override
1163   public CpoWhere newWhere() throws CpoException {
1164     return new JdbcCpoWhere();
1165   }
1166 
1167   /**
1168    * DOCUMENT ME!
1169    *
1170    * @param logical DOCUMENT ME!
1171    * @param attr    DOCUMENT ME!
1172    * @param comp    DOCUMENT ME!
1173    * @param value   DOCUMENT ME!
1174    * @return DOCUMENT ME!
1175    * @throws CpoException DOCUMENT ME!
1176    */
1177   @Override
1178   public <T> CpoWhere newWhere(int logical, String attr, int comp, T value) throws CpoException {
1179     return new JdbcCpoWhere(logical, attr, comp, value);
1180   }
1181 
1182   /**
1183    * DOCUMENT ME!
1184    *
1185    * @param logical DOCUMENT ME!
1186    * @param attr    DOCUMENT ME!
1187    * @param comp    DOCUMENT ME!
1188    * @param value   DOCUMENT ME!
1189    * @param not     DOCUMENT ME!
1190    * @return DOCUMENT ME!
1191    * @throws CpoException DOCUMENT ME!
1192    */
1193   @Override
1194   public <T> CpoWhere newWhere(int logical, String attr, int comp, T value, boolean not) throws CpoException {
1195     return new JdbcCpoWhere(logical, attr, comp, value, not);
1196   }
1197 
1198   /**
1199    * Persists the Object into the datasource. The CpoAdapter will check to see if this object exists in the datasource.
1200    * If it exists, the object is updated in the datasource If the object does not exist, then it is created in the
1201    * datasource. This method stores the object in the datasource. This method uses the default EXISTS, CREATE, and
1202    * UPDATE Function Groups specified for this object.
1203    * <p/>
1204    * <pre>Example:
1205    * <code>
1206    * <p/>
1207    * class SomeObject so = new SomeObject();
1208    * class CpoAdapter cpo = null;
1209    * <p/>
1210    * try {
1211    * 	cpo = new JdbcCpoAdapter(new JdbcDataSourceInfo(driver, url, user, password,1,1,false));
1212    * } catch (CpoException ce) {
1213    * 	// Handle the error
1214    * 	cpo = null;
1215    * }
1216    * <p/>
1217    * if (cpo!=null) {
1218    * 	so.setId(1);
1219    * 	so.setName("SomeName");
1220    * 	try{
1221    * 		cpo.persistObject(so);
1222    *  } catch (CpoException ce) {
1223    * 		// Handle the error
1224    *  }
1225    * }
1226    * </code>
1227    * </pre>
1228    *
1229    * @param obj This is an object that has been defined within the metadata of the datasource. If the class is not
1230    *            defined an exception will be thrown.
1231    * @return A count of the number of objects persisted
1232    * @throws CpoException Thrown if there are errors accessing the datasource
1233    * @see #existsObject
1234    * @see #insertObject
1235    * @see #updateObject
1236    */
1237   @Override
1238   public <T> long persistObject(T obj) throws CpoException {
1239     return processUpdateGroup(obj, JdbcCpoAdapter.PERSIST_GROUP, null, null, null, null);
1240   }
1241 
1242   /**
1243    * Persists the Object into the datasource. The CpoAdapter will check to see if this object exists in the datasource.
1244    * If it exists, the object is updated in the datasource If the object does not exist, then it is created in the
1245    * datasource. This method stores the object in the datasource.
1246    * <p/>
1247    * <pre>Example:
1248    * <code>
1249    * <p/>
1250    * class SomeObject so = new SomeObject();
1251    * class CpoAdapter cpo = null;
1252    * <p/>
1253    * try {
1254    * 	cpo = new JdbcCpoAdapter(new JdbcDataSourceInfo(driver, url, user, password,1,1,false));
1255    * } catch (CpoException ce) {
1256    * 	// Handle the error
1257    * 	cpo = null;
1258    * }
1259    * <p/>
1260    * if (cpo!=null) {
1261    * 	so.setId(1);
1262    * 	so.setName("SomeName");
1263    * 	try{
1264    * 		cpo.persistObject("persistSomeObject",so);
1265    *  } catch (CpoException ce) {
1266    * 		// Handle the error
1267    *  }
1268    * }
1269    * </code>
1270    * </pre>
1271    *
1272    * @param name The name which identifies which EXISTS, INSERT, and UPDATE Function Groups to execute to persist the
1273    *             object.
1274    * @param obj  This is an object that has been defined within the metadata of the datasource. If the class is not
1275    *             defined an exception will be thrown.
1276    * @return A count of the number of objects persisted
1277    * @throws CpoException Thrown if there are errors accessing the datasource
1278    * @see #existsObject
1279    * @see #insertObject
1280    * @see #updateObject
1281    */
1282   @Override
1283   public <T> long persistObject(String name, T obj) throws CpoException {
1284     return processUpdateGroup(obj, JdbcCpoAdapter.PERSIST_GROUP, name, null, null, null);
1285   }
1286 
1287   /**
1288    * Persists a collection of Objects into the datasource. The CpoAdapter will check to see if this object exists in the
1289    * datasource. If it exists, the object is updated in the datasource If the object does not exist, then it is created
1290    * in the datasource. This method stores the object in the datasource. The objects in the collection will be treated
1291    * as one transaction, meaning that if one of the objects fail being inserted or updated in the datasource then the
1292    * entire collection will be rolled back.
1293    * <p/>
1294    * <pre>Example:
1295    * <code>
1296    * <p/>
1297    * class SomeObject so = null;
1298    * class CpoAdapter cpo = null;
1299    * <p/>
1300    * try {
1301    * 	cpo = new JdbcCpoAdapter(new JdbcDataSourceInfo(driver, url, user, password,1,1,false));
1302    * } catch (CpoException ce) {
1303    * 	// Handle the error
1304    * 	cpo = null;
1305    * }
1306    * <p/>
1307    * if (cpo!=null) {
1308    * 	ArrayList al = new ArrayList();
1309    * 	for (int i=0; i<3; i++){
1310    * 		so = new SomeObject();
1311    * 		so.setId(1);
1312    * 		so.setName("SomeName");
1313    * 		al.add(so);
1314    *  }
1315    * 	try{
1316    * 		cpo.persistObjects(al);
1317    *  } catch (CpoException ce) {
1318    * 		// Handle the error
1319    *  }
1320    * }
1321    * </code>
1322    * </pre>
1323    *
1324    * @param coll This is a collection of objects that have been defined within the metadata of the datasource. If the
1325    *             class is not defined an exception will be thrown.
1326    * @return DOCUMENT ME!
1327    * @throws CpoException Thrown if there are errors accessing the datasource
1328    * @see #existsObject
1329    * @see #insertObject
1330    * @see #updateObject
1331    */
1332   @Override
1333   public <T> long persistObjects(Collection<T> coll) throws CpoException {
1334     return processUpdateGroup(coll, JdbcCpoAdapter.PERSIST_GROUP, null, null, null, null);
1335   }
1336 
1337   /**
1338    * Persists a collection of Objects into the datasource. The CpoAdapter will check to see if this object exists in the
1339    * datasource. If it exists, the object is updated in the datasource If the object does not exist, then it is created
1340    * in the datasource. This method stores the object in the datasource. The objects in the collection will be treated
1341    * as one transaction, meaning that if one of the objects fail being inserted or updated in the datasource then the
1342    * entire collection will be rolled back.
1343    * <p/>
1344    * <pre>Example:
1345    * <code>
1346    * <p/>
1347    * class SomeObject so = null;
1348    * class CpoAdapter cpo = null;
1349    * <p/>
1350    * try {
1351    * 	cpo = new JdbcCpoAdapter(new JdbcDataSourceInfo(driver, url, user, password,1,1,false));
1352    * } catch (CpoException ce) {
1353    * 	// Handle the error
1354    * 	cpo = null;
1355    * }
1356    * <p/>
1357    * if (cpo!=null) {
1358    * 	ArrayList al = new ArrayList();
1359    * 	for (int i=0; i<3; i++){
1360    * 		so = new SomeObject();
1361    * 		so.setId(1);
1362    * 		so.setName("SomeName");
1363    * 		al.add(so);
1364    *  }
1365    * 	try{
1366    * 		cpo.persistObjects("myPersist",al);
1367    *  } catch (CpoException ce) {
1368    * 		// Handle the error
1369    *  }
1370    * }
1371    * </code>
1372    * </pre>
1373    *
1374    * @param name The name which identifies which EXISTS, INSERT, and UPDATE Function Groups to execute to persist the
1375    *             object.
1376    * @param coll This is a collection of objects that have been defined within the metadata of the datasource. If the
1377    *             class is not defined an exception will be thrown.
1378    * @return DOCUMENT ME!
1379    * @throws CpoException Thrown if there are errors accessing the datasource
1380    * @see #existsObject
1381    * @see #insertObject
1382    * @see #updateObject
1383    */
1384   @Override
1385   public <T> long persistObjects(String name, Collection<T> coll) throws CpoException {
1386     return processUpdateGroup(coll, JdbcCpoAdapter.PERSIST_GROUP, name, null, null, null);
1387   }
1388 
1389   /**
1390    * Retrieves the bean from the datasource. The assumption is that the bean exists in the datasource. If the retrieve
1391    * function defined for this beans returns more than one row, an exception will be thrown.
1392    *
1393    * @param bean This is an bean that has been defined within the metadata of the datasource. If the class is not
1394    *             defined an exception will be thrown. If the bean does not exist in the datasource, an exception will be thrown. The
1395    *             input bean is used to specify the search criteria, the output bean is populated with the results of the function.
1396    * @return An bean of the same type as the result argument that is filled in as specified the metadata for the
1397    *         retireve.
1398    * @throws CpoException Thrown if there are errors accessing the datasource
1399    */
1400   @Override
1401   public <T> T retrieveBean(T bean) throws CpoException {
1402     return processSelectGroup(bean, null, null, null, null);
1403   }
1404 
1405   /**
1406    * Retrieves the bean from the datasource. The assumption is that the bean exists in the datasource. If the retrieve
1407    * function defined for this beans returns more than one row, an exception will be thrown.
1408    *
1409    * @param name DOCUMENT ME!
1410    * @param bean This is an bean that has been defined within the metadata of the datasource. If the class is not
1411    *             defined an exception will be thrown. If the bean does not exist in the datasource, an exception will be thrown. The
1412    *             input bean is used to specify the search criteria, the output bean is populated with the results of the function.
1413    * @return An bean of the same type as the result argument that is filled in as specified the metadata for the
1414    *         retireve.
1415    * @throws CpoException Thrown if there are errors accessing the datasource
1416    */
1417   @Override
1418   public <T> T retrieveBean(String name, T bean) throws CpoException {
1419     return processSelectGroup(bean, name, null, null, null);
1420   }
1421 
1422   /**
1423    * Retrieves the bean from the datasource. The assumption is that the bean exists in the datasource. If the retrieve
1424    * function defined for this beans returns more than one row, an exception will be thrown.
1425    *
1426    * @param name              DOCUMENT ME!
1427    * @param bean              This is an bean that has been defined within the metadata of the datasource. If the class is not
1428    *                          defined an exception will be thrown. If the bean does not exist in the datasource, an exception will be thrown. The
1429    *                          input bean is used to specify the search criteria, the output bean is populated with the results of the function.
1430    * @param wheres            A collection of CpoWhere beans that define the constraints that should be used when retrieving beans
1431    * @param orderBy           The CpoOrderBy bean that defines the order in which beans should be returned
1432    * @param nativeExpressions Native expression that will be used to augment the expression stored in the meta data. This
1433    *                          text will be embedded at run-time
1434    * @return An bean of the same type as the result argument that is filled in as specified the metadata for the
1435    *         retireve.
1436    * @throws CpoException Thrown if there are errors accessing the datasource
1437    */
1438   @Override
1439   public <T> T retrieveBean(String name, T bean, Collection<CpoWhere> wheres, Collection<CpoOrderBy> orderBy, Collection<CpoNativeFunction> nativeExpressions) throws CpoException {
1440     return processSelectGroup(bean, name, wheres, orderBy, nativeExpressions);
1441   }
1442 
1443   /**
1444    * Retrieves the bean from the datasource. The assumption is that the bean exists in the datasource. If the retrieve
1445    * function defined for this beans returns more than one row, an exception will be thrown.
1446    *
1447    * @param name     The filter name which tells the datasource which beans should be returned. The name also signifies what
1448    *                 data in the bean will be populated.
1449    * @param criteria This is an bean that has been defined within the metadata of the datasource. If the class is not
1450    *                 defined an exception will be thrown. If the bean does not exist in the datasource, an exception will be thrown.
1451    *                 This bean is used to specify the arguments used to retrieve the collection of beans.
1452    * @param result   This is an bean that has been defined within the metadata of the datasource. If the class is not
1453    *                 defined an exception will be thrown. If the bean does not exist in the datasource, an exception will be thrown.
1454    *                 This bean is used to specify the bean type that will be returned in the collection.
1455    * @param wheres   A collection of CpoWhere beans that define the constraints that should be used when retrieving beans
1456    * @param orderBy  The CpoOrderBy bean that defines the order in which beans should be returned
1457    * @return An bean of the same type as the result argument that is filled in as specified the metadata for the
1458    *         retireve.
1459    * @throws CpoException Thrown if there are errors accessing the datasource
1460    */
1461   @Override
1462   public <T, C> T retrieveBean(String name, C criteria, T result, Collection<CpoWhere> wheres, Collection<CpoOrderBy> orderBy) throws CpoException {
1463     return retrieveBean(name, criteria, result, wheres, orderBy, null);
1464   }
1465 
1466   /**
1467    * Retrieves the bean from the datasource. The assumption is that the bean exists in the datasource. If the retrieve
1468    * function defined for this beans returns more than one row, an exception will be thrown.
1469    *
1470    * @param name              The filter name which tells the datasource which beans should be returned. The name also signifies what
1471    *                          data in the bean will be populated.
1472    * @param criteria          This is an bean that has been defined within the metadata of the datasource. If the class is not
1473    *                          defined an exception will be thrown. If the bean does not exist in the datasource, an exception will be thrown.
1474    *                          This bean is used to specify the arguments used to retrieve the collection of beans.
1475    * @param result            This is an bean that has been defined within the metadata of the datasource. If the class is not
1476    *                          defined an exception will be thrown. If the bean does not exist in the datasource, an exception will be thrown.
1477    *                          This bean is used to specify the bean type that will be returned in the collection.
1478    * @param wheres            A collection of CpoWhere beans that define the constraints that should be used when retrieving beans
1479    * @param orderBy           The CpoOrderBy bean that defines the order in which beans should be returned
1480    * @param nativeExpressions Native expression that will be used to augment the expression stored in the meta data. This
1481    *                          text will be embedded at run-time
1482    * @return An bean of the same type as the result argument that is filled in as specified the metadata for the
1483    *         retireve.
1484    * @throws CpoException Thrown if there are errors accessing the datasource
1485    */
1486   @Override
1487   public <T, C> T retrieveBean(String name, C criteria, T result, Collection<CpoWhere> wheres, Collection<CpoOrderBy> orderBy, Collection<CpoNativeFunction> nativeExpressions) throws CpoException {
1488     Iterator<T> it = processSelectGroup(name, criteria, result, wheres, orderBy, nativeExpressions, true).iterator();
1489     if (it.hasNext()) {
1490       return it.next();
1491     } else {
1492       return null;
1493     }
1494   }
1495 
1496   /**
1497    * Retrieves the bean from the datasource. The assumption is that the bean exists in the datasource.
1498    *
1499    * @param name     The filter name which tells the datasource which beans should be returned. The name also signifies what
1500    *                 data in the bean will be populated.
1501    * @param criteria This is an bean that has been defined within the metadata of the datasource. If the class is not
1502    *                 defined an exception will be thrown. If the bean does not exist in the datasource, an exception will be thrown.
1503    *                 This bean is used to specify the arguments used to retrieve the collection of beans.
1504    * @return A collection of beans will be returned that meet the criteria specified by obj. The beans will be of the
1505    *         same type as the bean that was passed in. If no beans match the criteria, an empty collection will be returned
1506    * @throws CpoException Thrown if there are errors accessing the datasource
1507    */
1508   @Override
1509   public <C> List<C> retrieveBeans(String name, C criteria) throws CpoException {
1510     return processSelectGroup(name, criteria, criteria, null, null, null, false);
1511   }
1512 
1513   /**
1514    * Retrieves the bean from the datasource. The assumption is that the bean exists in the datasource.
1515    *
1516    * @param name     The filter name which tells the datasource which beans should be returned. The name also signifies what
1517    *                 data in the bean will be populated.
1518    * @param criteria This is an bean that has been defined within the metadata of the datasource. If the class is not
1519    *                 defined an exception will be thrown. If the bean does not exist in the datasource, an exception will be thrown.
1520    *                 This bean is used to specify the arguments used to retrieve the collection of beans.
1521    * @param where    A CpoWhere bean that defines the constraints that should be used when retrieving beans
1522    * @param orderBy  The CpoOrderBy bean that defines the order in which beans should be returned
1523    * @return A collection of beans will be returned that meet the criteria specified by obj. The beans will be of the
1524    *         same type as the bean that was passed in. If no beans match the criteria, an empty collection will be returned
1525    * @throws CpoException Thrown if there are errors accessing the datasource
1526    */
1527   @Override
1528   public <C> List<C> retrieveBeans(String name, C criteria, CpoWhere where, Collection<CpoOrderBy> orderBy) throws CpoException {
1529     ArrayList<CpoWhere> wheres = null;
1530     if (where != null) {
1531       wheres = new ArrayList<>();
1532       wheres.add(where);
1533     }
1534     return processSelectGroup(name, criteria, criteria, wheres, orderBy, null, false);
1535   }
1536 
1537   /**
1538    * Retrieves the bean from the datasource. The assumption is that the bean exists in the datasource.
1539    *
1540    * @param name     The filter name which tells the datasource which beans should be returned. The name also signifies what
1541    *                 data in the bean will be populated.
1542    * @param criteria This is an bean that has been defined within the metadata of the datasource. If the class is not
1543    *                 defined an exception will be thrown. If the bean does not exist in the datasource, an exception will be thrown.
1544    *                 This bean is used to specify the arguments used to retrieve the collection of beans.
1545    * @param wheres   A collection of CpoWhere beans that define the constraints that should be used when retrieving beans
1546    * @param orderBy  The CpoOrderBy bean that defines the order in which beans should be returned
1547    * @return A collection of beans will be returned that meet the criteria specified by obj. The beans will be of the
1548    *         same type as the bean that was passed in. If no beans match the criteria, an empty collection will be returned
1549    * @throws CpoException Thrown if there are errors accessing the datasource
1550    */
1551   @Override
1552   public <C> List<C> retrieveBeans(String name, C criteria, Collection<CpoWhere> wheres, Collection<CpoOrderBy> orderBy) throws CpoException {
1553     return processSelectGroup(name, criteria, criteria, wheres, orderBy, null, false);
1554   }
1555 
1556   /**
1557    * Retrieves the bean from the datasource. The assumption is that the bean exists in the datasource.
1558    *
1559    * @param name     The filter name which tells the datasource which beans should be returned. The name also signifies what
1560    *                 data in the bean will be populated.
1561    * @param criteria This is an bean that has been defined within the metadata of the datasource. If the class is not
1562    *                 defined an exception will be thrown. If the bean does not exist in the datasource, an exception will be thrown.
1563    *                 This bean is used to specify the arguments used to retrieve the collection of beans.
1564    * @param orderBy  The CpoOrderBy bean that defines the order in which beans should be returned
1565    * @return A collection of beans will be returned that meet the criteria specified by obj. The beans will be of the
1566    *         same type as the bean that was passed in. If no beans match the criteria, an empty collection will be returned
1567    * @throws CpoException Thrown if there are errors accessing the datasource
1568    */
1569   @Override
1570   public <C> List<C> retrieveBeans(String name, C criteria, Collection<CpoOrderBy> orderBy) throws CpoException {
1571     return processSelectGroup(name, criteria, criteria, null, orderBy, null, false);
1572   }
1573 
1574   /**
1575    * Retrieves the bean from the datasource. The assumption is that the bean exists in the datasource.
1576    *
1577    * @param name     The filter name which tells the datasource which beans should be returned. The name also signifies what
1578    *                 data in the bean will be populated.
1579    * @param criteria This is an bean that has been defined within the metadata of the datasource. If the class is not
1580    *                 defined an exception will be thrown. If the bean does not exist in the datasource, an exception will be thrown.
1581    *                 This bean is used to specify the arguments used to retrieve the collection of beans.
1582    * @param result   This is an bean that has been defined within the metadata of the datasource. If the class is not
1583    *                 defined an exception will be thrown. If the bean does not exist in the datasource, an exception will be thrown.
1584    *                 This bean is used to specify the bean type that will be returned in the collection.
1585    * @return A collection of beans will be returned that meet the criteria specified by obj. The beans will be of the
1586    *         same type as the bean that was passed in. If no beans match the criteria, an empty collection will be returned
1587    * @throws CpoException Thrown if there are errors accessing the datasource
1588    */
1589   @Override
1590   public <T, C> List<T> retrieveBeans(String name, C criteria, T result) throws CpoException {
1591     return processSelectGroup(name, criteria, result, null, null, null, false);
1592   }
1593 
1594   /**
1595    * Retrieves the bean from the datasource. The assumption is that the bean exists in the datasource.
1596    *
1597    * @param name     The filter name which tells the datasource which beans should be returned. The name also signifies what
1598    *                 data in the bean will be populated.
1599    * @param criteria This is an bean that has been defined within the metadata of the datasource. If the class is not
1600    *                 defined an exception will be thrown. If the bean does not exist in the datasource, an exception will be thrown.
1601    *                 This bean is used to specify the arguments used to retrieve the collection of beans.
1602    * @param result   This is an bean that has been defined within the metadata of the datasource. If the class is not
1603    *                 defined an exception will be thrown. If the bean does not exist in the datasource, an exception will be thrown.
1604    *                 This bean is used to specify the bean type that will be returned in the collection.
1605    * @param where    A CpoWhere bean that defines the constraints that should be used when retrieving beans
1606    * @param orderBy  The CpoOrderBy bean that defines the order in which beans should be returned
1607    * @return A collection of beans will be returned that meet the criteria specified by obj. The beans will be of the
1608    *         same type as the bean that was passed in. If no beans match the criteria, an empty collection will be returned
1609    * @throws CpoException Thrown if there are errors accessing the datasource
1610    */
1611   @Override
1612   public <T, C> List<T> retrieveBeans(String name, C criteria, T result, CpoWhere where, Collection<CpoOrderBy> orderBy) throws CpoException {
1613     ArrayList<CpoWhere> wheres = null;
1614     if (where != null) {
1615       wheres = new ArrayList<>();
1616       wheres.add(where);
1617     }
1618     return processSelectGroup(name, criteria, result, wheres, orderBy, null, false);
1619   }
1620 
1621   /**
1622    * Retrieves the bean from the datasource. The assumption is that the bean exists in the datasource.
1623    *
1624    * @param name     The filter name which tells the datasource which beans should be returned. The name also signifies what
1625    *                 data in the bean will be populated.
1626    * @param criteria This is an bean that has been defined within the metadata of the datasource. If the class is not
1627    *                 defined an exception will be thrown. If the bean does not exist in the datasource, an exception will be thrown.
1628    *                 This bean is used to specify the arguments used to retrieve the collection of beans.
1629    * @param result   This is an bean that has been defined within the metadata of the datasource. If the class is not
1630    *                 defined an exception will be thrown. If the bean does not exist in the datasource, an exception will be thrown.
1631    *                 This bean is used to specify the bean type that will be returned in the collection.
1632    * @param wheres   A collection of CpoWhere beans that define the constraints that should be used when retrieving beans
1633    * @param orderBy  The CpoOrderBy bean that defines the order in which beans should be returned
1634    * @return A collection of beans will be returned that meet the criteria specified by obj. The beans will be of the
1635    *         same type as the bean that was passed in. If no beans match the criteria, an empty collection will be returned
1636    * @throws CpoException Thrown if there are errors accessing the datasource
1637    */
1638   @Override
1639   public <T, C> List<T> retrieveBeans(String name, C criteria, T result, Collection<CpoWhere> wheres, Collection<CpoOrderBy> orderBy) throws CpoException {
1640     return processSelectGroup(name, criteria, result, wheres, orderBy, null, false);
1641   }
1642 
1643   /**
1644    * Retrieves the bean from the datasource. The assumption is that the bean exists in the datasource.
1645    *
1646    * @param name              The filter name which tells the datasource which beans should be returned. The name also signifies what
1647    *                          data in the bean will be populated.
1648    * @param criteria          This is an bean that has been defined within the metadata of the datasource. If the class is not
1649    *                          defined an exception will be thrown. If the bean does not exist in the datasource, an exception will be thrown.
1650    *                          This bean is used to specify the arguments used to retrieve the collection of beans.
1651    * @param result            This is an bean that has been defined within the metadata of the datasource. If the class is not
1652    *                          defined an exception will be thrown. If the bean does not exist in the datasource, an exception will be thrown.
1653    *                          This bean is used to specify the bean type that will be returned in the collection.
1654    * @param wheres            A collection of CpoWhere beans that define the constraints that should be used when retrieving beans
1655    * @param orderBy           The CpoOrderBy bean that defines the order in which beans should be returned
1656    * @param nativeExpressions Native expression that will be used to augment the expression stored in the meta data. This
1657    *                          text will be embedded at run-time
1658    * @return A collection of beans will be returned that meet the criteria specified by obj. The beans will be of the
1659    *         same type as the bean that was passed in. If no beans match the criteria, an empty collection will be returned
1660    * @throws CpoException Thrown if there are errors accessing the datasource
1661    */
1662   @Override
1663   public <T, C> List<T> retrieveBeans(String name, C criteria, T result, Collection<CpoWhere> wheres, Collection<CpoOrderBy> orderBy, Collection<CpoNativeFunction> nativeExpressions) throws CpoException {
1664     return processSelectGroup(name, criteria, result, wheres, orderBy, nativeExpressions, false);
1665   }
1666 
1667   /**
1668    * Retrieves the bean from the datasource. This method returns an Iterator immediately. The iterator will get filled
1669    * asynchronously by the cpo framework. The framework will stop supplying the iterator with beans if the
1670    * beanBufferSize is reached.
1671    * <p/>
1672    * If the consumer of the iterator is processing records faster than the framework is filling it, then the iterator
1673    * will wait until it has data to provide.
1674    *
1675    * @param name              The filter name which tells the datasource which beans should be returned. The name also signifies what
1676    *                          data in the bean will be populated.
1677    * @param criteria          This is an bean that has been defined within the metadata of the datasource. If the class is not
1678    *                          defined an exception will be thrown. If the bean does not exist in the datasource, an exception will be thrown.
1679    *                          This bean is used to specify the arguments used to retrieve the collection of beans.
1680    * @param result            This is an bean that has been defined within the metadata of the datasource. If the class is not
1681    *                          defined an exception will be thrown. If the bean does not exist in the datasource, an exception will be thrown.
1682    *                          This bean is used to specify the bean type that will be returned in the collection.
1683    * @param wheres            A collection of CpoWhere beans that define the constraints that should be used when retrieving beans
1684    * @param orderBy           The CpoOrderBy bean that defines the order in which beans should be returned
1685    * @param nativeExpressions Native expression that will be used to augment the expression stored in the meta data. This
1686    *                          text will be embedded at run-time
1687    * @param queueSize         the maximum number of beans that the Iterator is allowed to cache. Once reached, the CPO
1688    *                          framework will halt processing records from the datasource.
1689    * @return An iterator that will be fed beans from the CPO framework.
1690    * @throws CpoException Thrown if there are errors accessing the datasource
1691    */
1692   @Override
1693   public <T, C> CpoResultSet<T> retrieveBeans(String name, C criteria, T result, Collection<CpoWhere> wheres, Collection<CpoOrderBy> orderBy, Collection<CpoNativeFunction> nativeExpressions, int queueSize) throws CpoException {
1694     CpoBlockingResultSet<T> resultSet = new CpoBlockingResultSet<>(queueSize);
1695     RetrieverThread<T, C> retrieverThread = new RetrieverThread<>(name, criteria, result, wheres, orderBy, nativeExpressions, false, resultSet);
1696 
1697     retrieverThread.start();
1698     return resultSet;
1699   }
1700 
1701   /**
1702    * Update the Object in the datasource. The CpoAdapter will check to see if the object exists in the datasource. If it
1703    * exists then the object will be updated. If it does not exist, an exception will be thrown
1704    * <p/>
1705    * <pre>Example:
1706    * <code>
1707    * <p/>
1708    * class SomeObject so = new SomeObject();
1709    * class CpoAdapter cpo = null;
1710    * <p/>
1711    * try {
1712    * 	cpo = new JdbcCpoAdapter(new JdbcDataSourceInfo(driver, url, user, password,1,1,false));
1713    * } catch (CpoException ce) {
1714    * 	// Handle the error
1715    * 	cpo = null;
1716    * }
1717    * <p/>
1718    * if (cpo!=null) {
1719    * 	so.setId(1);
1720    * 	so.setName("SomeName");
1721    * 	try{
1722    * 		cpo.updateObject(so);
1723    *  } catch (CpoException ce) {
1724    * 		// Handle the error
1725    *  }
1726    * }
1727    * </code>
1728    * </pre>
1729    *
1730    * @param obj This is an object that has been defined within the metadata of the datasource. If the class is not
1731    *            defined an exception will be thrown.
1732    * @return The number of objects updated in the datasource
1733    * @throws CpoException Thrown if there are errors accessing the datasource
1734    */
1735   @Override
1736   public <T> long updateObject(T obj) throws CpoException {
1737     return processUpdateGroup(obj, JdbcCpoAdapter.UPDATE_GROUP, null, null, null, null);
1738   }
1739 
1740   /**
1741    * Update the Object in the datasource. The CpoAdapter will check to see if the object exists in the datasource. If it
1742    * exists then the object will be updated. If it does not exist, an exception will be thrown
1743    * <p/>
1744    * <pre>Example:
1745    * <code>
1746    * <p/>
1747    * class SomeObject so = new SomeObject();
1748    * class CpoAdapter cpo = null;
1749    * <p/>
1750    * try {
1751    * 	cpo = new JdbcCpoAdapter(new JdbcDataSourceInfo(driver, url, user, password,1,1,false));
1752    * } catch (CpoException ce) {
1753    * 	// Handle the error
1754    * 	cpo = null;
1755    * }
1756    * <p/>
1757    * if (cpo!=null) {
1758    * 	so.setId(1);
1759    * 	so.setName("SomeName");
1760    * 	try{
1761    * 		cpo.updateObject("updateSomeObject",so);
1762    *  } catch (CpoException ce) {
1763    * 		// Handle the error
1764    *  }
1765    * }
1766    * </code>
1767    * </pre>
1768    *
1769    * @param name The String name of the UPDATE Function Group that will be used to create the object in the datasource.
1770    *             null signifies that the default rules will be used.
1771    * @param obj  This is an object that has been defined within the metadata of the datasource. If the class is not
1772    *             defined an exception will be thrown.
1773    * @return The number of objects updated in the datasource
1774    * @throws CpoException Thrown if there are errors accessing the datasource
1775    */
1776   @Override
1777   public <T> long updateObject(String name, T obj) throws CpoException {
1778     return processUpdateGroup(obj, JdbcCpoAdapter.UPDATE_GROUP, name, null, null, null);
1779   }
1780 
1781   /**
1782    * Update the Object in the datasource. The CpoAdapter will check to see if the object exists in the datasource. If it
1783    * exists then the object will be updated. If it does not exist, an exception will be thrown
1784    * <p/>
1785    * <pre>Example:
1786    * <code>
1787    * <p/>
1788    * class SomeObject so = new SomeObject();
1789    * class CpoAdapter cpo = null;
1790    * <p/>
1791    * try {
1792    * 	cpo = new JdbcCpoAdapter(new JdbcDataSourceInfo(driver, url, user, password,1,1,false));
1793    * } catch (CpoException ce) {
1794    * 	// Handle the error
1795    * 	cpo = null;
1796    * }
1797    * <p/>
1798    * if (cpo!=null) {
1799    * 	so.setId(1);
1800    * 	so.setName("SomeName");
1801    * 	try{
1802    * 		cpo.updateObject("updateSomeObject",so);
1803    *  } catch (CpoException ce) {
1804    * 		// Handle the error
1805    *  }
1806    * }
1807    * </code>
1808    * </pre>
1809    *
1810    * @param name              The String name of the UPDATE Function Group that will be used to create the object in the datasource.
1811    *                          null signifies that the default rules will be used.
1812    * @param obj               This is an object that has been defined within the metadata of the datasource. If the class is not
1813    *                          defined an exception will be thrown.
1814    * @param wheres            A collection of CpoWhere objects to be used by the function
1815    * @param orderBy           A collection of CpoOrderBy objects to be used by the function
1816    * @param nativeExpressions A collection of CpoNativeFunction objects to be used by the function
1817    * @return The number of objects updated in the datasource
1818    * @throws CpoException Thrown if there are errors accessing the datasource
1819    */
1820   @Override
1821   public <T> long updateObject(String name, T obj, Collection<CpoWhere> wheres, Collection<CpoOrderBy> orderBy, Collection<CpoNativeFunction> nativeExpressions) throws CpoException {
1822     return processUpdateGroup(obj, JdbcCpoAdapter.UPDATE_GROUP, name, wheres, orderBy, nativeExpressions);
1823   }
1824 
1825   /**
1826    * Updates a collection of Objects in the datasource. The assumption is that the objects contained in the collection
1827    * exist in the datasource. This method stores the object in the datasource. The objects in the collection will be
1828    * treated as one transaction, meaning that if one of the objects fail being updated in the datasource then the entire
1829    * collection will be rolled back, if supported by the datasource.
1830    * <p/>
1831    * <pre>Example:
1832    * <code>
1833    * <p/>
1834    * class SomeObject so = null;
1835    * class CpoAdapter cpo = null;
1836    * <p/>
1837    * try {
1838    * 	cpo = new JdbcCpoAdapter(new JdbcDataSourceInfo(driver, url, user, password,1,1,false));
1839    * } catch (CpoException ce) {
1840    * 	// Handle the error
1841    * 	cpo = null;
1842    * }
1843    * <p/>
1844    * if (cpo!=null) {
1845    * 	ArrayList al = new ArrayList();
1846    * 	for (int i=0; i<3; i++){
1847    * 		so = new SomeObject();
1848    * 		so.setId(1);
1849    * 		so.setName("SomeName");
1850    * 		al.add(so);
1851    *  }
1852    * 	try{
1853    * 		cpo.updateObjects(al);
1854    *  } catch (CpoException ce) {
1855    * 		// Handle the error
1856    *  }
1857    * }
1858    * </code>
1859    * </pre>
1860    *
1861    * @param coll This is a collection of objects that have been defined within the metadata of the datasource. If the
1862    *             class is not defined an exception will be thrown.
1863    * @return The number of objects updated in the datasource
1864    * @throws CpoException Thrown if there are errors accessing the datasource
1865    */
1866   @Override
1867   public <T> long updateObjects(Collection<T> coll) throws CpoException {
1868     return processUpdateGroup(coll, JdbcCpoAdapter.UPDATE_GROUP, null, null, null, null);
1869   }
1870 
1871   /**
1872    * Updates a collection of Objects in the datasource. The assumption is that the objects contained in the collection
1873    * exist in the datasource. This method stores the object in the datasource. The objects in the collection will be
1874    * treated as one transaction, meaning that if one of the objects fail being updated in the datasource then the entire
1875    * collection will be rolled back, if supported by the datasource.
1876    * <p/>
1877    * <pre>Example:
1878    * <code>
1879    * <p/>
1880    * class SomeObject so = null;
1881    * class CpoAdapter cpo = null;
1882    * <p/>
1883    * try {
1884    * 	cpo = new JdbcCpoAdapter(new JdbcDataSourceInfo(driver, url, user, password,1,1,false));
1885    * } catch (CpoException ce) {
1886    * 	// Handle the error
1887    * 	cpo = null;
1888    * }
1889    * <p/>
1890    * if (cpo!=null) {
1891    * 	ArrayList al = new ArrayList();
1892    * 	for (int i=0; i<3; i++){
1893    * 		so = new SomeObject();
1894    * 		so.setId(1);
1895    * 		so.setName("SomeName");
1896    * 		al.add(so);
1897    *  }
1898    * 	try{
1899    * 		cpo.updateObjects("myUpdate",al);
1900    *  } catch (CpoException ce) {
1901    * 		// Handle the error
1902    *  }
1903    * }
1904    * </code>
1905    * </pre>
1906    *
1907    * @param name The String name of the UPDATE Function Group that will be used to create the object in the datasource.
1908    *             null signifies that the default rules will be used.
1909    * @param coll This is a collection of objects that have been defined within the metadata of the datasource. If the
1910    *             class is not defined an exception will be thrown.
1911    * @return The number of objects updated in the datasource
1912    * @throws CpoException Thrown if there are errors accessing the datasource
1913    */
1914   @Override
1915   public <T> long updateObjects(String name, Collection<T> coll) throws CpoException {
1916     return processUpdateGroup(coll, JdbcCpoAdapter.UPDATE_GROUP, name, null, null, null);
1917   }
1918 
1919   /**
1920    * Updates a collection of Objects in the datasource. The assumption is that the objects contained in the collection
1921    * exist in the datasource. This method stores the object in the datasource. The objects in the collection will be
1922    * treated as one transaction, meaning that if one of the objects fail being updated in the datasource then the entire
1923    * collection will be rolled back, if supported by the datasource.
1924    * <p/>
1925    * <pre>Example:
1926    * <code>
1927    * <p/>
1928    * class SomeObject so = null;
1929    * class CpoAdapter cpo = null;
1930    * <p/>
1931    * try {
1932    * 	cpo = new JdbcCpoAdapter(new JdbcDataSourceInfo(driver, url, user, password,1,1,false));
1933    * } catch (CpoException ce) {
1934    * 	// Handle the error
1935    * 	cpo = null;
1936    * }
1937    * <p/>
1938    * if (cpo!=null) {
1939    * 	ArrayList al = new ArrayList();
1940    * 	for (int i=0; i<3; i++){
1941    * 		so = new SomeObject();
1942    * 		so.setId(1);
1943    * 		so.setName("SomeName");
1944    * 		al.add(so);
1945    *  }
1946    * 	try{
1947    * 		cpo.updateObjects("myUpdate",al);
1948    *  } catch (CpoException ce) {
1949    * 		// Handle the error
1950    *  }
1951    * }
1952    * </code>
1953    * </pre>
1954    *
1955    * @param name              The String name of the UPDATE Function Group that will be used to create the object in the datasource.
1956    *                          null signifies that the default rules will be used.
1957    * @param coll              This is a collection of objects that have been defined within the metadata of the datasource. If the
1958    *                          class is not defined an exception will be thrown.
1959    * @param wheres            A collection of CpoWhere objects to be used by the function
1960    * @param orderBy           A collection of CpoOrderBy objects to be used by the function
1961    * @param nativeExpressions A collection of CpoNativeFunction objects to be used by the function
1962    * @return The number of objects updated in the datasource
1963    * @throws CpoException Thrown if there are errors accessing the datasource
1964    */
1965   @Override
1966   public <T> long updateObjects(String name, Collection<T> coll, Collection<CpoWhere> wheres, Collection<CpoOrderBy> orderBy, Collection<CpoNativeFunction> nativeExpressions) throws CpoException {
1967     return processUpdateGroup(coll, JdbcCpoAdapter.UPDATE_GROUP, name, wheres, orderBy, nativeExpressions);
1968   }
1969 
1970   /**
1971    * DOCUMENT ME!
1972    *
1973    * @param context DOCUMENT ME!
1974    * @throws CpoException DOCUMENT ME!
1975    */
1976   protected void setContext(Context context) throws CpoException {
1977     try {
1978       if (context == null) {
1979         context_ = new InitialContext();
1980       } else {
1981         context_ = context;
1982       }
1983     } catch (NamingException e) {
1984       throw new CpoException("Error setting Context", e);
1985     }
1986   }
1987 
1988   /**
1989    * DOCUMENT ME!
1990    *
1991    * @return DOCUMENT ME!
1992    */
1993   protected Context getContext() {
1994     return context_;
1995   }
1996 
1997   /**
1998    * DOCUMENT ME!
1999    *
2000    * @param obj  DOCUMENT ME!
2001    * @param type DOCUMENT ME!
2002    * @param name DOCUMENT ME!
2003    * @param c    DOCUMENT ME!
2004    * @return DOCUMENT ME!
2005    * @throws CpoException DOCUMENT ME!
2006    */
2007   protected <T> String getGroupType(T obj, String type, String name, Connection c) throws CpoException {
2008     String retType = type;
2009     long objCount;
2010 
2011     if (JdbcCpoAdapter.PERSIST_GROUP.equals(retType)) {
2012       objCount = existsObject(name, obj, c, null);
2013 
2014       if (objCount == 0) {
2015         retType = JdbcCpoAdapter.CREATE_GROUP;
2016       } else if (objCount == 1) {
2017         retType = JdbcCpoAdapter.UPDATE_GROUP;
2018       } else {
2019         throw new CpoException("Persist can only UPDATE one record. Your EXISTS function returned 2 or more.");
2020       }
2021     }
2022 
2023     return retType;
2024   }
2025 
2026   /**
2027    * DOCUMENT ME!
2028    *
2029    * @return DOCUMENT ME!
2030    * @throws CpoException DOCUMENT ME!
2031    */
2032   protected Connection getReadConnection() throws CpoException {
2033     Connection connection = getStaticConnection();
2034 
2035     if (connection == null) {
2036       try {
2037         if (!(invalidReadConnection_)) {
2038           connection = getReadDataSource().getConnection();
2039         } else {
2040           connection = getWriteDataSource().getConnection();
2041         }
2042         connection.setAutoCommit(false);
2043       } catch (Exception e) {
2044         invalidReadConnection_ = true;
2045 
2046         String msg = "getReadConnection(): failed";
2047         logger.error(msg, e);
2048 
2049         try {
2050           connection = getWriteDataSource().getConnection();
2051           connection.setAutoCommit(false);
2052         } catch (SQLException e2) {
2053           msg = "getWriteConnection(): failed";
2054           logger.error(msg, e2);
2055           throw new CpoException(msg, e2);
2056         }
2057       }
2058     }
2059 
2060     return connection;
2061   }
2062 
2063   /**
2064    * DOCUMENT ME!
2065    *
2066    * @return DOCUMENT ME!
2067    * @throws CpoException DOCUMENT ME!
2068    */
2069   protected Connection getWriteConnection() throws CpoException {
2070     Connection connection = getStaticConnection();
2071 
2072     if (connection == null) {
2073       try {
2074         connection = getWriteDataSource().getConnection();
2075         connection.setAutoCommit(false);
2076       } catch (SQLException e) {
2077         String msg = "getWriteConnection(): failed";
2078         logger.error(msg, e);
2079         throw new CpoException(msg, e);
2080       }
2081     }
2082 
2083     return connection;
2084   }
2085 
2086   protected Connection getStaticConnection() throws CpoException {
2087     // do nothing for JdbcCpoAdapter
2088     // overridden by JdbcTrxAdapter
2089     return null;
2090   }
2091 
2092   protected boolean isStaticConnection(Connection c) {
2093     // do nothing for JdbcCpoAdapter
2094     // overridden by JdbcTrxAdapter
2095     return false;
2096   }
2097 
2098   protected void setStaticConnection(Connection c) {
2099     // do nothing for JdbcCpoAdapter
2100     // overridden by JdbcTrxAdapter
2101   }
2102 
2103   /**
2104    * DOCUMENT ME!
2105    *
2106    * @param connection DOCUMENT ME!
2107    */
2108   protected void closeConnection(Connection connection) {
2109     try {
2110       clearConnectionBusy(connection);
2111       if (connection != null && !isStaticConnection(connection) && !connection.isClosed()) {
2112         connection.close();
2113       }
2114     } catch (SQLException e) {
2115       if (logger.isTraceEnabled()) {
2116         logger.trace(e.getMessage());
2117       }
2118     }
2119   }
2120 
2121   /**
2122    * DOCUMENT ME!
2123    *
2124    * @param connection DOCUMENT ME!
2125    */
2126   protected void commitConnection(Connection connection) {
2127     try {
2128       if (connection != null && !isStaticConnection(connection)) {
2129         connection.commit();
2130       }
2131     } catch (SQLException e) {
2132       if (logger.isTraceEnabled()) {
2133         logger.trace(e.getMessage());
2134       }
2135     }
2136   }
2137 
2138   /**
2139    * DOCUMENT ME!
2140    *
2141    * @param connection DOCUMENT ME!
2142    */
2143   protected void rollbackConnection(Connection connection) {
2144     try {
2145       if (connection != null && !isStaticConnection(connection)) {
2146         connection.rollback();
2147       }
2148     } catch (Exception e) {
2149       if (logger.isTraceEnabled()) {
2150         logger.trace(e.getMessage());
2151       }
2152     }
2153   }
2154 
2155   /**
2156    * Executes an Object whose MetaData contains a stored procedure. An assumption is that the object exists in the
2157    * datasource.
2158    *
2159    * @param name     The filter name which tells the datasource which objects should be returned. The name also signifies
2160    *                 what data in the object will be populated.
2161    * @param criteria This is an object that has been defined within the metadata of the datasource. If the class is not
2162    *                 defined an exception will be thrown. If the object does not exist in the datasource, an exception will be thrown.
2163    *                 This object is used to populate the IN arguments used to retrieve the collection of objects.
2164    * @param result   This is an object that has been defined within the metadata of the datasource. If the class is not
2165    *                 defined an exception will be thrown. If the object does not exist in the datasource, an exception will be thrown.
2166    *                 This object defines the object type that will be returned in the
2167    * @return A result object populate with the OUT arguments
2168    * @throws CpoException DOCUMENT ME!
2169    */
2170   protected <T, C> T processExecuteGroup(String name, C criteria, T result) throws CpoException {
2171     Connection c = null;
2172     T obj = null;
2173 
2174     try {
2175       c = getWriteConnection();
2176       obj = processExecuteGroup(name, criteria, result, c);
2177       commitConnection(c);
2178     } catch (Exception e) {
2179       // Any exception has to try to rollback the work;
2180       rollbackConnection(c);
2181       ExceptionHelper.reThrowCpoException(e, "processExecuteGroup(String name, Object criteria, Object result) failed");
2182     } finally {
2183       closeConnection(c);
2184     }
2185 
2186     return obj;
2187   }
2188 
2189   /**
2190    * DOCUMENT ME!
2191    *
2192    * @param name     DOCUMENT ME!
2193    * @param criteria DOCUMENT ME!
2194    * @param result   DOCUMENT ME!
2195    * @param conn     DOCUMENT ME!
2196    * @return DOCUMENT ME!
2197    * @throws CpoException DOCUMENT ME!
2198    */
2199   protected <T, C> T processExecuteGroup(String name, C criteria, T result, Connection conn) throws CpoException {
2200     CallableStatement cstmt = null;
2201     CpoClass criteriaClass;
2202     T returnObject = null;
2203     Logger localLogger = criteria == null ? logger : LoggerFactory.getLogger(criteria.getClass());
2204 
2205     JdbcCallableStatementFactory jcsf = null;
2206 
2207     if (criteria == null || result == null) {
2208       throw new CpoException("NULL Object passed into executeObject");
2209     }
2210 
2211     try {
2212       criteriaClass = metaDescriptor.getMetaClass(criteria);
2213       List<CpoFunction> functions = criteriaClass.getFunctionGroup(JdbcCpoAdapter.EXECUTE_GROUP, name).getFunctions();
2214       localLogger.info("===================processExecuteGroup (" + name + ") Count<" + functions.size() + ">=========================");
2215 
2216       try {
2217         returnObject = (T) result.getClass().newInstance();
2218       } catch (IllegalAccessException iae) {
2219         throw new CpoException("Unable to access the constructor of the Return Object", iae);
2220       } catch (InstantiationException iae) {
2221         throw new CpoException("Unable to instantiate Return Object", iae);
2222       }
2223 
2224       // Loop through the queries and process each one
2225       for (CpoFunction function : functions) {
2226 
2227         localLogger.debug("Executing Call:" + criteriaClass.getName() + ":" + name);
2228 
2229         jcsf = new JdbcCallableStatementFactory(conn, this, function, criteria);
2230         cstmt = jcsf.getCallableStatement();
2231         cstmt.execute();
2232         jcsf.release();
2233 
2234         localLogger.debug("Processing Call:" + criteriaClass.getName() + ":" + name);
2235 
2236         // Add Code here to go through the arguments, find record sets,
2237         // and process them
2238         // Process the non-record set out params and make it the first
2239         // object in the collection
2240 
2241         // Loop through the OUT Parameters and set them in the result
2242         // object
2243         int j = 1;
2244         for (CpoArgument cpoArgument : jcsf.getOutArguments()) {
2245           JdbcCpoArgument jdbcArgument = (JdbcCpoArgument) cpoArgument;
2246           if (jdbcArgument.isOutParameter()) {
2247             JdbcCpoAttribute jdbcAttribute = jdbcArgument.getAttribute();
2248             jdbcAttribute.invokeSetter(returnObject, new CallableStatementCpoData(cstmt, jdbcAttribute, j));
2249           }
2250           j++;
2251         }
2252 
2253         cstmt.close();
2254       }
2255     } catch (Throwable t) {
2256       String msg = "ProcessExecuteGroup(String name, Object criteria, Object result, Connection conn) failed. SQL=";
2257       localLogger.error(msg, t);
2258       throw new CpoException(msg, t);
2259     } finally {
2260       statementClose(cstmt);
2261       if (jcsf != null) {
2262         jcsf.release();
2263       }
2264     }
2265 
2266     return returnObject;
2267   }
2268 
2269   /**
2270    * Retrieves the Object from the datasource.
2271    *
2272    * @param obj               This is an object that has been defined within the metadata of the datasource. If the class is not
2273    *                          defined an exception will be thrown. The input object is used to specify the search criteria.
2274    * @param groupName         The name which identifies which RETRIEVE Function Group to execute to retrieve the object.
2275    * @param wheres            A collection of CpoWhere objects to be used by the function
2276    * @param orderBy           A collection of CpoOrderBy objects to be used by the function
2277    * @param nativeExpressions A collection of CpoNativeFunction objects to be used by the function
2278    * @return A populated object of the same type as the Object passed in as a argument. If no objects match the criteria
2279    *         a NULL will be returned.
2280    * @throws CpoException the retrieve function defined for this objects returns more than one row, an exception will be
2281    *                      thrown.
2282    */
2283   protected <T> T processSelectGroup(T obj, String groupName, Collection<CpoWhere> wheres, Collection<CpoOrderBy> orderBy, Collection<CpoNativeFunction> nativeExpressions) throws CpoException {
2284     Connection c = null;
2285     T result = null;
2286 
2287     try {
2288       c = getReadConnection();
2289       result = processSelectGroup(obj, groupName, wheres, orderBy, nativeExpressions, c);
2290 
2291       // The select may have a for update clause on it
2292       // Since the connection is cached we need to get rid of this
2293       commitConnection(c);
2294     } catch (Exception e) {
2295       // Any exception has to try to rollback the work;
2296       rollbackConnection(c);
2297       ExceptionHelper.reThrowCpoException(e, "processSelectGroup(Object obj, String groupName) failed");
2298     } finally {
2299       closeConnection(c);
2300     }
2301 
2302     return result;
2303   }
2304 
2305   /**
2306    * DOCUMENT ME!
2307    *
2308    * @param obj       DOCUMENT ME!
2309    * @param groupName DOCUMENT ME!
2310    * @param con       DOCUMENT ME!
2311    * @return DOCUMENT ME!
2312    * @throws CpoException DOCUMENT ME!
2313    */
2314   protected <T> T processSelectGroup(T obj, String groupName, Collection<CpoWhere> wheres, Collection<CpoOrderBy> orderBy, Collection<CpoNativeFunction> nativeExpressions, Connection con) throws CpoException {
2315     PreparedStatement ps = null;
2316     ResultSet rs = null;
2317     ResultSetMetaData rsmd;
2318     CpoClass cpoClass;
2319     JdbcCpoAttribute attribute;
2320     T criteriaObj = obj;
2321     boolean recordsExist = false;
2322     Logger localLogger = obj == null ? logger : LoggerFactory.getLogger(obj.getClass());
2323 
2324     int recordCount = 0;
2325     int attributesSet = 0;
2326 
2327     int k;
2328     T rObj = null;
2329 
2330     if (obj == null) {
2331       throw new CpoException("NULL Object passed into retrieveBean");
2332     }
2333 
2334     try {
2335       cpoClass = metaDescriptor.getMetaClass(criteriaObj);
2336       List<CpoFunction> functions = cpoClass.getFunctionGroup(JdbcCpoAdapter.RETRIEVE_GROUP, groupName).getFunctions();
2337 
2338       localLogger.info("=================== Class=<" + criteriaObj.getClass() + "> Type=<" + JdbcCpoAdapter.RETRIEVE_GROUP + "> Name=<" + groupName + "> =========================");
2339 
2340       try {
2341         rObj = (T) obj.getClass().newInstance();
2342       } catch (IllegalAccessException iae) {
2343         localLogger.error("=================== Could not access default constructor for Class=<" + obj.getClass() + "> ==================");
2344         throw new CpoException("Unable to access the constructor of the Return Object", iae);
2345       } catch (InstantiationException iae) {
2346         throw new CpoException("Unable to instantiate Return Object", iae);
2347       }
2348 
2349       for (CpoFunction cpoFunction : functions) {
2350 
2351         JdbcPreparedStatementFactory jpsf = new JdbcPreparedStatementFactory(con, this, cpoClass, cpoFunction, criteriaObj, wheres, orderBy, nativeExpressions);
2352         ps = jpsf.getPreparedStatement();
2353 
2354         // insertions on
2355         // selectgroup
2356         rs = ps.executeQuery();
2357         jpsf.release();
2358 
2359         if (rs.isBeforeFirst()) {
2360           rsmd = rs.getMetaData();
2361 
2362           if ((rsmd.getColumnCount() == 2) && "CPO_ATTRIBUTE".equalsIgnoreCase(rsmd.getColumnLabel(1)) && "CPO_VALUE".equalsIgnoreCase(rsmd.getColumnLabel(2))) {
2363             while (rs.next()) {
2364               recordsExist = true;
2365               recordCount++;
2366               attribute = (JdbcCpoAttribute) cpoClass.getAttributeData(rs.getString(1));
2367 
2368               if (attribute != null) {
2369                 attribute.invokeSetter(rObj, new ResultSetCpoData(JdbcMethodMapper.getMethodMapper(), rs, attribute, 2));
2370                 attributesSet++;
2371               }
2372             }
2373           } else if (rs.next()) {
2374             recordsExist = true;
2375             recordCount++;
2376             for (k = 1; k <= rsmd.getColumnCount(); k++) {
2377               attribute = (JdbcCpoAttribute) cpoClass.getAttributeData(rsmd.getColumnLabel(k));
2378 
2379               if (attribute != null) {
2380                 attribute.invokeSetter(rObj, new ResultSetCpoData(JdbcMethodMapper.getMethodMapper(), rs, attribute, k));
2381                 attributesSet++;
2382               }
2383             }
2384 
2385             if (rs.next()) {
2386               String msg = "ProcessSelectGroup(Object, String) failed: Multiple Records Returned";
2387               localLogger.error(msg);
2388               throw new CpoException(msg);
2389             }
2390           }
2391           criteriaObj = rObj;
2392         }
2393 
2394         rs.close();
2395         rs = null;
2396         ps.close();
2397         ps = null;
2398       }
2399 
2400       if (!recordsExist) {
2401         rObj = null;
2402         localLogger.info("=================== 0 Records - 0 Attributes - Class=<" + criteriaObj.getClass() + "> Type=<" + JdbcCpoAdapter.RETRIEVE_GROUP + "> Name=<" + groupName + "> =========================");
2403       } else {
2404         localLogger.info("=================== " + recordCount + " Records - " + attributesSet + " Attributes - Class=<" + criteriaObj.getClass() + ">  Type=<" + JdbcCpoAdapter.RETRIEVE_GROUP + "> Name=<" + groupName + "> =========================");
2405       }
2406     } catch (Throwable t) {
2407       String msg = "ProcessSeclectGroup(Object) failed: " + ExceptionHelper.getLocalizedMessage(t);
2408       localLogger.error(msg, t);
2409       rObj = null;
2410       throw new CpoException(msg, t);
2411     } finally {
2412       resultSetClose(rs);
2413       statementClose(ps);
2414     }
2415 
2416     return rObj;
2417   }
2418 
2419   /**
2420    * DOCUMENT ME!
2421    *
2422    * @param name        DOCUMENT ME!
2423    * @param criteria    DOCUMENT ME!
2424    * @param result      DOCUMENT ME!
2425    * @param wheres      DOCUMENT ME!
2426    * @param orderBy     DOCUMENT ME!
2427    * @param useRetrieve DOCUMENT ME!
2428    * @return DOCUMENT ME!
2429    * @throws CpoException DOCUMENT ME!
2430    */
2431   protected <T, C> List<T> processSelectGroup(String name, C criteria, T result, Collection<CpoWhere> wheres, Collection<CpoOrderBy> orderBy, Collection<CpoNativeFunction> nativeExpressions,
2432                                               boolean useRetrieve) throws CpoException {
2433     Connection con = null;
2434     CpoArrayResultSet<T> resultSet = new CpoArrayResultSet<>();
2435 
2436     try {
2437       con = getReadConnection();
2438       processSelectGroup(name, criteria, result, wheres, orderBy, nativeExpressions, con, useRetrieve, resultSet);
2439       // The select may have a for update clause on it
2440       // Since the connection is cached we need to get rid of this
2441       commitConnection(con);
2442     } catch (Exception e) {
2443       // Any exception has to try to rollback the work;
2444       rollbackConnection(con);
2445       ExceptionHelper.reThrowCpoException(e, "processSelectGroup(String name, Object criteria, Object result,CpoWhere where, Collection orderBy, boolean useRetrieve) failed");
2446     } finally {
2447       closeConnection(con);
2448     }
2449 
2450     return resultSet;
2451   }
2452 
2453   protected <T, C> void processSelectGroup(String name, C criteria, T result, Collection<CpoWhere> wheres, Collection<CpoOrderBy> orderBy, Collection<CpoNativeFunction> nativeExpressions,
2454                                            boolean useRetrieve, CpoResultSet<T> resultSet) throws CpoException {
2455     Connection con = null;
2456 
2457     try {
2458       con = getReadConnection();
2459       processSelectGroup(name, criteria, result, wheres, orderBy, nativeExpressions, con, useRetrieve, resultSet);
2460       // The select may have a for update clause on it
2461       // Since the connection is cached we need to get rid of this
2462       commitConnection(con);
2463     } catch (Exception e) {
2464       // Any exception has to try to rollback the work;
2465       rollbackConnection(con);
2466       ExceptionHelper.reThrowCpoException(e, "processSelectGroup(String name, Object criteria, Object result,CpoWhere where, Collection orderBy, boolean useRetrieve) failed");
2467     } finally {
2468       closeConnection(con);
2469     }
2470   }
2471 
2472   /**
2473    * DOCUMENT ME!
2474    *
2475    * @param name        DOCUMENT ME!
2476    * @param criteria    DOCUMENT ME!
2477    * @param result      DOCUMENT ME!
2478    * @param wheres      DOCUMENT ME!
2479    * @param orderBy     DOCUMENT ME!
2480    * @param con         DOCUMENT ME!
2481    * @param useRetrieve DOCUMENT ME!
2482    * @throws CpoException DOCUMENT ME!
2483    */
2484   protected <T, C> void processSelectGroup(String name, C criteria, T result, Collection<CpoWhere> wheres, Collection<CpoOrderBy> orderBy, Collection<CpoNativeFunction> nativeExpressions, Connection con, boolean useRetrieve, CpoResultSet<T> resultSet) throws CpoException {
2485     Logger localLogger = criteria == null ? logger : LoggerFactory.getLogger(criteria.getClass());
2486     PreparedStatement ps = null;
2487     List<CpoFunction> cpoFunctions;
2488     CpoClass criteriaClass;
2489     CpoClass resultClass;
2490     ResultSet rs = null;
2491     ResultSetMetaData rsmd;
2492     int columnCount;
2493     int k;
2494     T obj;
2495     JdbcCpoAttribute[] attributes;
2496     JdbcPreparedStatementFactory jpsf;
2497     int i;
2498 
2499     if (criteria == null || result == null) {
2500       throw new CpoException("NULL Object passed into retrieveBean or retrieveBeans");
2501     }
2502 
2503     try {
2504       criteriaClass = metaDescriptor.getMetaClass(criteria);
2505       resultClass = metaDescriptor.getMetaClass(result);
2506       if (useRetrieve) {
2507         localLogger.info("=================== Class=<" + criteria.getClass() + "> Type=<" + JdbcCpoAdapter.RETRIEVE_GROUP + "> Name=<" + name + "> =========================");
2508         cpoFunctions = criteriaClass.getFunctionGroup(JdbcCpoAdapter.RETRIEVE_GROUP, name).getFunctions();
2509       } else {
2510         localLogger.info("=================== Class=<" + criteria.getClass() + "> Type=<" + JdbcCpoAdapter.LIST_GROUP + "> Name=<" + name + "> =========================");
2511         cpoFunctions = criteriaClass.getFunctionGroup(JdbcCpoAdapter.LIST_GROUP, name).getFunctions();
2512       }
2513 
2514       for (CpoFunction cpoFunction : cpoFunctions) {
2515         jpsf = new JdbcPreparedStatementFactory(con, this, criteriaClass, cpoFunction, criteria, wheres, orderBy, nativeExpressions);
2516         ps = jpsf.getPreparedStatement();
2517         if (resultSet.getFetchSize() != -1) {
2518           ps.setFetchSize(resultSet.getFetchSize());
2519         }
2520 
2521         localLogger.debug("Retrieving Records");
2522 
2523         rs = ps.executeQuery();
2524         jpsf.release();
2525 
2526         localLogger.debug("Processing Records");
2527 
2528         rsmd = rs.getMetaData();
2529 
2530         columnCount = rsmd.getColumnCount();
2531 
2532         attributes = new JdbcCpoAttribute[columnCount + 1];
2533 
2534         for (k = 1; k <= columnCount; k++) {
2535           attributes[k] = (JdbcCpoAttribute) resultClass.getAttributeData(rsmd.getColumnLabel(k));
2536         }
2537 
2538         while (rs.next()) {
2539           try {
2540             obj = (T) result.getClass().newInstance();
2541           } catch (IllegalAccessException iae) {
2542             localLogger.error("=================== Could not access default constructor for Class=<" + result.getClass() + "> ==================");
2543             throw new CpoException("Unable to access the constructor of the Return Object", iae);
2544           } catch (InstantiationException iae) {
2545             throw new CpoException("Unable to instantiate Return Object", iae);
2546           }
2547 
2548           for (k = 1; k <= columnCount; k++) {
2549             if (attributes[k] != null) {
2550               attributes[k].invokeSetter(obj, new ResultSetCpoData(JdbcMethodMapper.getMethodMapper(), rs, attributes[k], k));
2551             }
2552           }
2553 
2554           try {
2555             resultSet.put(obj);
2556           } catch (InterruptedException e) {
2557             localLogger.error("Retriever Thread was interrupted", e);
2558             break;
2559           }
2560         }
2561 
2562         resultSetClose(rs);
2563         statementClose(ps);
2564 
2565         localLogger.info("=================== " + resultSet.size() + " Records - Class=<" + criteria.getClass() + "> Type=<" + JdbcCpoAdapter.LIST_GROUP + "> Name=<" + name + "> Result=<" + result.getClass() + "> ====================");
2566       }
2567     } catch (Throwable t) {
2568       String msg = "ProcessSelectGroup(String name, Object criteria, Object result, CpoWhere where, Collection orderBy, Connection con) failed. Error:";
2569       localLogger.error(msg, t);
2570       throw new CpoException(msg, t);
2571     } finally {
2572       resultSetClose(rs);
2573       statementClose(ps);
2574     }
2575   }
2576 
2577   /**
2578    * DOCUMENT ME!
2579    *
2580    * @param obj       DOCUMENT ME!
2581    * @param groupType DOCUMENT ME!
2582    * @param groupName DOCUMENT ME!
2583    * @return DOCUMENT ME!
2584    * @throws CpoException DOCUMENT ME!
2585    */
2586   protected <T> long processUpdateGroup(T obj, String groupType, String groupName, Collection<CpoWhere> wheres, Collection<CpoOrderBy> orderBy, Collection<CpoNativeFunction> nativeExpressions) throws CpoException {
2587     Connection c = null;
2588     long updateCount = 0;
2589 
2590     try {
2591       c = getWriteConnection();
2592       updateCount = processUpdateGroup(obj, groupType, groupName, wheres, orderBy, nativeExpressions, c);
2593       commitConnection(c);
2594     } catch (Exception e) {
2595       // Any exception has to try to rollback the work;
2596       rollbackConnection(c);
2597       ExceptionHelper.reThrowCpoException(e, "processUdateGroup(Object obj, String groupType, String groupName) failed");
2598     } finally {
2599       closeConnection(c);
2600     }
2601 
2602     return updateCount;
2603   }
2604 
2605   /**
2606    * DOCUMENT ME!
2607    *
2608    * @param obj       DOCUMENT ME!
2609    * @param groupType DOCUMENT ME!
2610    * @param groupName DOCUMENT ME!
2611    * @param con       DOCUMENT ME!
2612    * @return DOCUMENT ME!
2613    * @throws CpoException DOCUMENT ME!
2614    */
2615   protected <T> long processUpdateGroup(T obj, String groupType, String groupName, Collection<CpoWhere> wheres, Collection<CpoOrderBy> orderBy, Collection<CpoNativeFunction> nativeExpressions, Connection con) throws CpoException {
2616     Logger localLogger = obj == null ? logger : LoggerFactory.getLogger(obj.getClass());
2617     CpoClass cpoClass;
2618     PreparedStatement ps = null;
2619 
2620     JdbcPreparedStatementFactory jpsf = null;
2621     long updateCount = 0;
2622 
2623     if (obj == null) {
2624       throw new CpoException("NULL Object passed into insertObject, deleteObject, updateObject, or persistObject");
2625     }
2626 
2627     try {
2628       cpoClass = metaDescriptor.getMetaClass(obj);
2629       List<CpoFunction> cpoFunctions = cpoClass.getFunctionGroup(getGroupType(obj, groupType, groupName, con), groupName).getFunctions();
2630       localLogger.info("=================== Class=<" + obj.getClass() + "> Type=<" + groupType + "> Name=<" + groupName + "> =========================");
2631 
2632       int numRows = 0;
2633 
2634       for (CpoFunction cpoFunction : cpoFunctions) {
2635         jpsf = new JdbcPreparedStatementFactory(con, this, cpoClass, cpoFunction, obj, wheres, orderBy, nativeExpressions);
2636         ps = jpsf.getPreparedStatement();
2637         numRows += ps.executeUpdate();
2638         jpsf.release();
2639         ps.close();
2640       }
2641       localLogger.info("=================== " + numRows + " Updates - Class=<" + obj.getClass() + "> Type=<" + groupType + "> Name=<" + groupName + "> =========================");
2642 
2643       if (numRows > 0) {
2644         updateCount++;
2645       }
2646     } catch (Throwable t) {
2647       String msg = "ProcessUpdateGroup failed:" + groupType + "," + groupName + "," + obj.getClass().getName();
2648       // TODO FIX THIS
2649       // localLogger.error("bound values:" + this.parameterToString(jq));
2650       localLogger.error(msg, t);
2651       throw new CpoException(msg, t);
2652     } finally {
2653       statementClose(ps);
2654       if (jpsf != null) {
2655         jpsf.release();
2656       }
2657     }
2658 
2659     return updateCount;
2660   }
2661 
2662   /**
2663    * DOCUMENT ME!
2664    *
2665    * @param arr       DOCUMENT ME!
2666    * @param groupType DOCUMENT ME!
2667    * @param groupName DOCUMENT ME!
2668    * @param con       DOCUMENT ME!
2669    * @return DOCUMENT ME!
2670    * @throws CpoException DOCUMENT ME!
2671    */
2672   protected <T> long processBatchUpdateGroup(T[] arr, String groupType, String groupName, Collection<CpoWhere> wheres, Collection<CpoOrderBy> orderBy, Collection<CpoNativeFunction> nativeExpressions, Connection con) throws CpoException {
2673     CpoClass jmc;
2674     List<CpoFunction> cpoFunctions;
2675     PreparedStatement ps = null;
2676     CpoFunction cpoFunction;
2677     JdbcPreparedStatementFactory jpsf = null;
2678     long updateCount = 0;
2679     int[] updates;
2680     Logger localLogger = logger;
2681 
2682     try {
2683       jmc = metaDescriptor.getMetaClass(arr[0]);
2684       cpoFunctions = jmc.getFunctionGroup(getGroupType(arr[0], groupType, groupName, con), groupName).getFunctions();
2685       localLogger = LoggerFactory.getLogger(jmc.getMetaClass());
2686 
2687       int numRows = 0;
2688 
2689       // Only Batch if there is only one function
2690       if (cpoFunctions.size() == 1) {
2691         localLogger.info("=================== BATCH - Class=<" + arr[0].getClass() + "> Type=<" + groupType + "> Name=<" + groupName + "> =========================");
2692         cpoFunction = cpoFunctions.get(0);
2693         jpsf = new JdbcPreparedStatementFactory(con, this, jmc, cpoFunction, arr[0], wheres, orderBy, nativeExpressions);
2694         ps = jpsf.getPreparedStatement();
2695         ps.addBatch();
2696         for (int j = 1; j < arr.length; j++) {
2697 //          jpsf.bindParameters(arr[j]);
2698           jpsf.setBindValues(jpsf.getBindValues(cpoFunction, arr[j]));
2699           ps.addBatch();
2700         }
2701         updates = ps.executeBatch();
2702         jpsf.release();
2703         ps.close();
2704         for (int update : updates) {
2705           if (update < 0 && update == PreparedStatement.SUCCESS_NO_INFO) {
2706             // something updated but we do not know what or how many so default to one.
2707             numRows++;
2708           } else {
2709             numRows += update;
2710           }
2711         }
2712         localLogger.info("=================== BATCH - " + numRows + " Updates - Class=<" + arr[0].getClass() + "> Type=<" + groupType + "> Name=<" + groupName + "> =========================");
2713       } else {
2714         localLogger.info("=================== Class=<" + arr[0].getClass() + "> Type=<" + groupType + "> Name=<" + groupName + "> =========================");
2715         for (T obj : arr) {
2716           for (CpoFunction function : cpoFunctions) {
2717             jpsf = new JdbcPreparedStatementFactory(con, this, jmc, function, obj, wheres, orderBy, nativeExpressions);
2718             ps = jpsf.getPreparedStatement();
2719             numRows += ps.executeUpdate();
2720             jpsf.release();
2721             ps.close();
2722           }
2723         }
2724         localLogger.info("=================== " + numRows + " Updates - Class=<" + arr[0].getClass() + "> Type=<" + groupType + "> Name=<" + groupName + "> =========================");
2725       }
2726 
2727       if (numRows > 0) {
2728         updateCount = numRows;
2729       }
2730     } catch (Throwable t) {
2731       String msg = "ProcessUpdateGroup failed:" + groupType + "," + groupName + "," + arr[0].getClass().getName();
2732       // TODO FIX This
2733       // localLogger.error("bound values:" + this.parameterToString(jq));
2734       localLogger.error(msg, t);
2735       throw new CpoException(msg, t);
2736     } finally {
2737       statementClose(ps);
2738       if (jpsf != null) {
2739         jpsf.release();
2740       }
2741     }
2742 
2743     return updateCount;
2744   }
2745 
2746   /**
2747    * DOCUMENT ME!
2748    *
2749    * @param coll      DOCUMENT ME!
2750    * @param groupType DOCUMENT ME!
2751    * @param groupName DOCUMENT ME!
2752    * @return DOCUMENT ME!
2753    * @throws CpoException DOCUMENT ME!
2754    */
2755   protected <T> long processUpdateGroup(Collection<T> coll, String groupType, String groupName, Collection<CpoWhere> wheres, Collection<CpoOrderBy> orderBy, Collection<CpoNativeFunction> nativeExpressions) throws CpoException {
2756     Connection c = null;
2757     long updateCount = 0;
2758 
2759     try {
2760       c = getWriteConnection();
2761 
2762       updateCount = processUpdateGroup(coll, groupType, groupName, wheres, orderBy, nativeExpressions, c);
2763       commitConnection(c);
2764     } catch (Exception e) {
2765       // Any exception has to try to rollback the work;
2766       rollbackConnection(c);
2767       ExceptionHelper.reThrowCpoException(e, "processUpdateGroup(Collection coll, String groupType, String groupName) failed");
2768     } finally {
2769       closeConnection(c);
2770     }
2771 
2772     return updateCount;
2773   }
2774 
2775   /**
2776    * DOCUMENT ME!
2777    *
2778    * @param coll              DOCUMENT ME!
2779    * @param groupType         DOCUMENT ME!
2780    * @param groupName         DOCUMENT ME!
2781    * @param wheres            DOCUMENT ME!
2782    * @param orderBy           DOCUMENT ME!
2783    * @param nativeExpressions DOCUMENT ME!
2784    * @param con               DOCUMENT ME!
2785    * @return DOCUMENT ME!
2786    * @throws CpoException DOCUMENT ME!
2787    */
2788   protected <T> long processUpdateGroup(Collection<T> coll, String groupType, String groupName, Collection<CpoWhere> wheres, Collection<CpoOrderBy> orderBy, Collection<CpoNativeFunction> nativeExpressions, Connection con) throws CpoException {
2789     long updateCount = 0;
2790 
2791     if (!coll.isEmpty()) {
2792       T[] arr = (T[]) coll.toArray();
2793 
2794       T obj1 = arr[0];
2795       boolean allEqual = true;
2796       for (int i = 1; i < arr.length; i++) {
2797         if (!obj1.getClass().getName().equals(arr[i].getClass().getName())) {
2798           allEqual = false;
2799           break;
2800         }
2801       }
2802 
2803       if (allEqual && batchUpdatesSupported_ && !JdbcCpoAdapter.PERSIST_GROUP.equals(groupType)) {
2804         updateCount = processBatchUpdateGroup(arr, groupType, groupName, wheres, orderBy, nativeExpressions, con);
2805       } else {
2806         for (T obj : arr) {
2807           updateCount += processUpdateGroup(obj, groupType, groupName, wheres, orderBy, nativeExpressions, con);
2808         }
2809       }
2810     }
2811 
2812     return updateCount;
2813   }
2814 
2815   /**
2816    * Provides a mechanism for the user to obtain a CpoTrxAdapter object. This object allows the to control when commits
2817    * and rollbacks occur on CPO.
2818    * <p/>
2819    * <p/>
2820    * <pre>Example:
2821    * <code>
2822    * <p/>
2823    * class SomeObject so = null;
2824    * class CpoAdapter cpo = null;
2825    * class CpoTrxAdapter cpoTrx = null;
2826    * <p/>
2827    * try {
2828    * 	cpo = new JdbcCpoAdapter(new JdbcDataSourceInfo(driver, url, user, password,1,1,false));
2829    * 	cpoTrx = cpo.getCpoTrxAdapter();
2830    * } catch (CpoException ce) {
2831    * 	// Handle the error
2832    * 	cpo = null;
2833    * }
2834    * <p/>
2835    * if (cpo!=null) {
2836    * 	try{
2837    * 		for (int i=0; i<3; i++){
2838    * 			so = new SomeObject();
2839    * 			so.setId(1);
2840    * 			so.setName("SomeName");
2841    * 			cpo.updateObject("myUpdate",so);
2842    *    }
2843    * 		cpoTrx.commit();
2844    *  } catch (CpoException ce) {
2845    * 		// Handle the error
2846    * 		cpoTrx.rollback();
2847    *  }
2848    * }
2849    * </code>
2850    * </pre>
2851    *
2852    * @return A CpoTrxAdapter to manage the transactionality of CPO
2853    * @throws CpoException Thrown if there are errors accessing the datasource
2854    * @see CpoTrxAdapter
2855    */
2856   @Override
2857   public CpoTrxAdapter getCpoTrxAdapter() throws CpoException {
2858     return new JdbcCpoTrxAdapter(metaDescriptor, getWriteConnection(), batchUpdatesSupported_, getDataSourceName());
2859   }
2860 
2861   protected boolean isConnectionBusy(Connection c) {
2862     // do nothing for JdbcCpoAdapter
2863     // overridden by JdbcTrxAdapter
2864     return false;
2865   }
2866 
2867   protected void setConnectionBusy(Connection c) {
2868     // do nothing for JdbcCpoAdapter
2869     // overridden by JdbcTrxAdapter
2870   }
2871 
2872   protected void clearConnectionBusy(Connection c) {
2873     // do nothing for JdbcCpoAdapter
2874     // overridden by JdbcTrxAdapter
2875   }
2876 
2877   private void statementClose(Statement s) {
2878     if (s != null) {
2879       try {
2880         s.close();
2881       } catch (Exception e) {
2882         if (logger.isTraceEnabled()) {
2883           logger.trace(e.getMessage());
2884         }
2885       }
2886     }
2887   }
2888 
2889   private void resultSetClose(ResultSet rs) {
2890     if (rs != null) {
2891       try {
2892         rs.close();
2893       } catch (Exception e) {
2894         if (logger.isTraceEnabled()) {
2895           logger.trace(e.getMessage());
2896         }
2897       }
2898     }
2899   }
2900 
2901   @Override
2902   public CpoMetaDescriptor getCpoMetaDescriptor() {
2903     return metaDescriptor;
2904   }
2905 
2906   @Override
2907   public List<CpoAttribute> getCpoAttributes(String expression) throws CpoException {
2908     List<CpoAttribute> attributes = new ArrayList<>();
2909 
2910     if (expression != null && !expression.isEmpty()) {
2911       Connection c = null;
2912       PreparedStatement ps = null;
2913       ResultSet rs = null;
2914       try {
2915         c = getWriteConnection();
2916         ps = c.prepareStatement(expression);
2917         rs = ps.executeQuery();
2918         ResultSetMetaData rsmd = rs.getMetaData();
2919         for (int i = 1; i <= rsmd.getColumnCount(); i++) {
2920           JdbcCpoAttribute attribute = new JdbcCpoAttribute();
2921           attribute.setDataName(rsmd.getColumnLabel(i));
2922           attribute.setDbColumn(rsmd.getColumnName(i));
2923           try {
2924             attribute.setDbTable(rsmd.getTableName(i));
2925           } catch (Exception e) {
2926             // do nothing if this call is not supported
2927           }
2928 
2929           DataTypeMapEntry<?> dataTypeMapEntry = metaDescriptor.getDataTypeMapEntry(rsmd.getColumnType(i));
2930           attribute.setDataType(dataTypeMapEntry.getDataTypeName());
2931           attribute.setDataTypeInt(dataTypeMapEntry.getDataTypeInt());
2932           attribute.setJavaType(dataTypeMapEntry.getJavaClass().getName());
2933           attribute.setJavaName(dataTypeMapEntry.makeJavaName(rsmd.getColumnLabel(i)));
2934 
2935           attributes.add(attribute);
2936         }
2937       } catch (Throwable t) {
2938         logger.error(ExceptionHelper.getLocalizedMessage(t), t);
2939         throw new CpoException("Error Generating Attributes", t);
2940       } finally {
2941         resultSetClose(rs);
2942         statementClose(ps);
2943         closeConnection(c);
2944       }
2945     }
2946     return attributes;
2947   }
2948 
2949 }