1 package org.synchronoss.cpo.jdbc;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 import java.lang.reflect.Constructor;
26 import java.sql.CallableStatement;
27 import java.sql.Connection;
28 import java.sql.PreparedStatement;
29 import java.sql.ResultSet;
30 import java.sql.ResultSetMetaData;
31 import java.sql.SQLException;
32 import java.sql.Statement;
33 import java.sql.Types;
34 import java.util.ArrayList;
35 import java.util.Collection;
36 import java.util.List;
37 import java.util.Spliterator;
38 import java.util.Spliterators;
39 import java.util.function.Consumer;
40 import java.util.stream.Stream;
41 import java.util.stream.StreamSupport;
42 import javax.naming.Context;
43 import javax.naming.InitialContext;
44 import javax.naming.NamingException;
45 import javax.sql.DataSource;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48 import org.synchronoss.cpo.core.*;
49 import org.synchronoss.cpo.core.enums.Comparison;
50 import org.synchronoss.cpo.core.enums.Crud;
51 import org.synchronoss.cpo.core.enums.Logical;
52 import org.synchronoss.cpo.core.helper.ExceptionHelper;
53 import org.synchronoss.cpo.core.meta.CpoMetaDescriptor;
54 import org.synchronoss.cpo.core.meta.DataTypeMapEntry;
55 import org.synchronoss.cpo.core.meta.domain.CpoArgument;
56 import org.synchronoss.cpo.core.meta.domain.CpoAttribute;
57 import org.synchronoss.cpo.core.meta.domain.CpoClass;
58 import org.synchronoss.cpo.core.meta.domain.CpoFunction;
59 import org.synchronoss.cpo.jdbc.meta.JdbcCpoMetaDescriptor;
60 import org.synchronoss.cpo.jdbc.meta.JdbcMethodMapper;
61 import org.synchronoss.cpo.jdbc.meta.JdbcResultSetCpoData;
62
63
64
65
66
67
68
69 public class JdbcCpoAdapter extends CpoBaseAdapter<DataSource> {
70
71
72 private static final long serialVersionUID = 1L;
73
74 private static final Logger logger = LoggerFactory.getLogger(JdbcCpoAdapter.class);
75
76
77 private transient Context context_ = null;
78
79
80 private final JdbcDatabaseCapabilities capabilities;
81
82
83 private transient JdbcConnectionStrategy connectionStrategy;
84
85
86 private JdbcCpoMetaDescriptor metaDescriptor = null;
87
88
89
90
91
92
93
94
95 protected JdbcCpoAdapter(JdbcCpoMetaDescriptor metaDescriptor, DataSourceInfo<DataSource> jdsiTrx)
96 throws CpoException {
97 super(jdsiTrx.getDataSourceName(), jdsiTrx.getFetchSize(), jdsiTrx.getBatchSize());
98 this.metaDescriptor = metaDescriptor;
99 setWriteDataSource(jdsiTrx.getDataSource());
100 setReadDataSource(jdsiTrx.getDataSource());
101 this.connectionStrategy =
102 new JdbcPooledConnectionStrategy(getReadDataSource(), getWriteDataSource());
103 this.capabilities = JdbcDatabaseCapabilities.probe(connectionStrategy);
104 }
105
106
107
108
109
110
111
112
113
114
115
116 protected JdbcCpoAdapter(
117 JdbcCpoMetaDescriptor metaDescriptor,
118 DataSourceInfo<DataSource> jdsiWrite,
119 DataSourceInfo<DataSource> jdsiRead)
120 throws CpoException {
121 super(jdsiWrite.getDataSourceName(), jdsiWrite.getFetchSize(), jdsiWrite.getBatchSize());
122 this.metaDescriptor = metaDescriptor;
123 setWriteDataSource(jdsiWrite.getDataSource());
124 setReadDataSource(jdsiRead.getDataSource());
125 this.connectionStrategy =
126 new JdbcPooledConnectionStrategy(getReadDataSource(), getWriteDataSource());
127 this.capabilities = JdbcDatabaseCapabilities.probe(connectionStrategy);
128 }
129
130
131
132
133
134
135
136 protected JdbcCpoAdapter(JdbcCpoAdapter jdbcCpoAdapter) throws CpoException {
137 super(
138 jdbcCpoAdapter.getDataSourceName(),
139 jdbcCpoAdapter.getFetchSize(),
140 jdbcCpoAdapter.getBatchSize());
141 this.metaDescriptor = (JdbcCpoMetaDescriptor) jdbcCpoAdapter.getCpoMetaDescriptor();
142 this.capabilities = jdbcCpoAdapter.capabilities;
143 setWriteDataSource(jdbcCpoAdapter.getWriteDataSource());
144 setReadDataSource(jdbcCpoAdapter.getReadDataSource());
145 this.connectionStrategy =
146 new JdbcPooledConnectionStrategy(getReadDataSource(), getWriteDataSource());
147 }
148
149
150
151
152
153
154 JdbcConnectionStrategy getConnectionStrategy() {
155 return connectionStrategy;
156 }
157
158
159
160
161
162
163 void setConnectionStrategy(JdbcConnectionStrategy connectionStrategy) {
164 this.connectionStrategy = connectionStrategy;
165 }
166
167
168
169
170
171
172 protected boolean isBatchUpdatesSupported() {
173 return capabilities.batchUpdatesSupported();
174 }
175
176
177
178
179
180
181
182
183
184 public static JdbcCpoAdapter getInstance(
185 JdbcCpoMetaDescriptor metaDescriptor, DataSourceInfo<DataSource> jdsiTrx)
186 throws CpoException {
187 String adapterKey = metaDescriptor + ":" + jdsiTrx.getDataSourceName();
188 JdbcCpoAdapter adapter = (JdbcCpoAdapter) findCpoAdapter(adapterKey);
189 if (adapter == null) {
190 adapter = new JdbcCpoAdapter(metaDescriptor, jdsiTrx);
191 addCpoAdapter(adapterKey, adapter);
192 }
193 return adapter;
194 }
195
196
197
198
199
200
201
202
203
204
205
206
207 public static JdbcCpoAdapter getInstance(
208 JdbcCpoMetaDescriptor metaDescriptor,
209 DataSourceInfo<DataSource> jdsiWrite,
210 DataSourceInfo<DataSource> jdsiRead)
211 throws CpoException {
212 String adapterKey =
213 metaDescriptor + ":" + jdsiWrite.getDataSourceName() + ":" + jdsiRead.getDataSourceName();
214 JdbcCpoAdapter adapter = (JdbcCpoAdapter) findCpoAdapter(adapterKey);
215 if (adapter == null) {
216 adapter = new JdbcCpoAdapter(metaDescriptor, jdsiWrite, jdsiRead);
217 addCpoAdapter(adapterKey, adapter);
218 }
219 return adapter;
220 }
221
222 @Override
223 public <T> long existsBean(CpoQuery query, T bean) throws CpoException {
224 Connection c = null;
225 long objCount = -1;
226
227 try {
228 c = getReadConnection();
229
230 objCount = existsBean(query.groupName(), bean, c, query.wheres());
231 } finally {
232
233
234
235
236
237 rollbackLocalConnection(c);
238 closeLocalConnection(c);
239 }
240
241 return objCount;
242 }
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258 protected <T> long existsBean(
259 String groupName, T bean, Connection con, Collection<CpoWhere> wheres) throws CpoException {
260 PreparedStatement ps = null;
261 ResultSet rs = null;
262 ResultSetMetaData rsmd;
263 CpoClass cpoClass;
264 long objCount = 0;
265 Logger localLogger = logger;
266
267 if (bean == null) {
268 throw new CpoException("NULL Bean passed into existsBean");
269 }
270
271 try {
272 cpoClass = metaDescriptor.getMetaClass(bean);
273 List<CpoFunction> cpoFunctions =
274 cpoClass.getFunctionGroup(Crud.EXIST, groupName).getFunctions();
275 localLogger = LoggerFactory.getLogger(cpoClass.getMetaClass());
276
277 for (CpoFunction cpoFunction : cpoFunctions) {
278 localLogger.info(cpoFunction.getExpression());
279 JdbcPreparedStatementFactory jpsf =
280 new JdbcPreparedStatementFactory(
281 con, this, cpoClass, cpoFunction, bean, wheres, null, null);
282 ps = jpsf.getPreparedStatement();
283
284 long qCount = 0;
285
286 rs = ps.executeQuery();
287 jpsf.release();
288 rsmd = rs.getMetaData();
289
290
291
292 if (rsmd.getColumnCount() == 1 && isCountResult(rsmd.getColumnType(1)) && rs.next()) {
293 qCount = rs.getLong(1);
294 if (rs.next()) {
295
296 qCount = 2;
297 }
298 }
299
300 while (rs.next()) {
301 qCount++;
302 }
303
304 objCount += qCount;
305
306 rs.close();
307 ps.close();
308 rs = null;
309 ps = null;
310 }
311 } catch (SQLException e) {
312 String msg = "existsBean(groupName, bean, con) failed:";
313 throw new CpoException(msg, e);
314 } finally {
315 resultSetClose(rs);
316 statementClose(ps);
317 }
318
319 return objCount;
320 }
321
322 private static boolean isCountResult(int sqlType) {
323 return switch (sqlType) {
324 case Types.BIGINT,
325 Types.INTEGER,
326 Types.NUMERIC,
327 Types.DECIMAL,
328 Types.SMALLINT,
329 Types.TINYINT ->
330 true;
331 default -> false;
332 };
333 }
334
335 @Override
336 public CpoWhere newWhere() {
337 return new JdbcCpoWhere();
338 }
339
340 @Override
341 public <T> CpoWhere newWhere(Logical logical, String attr, Comparison comp, T value) {
342 return new JdbcCpoWhere(logical, attr, comp, value);
343 }
344
345 @Override
346 public <T> CpoWhere newWhere(
347 Logical logical, String attr, Comparison comp, T value, boolean not) {
348 return new JdbcCpoWhere(logical, attr, comp, value, not);
349 }
350
351
352
353
354
355
356
357 protected void setContext(Context context) throws CpoException {
358 try {
359 if (context == null) {
360 context_ = new InitialContext();
361 } else {
362 context_ = context;
363 }
364 } catch (NamingException e) {
365 throw new CpoException("Error setting Context", e);
366 }
367 }
368
369
370
371
372
373
374 protected Context getContext() {
375 return context_;
376 }
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391 protected <T> Crud adjustCrud(T bean, Crud crud, String groupName, Connection c)
392 throws CpoException {
393 Crud retType = crud;
394 long objCount;
395
396 if (Crud.UPSERT == retType) {
397 objCount = existsBean(groupName, bean, c, null);
398
399 if (objCount == 0) {
400 retType = Crud.CREATE;
401 } else if (objCount == 1) {
402 retType = Crud.UPDATE;
403 } else {
404 throw new CpoException(
405 "UPSERT can only UPDATE one record. Your EXISTS function returned 2 or more.");
406 }
407 }
408
409 return retType;
410 }
411
412
413
414
415
416
417
418 protected Connection getReadConnection() throws CpoException {
419 return connectionStrategy.getReadConnection();
420 }
421
422
423
424
425
426
427
428 protected Connection getWriteConnection() throws CpoException {
429 return connectionStrategy.getWriteConnection();
430 }
431
432
433
434
435
436
437 protected void closeLocalConnection(Connection connection) {
438 connectionStrategy.closeLocalConnection(connection);
439 }
440
441
442
443
444
445
446 protected void commitLocalConnection(Connection connection) {
447 connectionStrategy.commitLocalConnection(connection);
448 }
449
450
451
452
453
454
455 protected void rollbackLocalConnection(Connection connection) {
456 connectionStrategy.rollbackLocalConnection(connection);
457 }
458
459 @Override
460 protected <T, C> T processExecuteGroup(String groupName, C criteria, T result)
461 throws CpoException {
462 Connection c = null;
463 T bean = null;
464
465 try {
466 c = getWriteConnection();
467 bean = processExecuteGroup(groupName, criteria, result, c);
468 commitLocalConnection(c);
469 } catch (Exception e) {
470
471 rollbackLocalConnection(c);
472 ExceptionHelper.reThrowCpoException(
473 e, "processExecuteGroup(String groupName, C criteria, T result) failed");
474 } finally {
475 closeLocalConnection(c);
476 }
477
478 return bean;
479 }
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502 protected <T, C> T processExecuteGroup(String groupName, C criteria, T result, Connection conn)
503 throws CpoException {
504 CallableStatement cstmt = null;
505 CpoClass criteriaClass;
506 CpoClass resultClass;
507 T returnBean = null;
508 Logger localLogger = criteria == null ? logger : LoggerFactory.getLogger(criteria.getClass());
509
510 JdbcCallableStatementFactory jcsf = null;
511
512 if (criteria == null || result == null) {
513 throw new CpoException("NULL Bean passed into executeBean");
514 }
515
516 try {
517 criteriaClass = metaDescriptor.getMetaClass(criteria);
518 resultClass = metaDescriptor.getMetaClass(result);
519
520 List<CpoFunction> functions =
521 criteriaClass.getFunctionGroup(Crud.EXECUTE, groupName).getFunctions();
522 localLogger.info(
523 "===================processExecuteGroup ("
524 + groupName
525 + ") Count<"
526 + functions.size()
527 + ">=========================");
528
529 try {
530 returnBean = (T) result.getClass().getDeclaredConstructor().newInstance();
531 } catch (IllegalAccessException iae) {
532 throw new CpoException("Unable to access the constructor of the Return Bean", iae);
533 } catch (InstantiationException iae) {
534 throw new CpoException("Unable to instantiate Return Bean", iae);
535 }
536
537
538 for (CpoFunction function : functions) {
539
540 localLogger.debug("Executing Call:" + criteriaClass.getName() + ":" + groupName);
541
542 jcsf = new JdbcCallableStatementFactory(conn, this, function, criteria, resultClass);
543 cstmt = jcsf.getCallableStatement();
544 cstmt.execute();
545 jcsf.release();
546
547 localLogger.debug("Processing Call:" + criteriaClass.getName() + ":" + groupName);
548
549
550
551
552
553
554
555
556 int j = 1;
557 for (CpoArgument cpoArgument : jcsf.getOutArguments()) {
558 JdbcCpoArgument jdbcArgument = (JdbcCpoArgument) cpoArgument;
559 if (jdbcArgument.isOutParameter()) {
560 JdbcCpoAttribute jdbcAttribute = jdbcArgument.getAttribute();
561 if (jdbcAttribute == null) {
562 jdbcAttribute =
563 (JdbcCpoAttribute) resultClass.getAttributeJava(jdbcArgument.getName());
564 if (jdbcAttribute == null) {
565 throw new CpoException(
566 "Attribute <"
567 + jdbcArgument.getName()
568 + "> does not exist on class <"
569 + resultClass.getName()
570 + ">");
571 }
572 }
573 jdbcAttribute.invokeSetter(
574 returnBean, new CallableStatementCpoData(cstmt, jdbcAttribute, j));
575 }
576 j++;
577 }
578
579 cstmt.close();
580 }
581 } catch (Throwable t) {
582 String msg =
583 "processExecuteGroup(String groupName, C criteria, T result, Connection conn)"
584 + " failed. SQL=";
585 localLogger.error(msg, t);
586 throw new CpoException(msg, t);
587 } finally {
588 statementClose(cstmt);
589 if (jcsf != null) {
590 jcsf.release();
591 }
592 }
593
594 return returnBean;
595 }
596
597 @Override
598 protected <T> T processSelectGroup(
599 T bean,
600 String groupName,
601 Collection<CpoWhere> wheres,
602 Collection<CpoOrderBy> orderBy,
603 Collection<CpoNativeFunction> nativeExpressions)
604 throws CpoException {
605 Connection c = null;
606 T result = null;
607
608 try {
609 c = getReadConnection();
610 result = processSelectGroup(bean, groupName, wheres, orderBy, nativeExpressions, c);
611
612
613
614 commitLocalConnection(c);
615 } catch (Exception e) {
616
617 rollbackLocalConnection(c);
618 ExceptionHelper.reThrowCpoException(e, "processSelectGroup(T bean, String groupName) failed");
619 } finally {
620 closeLocalConnection(c);
621 }
622
623 return result;
624 }
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644 protected <T> T processSelectGroup(
645 T bean,
646 String groupName,
647 Collection<CpoWhere> wheres,
648 Collection<CpoOrderBy> orderBy,
649 Collection<CpoNativeFunction> nativeExpressions,
650 Connection con)
651 throws CpoException {
652 PreparedStatement ps = null;
653 ResultSet rs = null;
654 ResultSetMetaData rsmd;
655 CpoClass cpoClass;
656 JdbcCpoAttribute attribute;
657 T criteriaObj = bean;
658 boolean recordsExist = false;
659 Logger localLogger = bean == null ? logger : LoggerFactory.getLogger(bean.getClass());
660
661 int recordCount = 0;
662 int attributesSet = 0;
663
664 int k;
665 T rObj = null;
666
667 if (bean == null) {
668 throw new CpoException("NULL Bean passed into retrieveBean");
669 }
670
671 try {
672 cpoClass = metaDescriptor.getMetaClass(criteriaObj);
673 List<CpoFunction> functions =
674 cpoClass.getFunctionGroup(Crud.RETRIEVE, groupName).getFunctions();
675
676 localLogger.info(buildCpoClassLogLine(criteriaObj.getClass(), Crud.RETRIEVE, groupName));
677
678 try {
679 rObj = (T) bean.getClass().getDeclaredConstructor().newInstance();
680 } catch (IllegalAccessException iae) {
681 localLogger.error(
682 "=================== Could not access default constructor for Class=<"
683 + bean.getClass()
684 + "> ==================");
685 throw new CpoException("Unable to access the constructor of the Return Bean", iae);
686 } catch (InstantiationException iae) {
687 throw new CpoException("Unable to instantiate Return Bean", iae);
688 }
689
690 for (CpoFunction cpoFunction : functions) {
691
692 JdbcPreparedStatementFactory jpsf =
693 new JdbcPreparedStatementFactory(
694 con, this, cpoClass, cpoFunction, criteriaObj, wheres, orderBy, nativeExpressions);
695 ps = jpsf.getPreparedStatement();
696
697
698
699 rs = ps.executeQuery();
700 jpsf.release();
701
702 if (rs.isBeforeFirst()) {
703 rsmd = rs.getMetaData();
704
705 if ((rsmd.getColumnCount() == 2)
706 && "CPO_ATTRIBUTE".equalsIgnoreCase(rsmd.getColumnLabel(1))
707 && "CPO_VALUE".equalsIgnoreCase(rsmd.getColumnLabel(2))) {
708 while (rs.next()) {
709 recordsExist = true;
710 recordCount++;
711 attribute = (JdbcCpoAttribute) cpoClass.getAttributeData(rs.getString(1));
712
713 if (attribute != null) {
714 attribute.invokeSetter(
715 rObj,
716 new JdbcResultSetCpoData(JdbcMethodMapper.getMethodMapper(), rs, attribute, 2));
717 attributesSet++;
718 }
719 }
720 } else if (rs.next()) {
721 recordsExist = true;
722 recordCount++;
723 for (k = 1; k <= rsmd.getColumnCount(); k++) {
724 attribute = (JdbcCpoAttribute) cpoClass.getAttributeData(rsmd.getColumnLabel(k));
725
726 if (attribute != null) {
727 attribute.invokeSetter(
728 rObj,
729 new JdbcResultSetCpoData(JdbcMethodMapper.getMethodMapper(), rs, attribute, k));
730 attributesSet++;
731 }
732 }
733
734 if (rs.next()) {
735 String msg =
736 "processSelectGroup(T bean, String groupName) failed: Multiple Records Returned";
737 localLogger.error(msg);
738 throw new CpoException(msg);
739 }
740 }
741 criteriaObj = rObj;
742 }
743
744 rs.close();
745 rs = null;
746 ps.close();
747 ps = null;
748 }
749
750 if (!recordsExist) {
751 rObj = null;
752 localLogger.info(
753 buildRecordsLogLine(0, 0, criteriaObj.getClass(), Crud.RETRIEVE, groupName));
754 } else {
755 localLogger.info(
756 buildRecordsLogLine(
757 recordCount, attributesSet, criteriaObj.getClass(), Crud.RETRIEVE, groupName));
758 }
759 } catch (Throwable t) {
760 String msg = "processSeclectGroup(T bean) failed: " + ExceptionHelper.getLocalizedMessage(t);
761 localLogger.error(msg, t);
762 rObj = null;
763 throw new CpoException(msg, t);
764 } finally {
765 resultSetClose(rs);
766 statementClose(ps);
767 }
768
769 return rObj;
770 }
771
772 @Override
773 protected <T, C> Stream<T> processSelectGroup(
774 String groupName,
775 C criteria,
776 T result,
777 Collection<CpoWhere> wheres,
778 Collection<CpoOrderBy> orderBy,
779 Collection<CpoNativeFunction> nativeExpressions,
780 boolean useRetrieve)
781 throws CpoException {
782 Connection con = null;
783
784 try {
785 con = getReadConnection();
786 return processSelectGroup(
787 groupName, criteria, result, wheres, orderBy, nativeExpressions, con, useRetrieve);
788 } catch (Exception e) {
789
790 rollbackLocalConnection(con);
791 closeLocalConnection(con);
792 ExceptionHelper.reThrowCpoException(
793 e,
794 "processSelectGroup(String groupName, C criteria, T result,C poWhere where,"
795 + " Collection orderBy, boolean useRetrieve) failed");
796 }
797 return Stream.empty();
798 }
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816 protected <T, C> Stream<T> processSelectGroup(
817 String groupName,
818 C criteria,
819 T result,
820 Collection<CpoWhere> wheres,
821 Collection<CpoOrderBy> orderBy,
822 Collection<CpoNativeFunction> nativeExpressions,
823 Connection con,
824 boolean useRetrieve)
825 throws CpoException {
826 Logger localLogger = criteria == null ? logger : LoggerFactory.getLogger(criteria.getClass());
827 PreparedStatement ps = null;
828 List<CpoFunction> cpoFunctions;
829 CpoClass criteriaClass;
830 CpoClass resultClass;
831 ResultSet rs = null;
832 ResultSetMetaData rsmd;
833 int columnCount;
834 JdbcCpoAttribute[] attributes;
835 JdbcPreparedStatementFactory jpsf;
836
837 if (criteria == null || result == null) {
838 throw new CpoException("NULL Bean passed into retrieveBean or retrieveBeans");
839 }
840
841 try {
842 criteriaClass = metaDescriptor.getMetaClass(criteria);
843 resultClass = metaDescriptor.getMetaClass(result);
844 if (useRetrieve) {
845 localLogger.info(buildCpoClassLogLine(criteria.getClass(), Crud.RETRIEVE, groupName));
846 cpoFunctions = criteriaClass.getFunctionGroup(Crud.RETRIEVE, groupName).getFunctions();
847 } else {
848 localLogger.info(buildCpoClassLogLine(criteria.getClass(), Crud.LIST, groupName));
849 cpoFunctions = criteriaClass.getFunctionGroup(Crud.LIST, groupName).getFunctions();
850 }
851
852 CpoFunction cpoFunction = cpoFunctions.getFirst();
853 jpsf =
854 new JdbcPreparedStatementFactory(
855 con, this, criteriaClass, cpoFunction, criteria, wheres, orderBy, nativeExpressions);
856 ps = jpsf.getPreparedStatement();
857
858 localLogger.debug("Retrieving Records");
859
860 rs = ps.executeQuery();
861 jpsf.release();
862
863 localLogger.debug("Processing Records");
864
865 rsmd = rs.getMetaData();
866
867 columnCount = rsmd.getColumnCount();
868
869 attributes = new JdbcCpoAttribute[columnCount + 1];
870
871 for (int k = 1; k <= columnCount; k++) {
872 attributes[k] = (JdbcCpoAttribute) resultClass.getAttributeData(rsmd.getColumnLabel(k));
873 }
874
875
876
877 Constructor<?> resultConstructor = result.getClass().getDeclaredConstructor();
878 JdbcResultSetCpoData[] columnData = new JdbcResultSetCpoData[columnCount + 1];
879 for (int k = 1; k <= columnCount; k++) {
880 if (attributes[k] != null) {
881 columnData[k] =
882 new JdbcResultSetCpoData(JdbcMethodMapper.getMethodMapper(), rs, attributes[k], k);
883 }
884 }
885
886 ResultSet finalRs = rs;
887 PreparedStatement finalPs = ps;
888 return StreamSupport.stream(
889 new Spliterators.AbstractSpliterator<T>(Long.MAX_VALUE, Spliterator.ORDERED) {
890 @Override
891 public boolean tryAdvance(Consumer<? super T> action) {
892 try {
893 if (!finalRs.next()) return false;
894 T bean = null;
895 try {
896 bean = (T) resultConstructor.newInstance();
897 } catch (IllegalAccessException iae) {
898 localLogger.error(
899 "=================== Could not access default constructor for Class=<"
900 + result.getClass()
901 + "> ==================");
902 throw new CpoException(
903 "Unable to access the constructor of the Return Bean", iae);
904 } catch (InstantiationException iae) {
905 throw new CpoException("Unable to instantiate Return Bean", iae);
906 }
907
908 for (int k = 1; k <= columnCount; k++) {
909 if (columnData[k] != null) {
910 attributes[k].invokeSetter(bean, columnData[k]);
911 }
912 }
913 action.accept(bean);
914 return true;
915 } catch (Exception ex) {
916 throw new RuntimeException(ex);
917 }
918 }
919 },
920 false)
921 .onClose(
922 () -> {
923 try {
924
925
926 resultSetClose(finalRs);
927 statementClose(finalPs);
928 commitLocalConnection(con);
929 closeLocalConnection(con);
930 } catch (Exception e) {
931 resultSetClose(finalRs);
932 statementClose(finalPs);
933 rollbackLocalConnection(con);
934 closeLocalConnection(con);
935 throw new RuntimeException(e);
936 }
937 });
938 } catch (Throwable t) {
939 resultSetClose(rs);
940 statementClose(ps);
941 rollbackLocalConnection(con);
942 closeLocalConnection(con);
943 String msg =
944 "processSelectGroup(String groupName, C criteria, T result, CpoWhere where,"
945 + " Collection orderBy, Connection con) failed. Error:";
946 localLogger.error(msg, t);
947 throw new CpoException(msg, t);
948 }
949 }
950
951 @Override
952 protected <T> long processUpdateGroup(
953 T bean,
954 Crud crud,
955 String groupName,
956 Collection<CpoWhere> wheres,
957 Collection<CpoOrderBy> orderBy,
958 Collection<CpoNativeFunction> nativeExpressions)
959 throws CpoException {
960 Connection c = null;
961 long updateCount = 0;
962
963 try {
964 c = getWriteConnection();
965 updateCount =
966 processUpdateGroup(bean, crud, groupName, wheres, orderBy, nativeExpressions, c);
967 commitLocalConnection(c);
968 } catch (Exception e) {
969
970 rollbackLocalConnection(c);
971 ExceptionHelper.reThrowCpoException(
972 e, "processUdateGroup(T bean, String crud, String groupName) failed");
973 } finally {
974 closeLocalConnection(c);
975 }
976
977 return updateCount;
978 }
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994 protected <T> long processUpdateGroup(
995 T bean,
996 Crud crud,
997 String groupName,
998 Collection<CpoWhere> wheres,
999 Collection<CpoOrderBy> orderBy,
1000 Collection<CpoNativeFunction> nativeExpressions,
1001 Connection con)
1002 throws CpoException {
1003 Logger localLogger = bean == null ? logger : LoggerFactory.getLogger(bean.getClass());
1004 CpoClass cpoClass;
1005 PreparedStatement ps = null;
1006
1007 JdbcPreparedStatementFactory jpsf = null;
1008 long updateCount = 0;
1009
1010 if (bean == null) {
1011 throw new CpoException(
1012 "NULL Bean passed into insertBean, deleteBean, updateBean, or upsertBean");
1013 }
1014
1015 try {
1016 cpoClass = metaDescriptor.getMetaClass(bean);
1017 List<CpoFunction> cpoFunctions =
1018 cpoClass
1019 .getFunctionGroup(adjustCrud(bean, crud, groupName, con), groupName)
1020 .getFunctions();
1021 localLogger.info(buildCpoClassLogLine(bean.getClass(), crud, groupName));
1022
1023 int numRows = 0;
1024
1025 for (CpoFunction cpoFunction : cpoFunctions) {
1026 jpsf =
1027 new JdbcPreparedStatementFactory(
1028 con, this, cpoClass, cpoFunction, bean, wheres, orderBy, nativeExpressions);
1029 ps = jpsf.getPreparedStatement();
1030 numRows += ps.executeUpdate();
1031 jpsf.release();
1032 ps.close();
1033 }
1034 localLogger.info(buildUpdatesLogLine(numRows, bean.getClass(), crud, groupName));
1035
1036 if (numRows > 0) {
1037 updateCount++;
1038 }
1039 } catch (Throwable t) {
1040 String msg =
1041 "ProcessUpdateGroup failed:"
1042 + crud.operation
1043 + ","
1044 + groupName
1045 + ","
1046 + bean.getClass().getName();
1047
1048
1049 localLogger.error(msg, t);
1050 throw new CpoException(msg, t);
1051 } finally {
1052 statementClose(ps);
1053 if (jpsf != null) {
1054 jpsf.release();
1055 }
1056 }
1057
1058 return updateCount;
1059 }
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075 protected <T> long processBatchUpdateGroup(
1076 List<T> beans,
1077 Crud crud,
1078 String groupName,
1079 Collection<CpoWhere> wheres,
1080 Collection<CpoOrderBy> orderBy,
1081 Collection<CpoNativeFunction> nativeExpressions,
1082 Connection con)
1083 throws CpoException {
1084 CpoClass jmc;
1085 List<CpoFunction> cpoFunctions;
1086 PreparedStatement ps = null;
1087 CpoFunction cpoFunction;
1088 JdbcPreparedStatementFactory jpsf = null;
1089 long updateCount = 0;
1090 Logger localLogger = logger;
1091
1092 if (beans.isEmpty()) return updateCount;
1093
1094 T firstBean = beans.getFirst();
1095 try {
1096 jmc = metaDescriptor.getMetaClass(firstBean);
1097 cpoFunctions =
1098 jmc.getFunctionGroup(adjustCrud(firstBean, crud, groupName, con), groupName)
1099 .getFunctions();
1100 localLogger = LoggerFactory.getLogger(jmc.getMetaClass());
1101
1102
1103 if (cpoFunctions.size() == 1) {
1104 localLogger.info(buildBatchLogLine(firstBean.getClass(), crud, groupName));
1105 cpoFunction = cpoFunctions.get(0);
1106 jpsf =
1107 new JdbcPreparedStatementFactory(
1108 con, this, jmc, cpoFunction, firstBean, wheres, orderBy, nativeExpressions);
1109 updateCount =
1110 new JdbcBatchExecutor(getBatchSize()).executeBatchedUpdates(jpsf, cpoFunction, beans);
1111 jpsf.release();
1112 localLogger.info(buildUpdatesLogLine(updateCount, firstBean.getClass(), crud, groupName));
1113 } else {
1114 localLogger.info(buildCpoClassLogLine(firstBean.getClass(), crud, groupName));
1115 for (T bean : beans) {
1116 for (CpoFunction function : cpoFunctions) {
1117 jpsf =
1118 new JdbcPreparedStatementFactory(
1119 con, this, jmc, function, bean, wheres, orderBy, nativeExpressions);
1120 ps = jpsf.getPreparedStatement();
1121 updateCount += ps.executeUpdate();
1122 jpsf.release();
1123 ps.close();
1124 }
1125 }
1126 localLogger.info(buildUpdatesLogLine(updateCount, firstBean.getClass(), crud, groupName));
1127 }
1128
1129 } catch (Throwable t) {
1130 String msg =
1131 "ProcessUpdateGroup failed:"
1132 + crud.operation
1133 + ","
1134 + groupName
1135 + ","
1136 + firstBean.getClass().getName();
1137
1138
1139 localLogger.error(msg, t);
1140 throw new CpoException(msg, t);
1141 } finally {
1142 statementClose(ps);
1143 if (jpsf != null) {
1144 jpsf.release();
1145 }
1146 }
1147
1148 return updateCount;
1149 }
1150
1151 @Override
1152 protected <T> long processUpdateGroup(
1153 List<T> beans,
1154 Crud crud,
1155 String groupName,
1156 Collection<CpoWhere> wheres,
1157 Collection<CpoOrderBy> orderBy,
1158 Collection<CpoNativeFunction> nativeExpressions)
1159 throws CpoException {
1160 Connection c = null;
1161 long updateCount = 0;
1162
1163 try {
1164 c = getWriteConnection();
1165
1166 updateCount =
1167 processUpdateGroup(beans, crud, groupName, wheres, orderBy, nativeExpressions, c);
1168 commitLocalConnection(c);
1169 } catch (Exception e) {
1170
1171 rollbackLocalConnection(c);
1172 ExceptionHelper.reThrowCpoException(
1173 e, "processUpdateGroup(Collection beans, String crud, String groupName) failed");
1174 } finally {
1175 closeLocalConnection(c);
1176 }
1177
1178 return updateCount;
1179 }
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195 protected <T> long processUpdateGroup(
1196 List<T> beans,
1197 Crud crud,
1198 String groupName,
1199 Collection<CpoWhere> wheres,
1200 Collection<CpoOrderBy> orderBy,
1201 Collection<CpoNativeFunction> nativeExpressions,
1202 Connection con)
1203 throws CpoException {
1204 long updateCount = 0;
1205
1206 if (beans.isEmpty()) return updateCount;
1207
1208 if (capabilities.batchUpdatesSupported() && !Crud.UPSERT.equals(crud)) {
1209 updateCount =
1210 processBatchUpdateGroup(beans, crud, groupName, wheres, orderBy, nativeExpressions, con);
1211 } else {
1212 for (T bean : beans) {
1213 updateCount +=
1214 processUpdateGroup(bean, crud, groupName, wheres, orderBy, nativeExpressions, con);
1215 }
1216 }
1217
1218 return updateCount;
1219 }
1220
1221 private void statementClose(Statement s) {
1222 if (s != null) {
1223 try {
1224 s.close();
1225 } catch (Exception e) {
1226 if (logger.isTraceEnabled()) {
1227 logger.trace(e.getMessage());
1228 }
1229 }
1230 }
1231 }
1232
1233 private void resultSetClose(ResultSet rs) {
1234 if (rs != null) {
1235 try {
1236 rs.close();
1237 } catch (Exception e) {
1238 if (logger.isTraceEnabled()) {
1239 logger.trace(e.getMessage());
1240 }
1241 }
1242 }
1243 }
1244
1245 @Override
1246 public CpoMetaDescriptor getCpoMetaDescriptor() {
1247 return metaDescriptor;
1248 }
1249
1250 @Override
1251 public List<CpoAttribute> getCpoAttributes(String expression) throws CpoException {
1252 List<CpoAttribute> attributes = new ArrayList<>();
1253
1254 if (expression != null && !expression.isEmpty()) {
1255 Connection c = null;
1256 PreparedStatement ps = null;
1257 ResultSet rs = null;
1258 try {
1259 c = getReadConnection();
1260 ps = c.prepareStatement(expression);
1261 rs = ps.executeQuery();
1262 ResultSetMetaData rsmd = rs.getMetaData();
1263 for (int i = 1; i <= rsmd.getColumnCount(); i++) {
1264 JdbcCpoAttribute attribute = new JdbcCpoAttribute();
1265 attribute.setDataName(rsmd.getColumnLabel(i));
1266 attribute.setDbColumn(rsmd.getColumnName(i));
1267 try {
1268 attribute.setDbTable(rsmd.getTableName(i));
1269 } catch (Exception e) {
1270
1271 logger.info("Could not get table name", e);
1272 }
1273
1274 DataTypeMapEntry<?> dataTypeMapEntry =
1275 metaDescriptor.getDataTypeMapEntry(rsmd.getColumnType(i));
1276 attribute.setDataType(dataTypeMapEntry.dataTypeName());
1277 attribute.setDataTypeInt(dataTypeMapEntry.dataTypeInt());
1278 attribute.setJavaType(dataTypeMapEntry.javaClass().getName());
1279 attribute.setJavaName(dataTypeMapEntry.makeJavaName(rsmd.getColumnLabel(i)));
1280
1281 attributes.add(attribute);
1282 }
1283 } catch (Throwable t) {
1284 logger.error(ExceptionHelper.getLocalizedMessage(t), t);
1285 throw new CpoException("Error Generating Attributes", t);
1286 } finally {
1287 resultSetClose(rs);
1288 statementClose(ps);
1289
1290 rollbackLocalConnection(c);
1291 closeLocalConnection(c);
1292 }
1293 }
1294 return attributes;
1295 }
1296 }