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