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