1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.synchronoss.cpo.jdbc;
22
23 import java.io.StringReader;
24 import java.lang.reflect.InvocationTargetException;
25 import java.sql.Connection;
26 import java.sql.PreparedStatement;
27 import java.sql.SQLException;
28 import java.util.Map.Entry;
29 import java.util.*;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32 import org.synchronoss.cpo.*;
33 import org.synchronoss.cpo.helper.ExceptionHelper;
34 import org.synchronoss.cpo.meta.domain.CpoArgument;
35 import org.synchronoss.cpo.meta.domain.CpoClass;
36 import org.synchronoss.cpo.meta.domain.CpoFunction;
37
38
39
40
41
42
43
44 public class JdbcPreparedStatementFactory implements CpoReleasible {
45
46
47
48
49 private static final long serialVersionUID = 1L;
50
51
52
53 private static final Logger logger = LoggerFactory.getLogger(JdbcPreparedStatementFactory.class);
54 private Logger localLogger = null;
55 private PreparedStatement ps_ = null;
56
57 @SuppressWarnings("unused")
58 private JdbcPreparedStatementFactory() {
59 }
60 private List<CpoReleasible> releasibles = new ArrayList<CpoReleasible>();
61 private static final String WHERE_MARKER = "__CPO_WHERE__";
62 private static final String ORDERBY_MARKER = "__CPO_ORDERBY__";
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80 public <T> JdbcPreparedStatementFactory(Connection conn, JdbcCpoAdapter jca, CpoClass criteria,
81 CpoFunction function, T obj, Collection<CpoWhere> wheres, Collection<CpoOrderBy> orderBy,
82 Collection<CpoNativeFunction> nativeQueries) throws CpoException {
83
84
85 List<BindAttribute> bindValues = getBindValues(function, obj);
86
87 String sql = buildSql(criteria, function.getExpression(), wheres, orderBy, nativeQueries, bindValues);
88
89 localLogger = obj == null ? logger : LoggerFactory.getLogger(obj.getClass());
90
91 localLogger.debug("CpoFunction SQL = <" + sql + ">");
92
93 PreparedStatement pstmt = null;
94
95 try {
96 pstmt = conn.prepareStatement(sql);
97 } catch (SQLException se) {
98 localLogger.error("Error Instantiating JdbcPreparedStatementFactory SQL=<" + sql + ">" + ExceptionHelper.getLocalizedMessage(se));
99 throw new CpoException(se);
100 }
101 setPreparedStatement(pstmt);
102
103 setBindValues(bindValues);
104
105 }
106
107
108
109
110
111
112
113
114
115
116
117
118
119 private <T> String buildSql(CpoClass cpoClass, String sql, Collection<CpoWhere> wheres, Collection<CpoOrderBy> orderBy, Collection<CpoNativeFunction> nativeQueries, List<BindAttribute> bindValues) throws CpoException {
120 StringBuilder sqlText = new StringBuilder();
121
122 sqlText.append(sql);
123
124 if (wheres != null) {
125 for (CpoWhere where : wheres) {
126 JdbcWhereBuilder<T> jwb = new JdbcWhereBuilder<T>(cpoClass);
127 JdbcCpoWhere jcw = (JdbcCpoWhere) where;
128
129
130 try {
131 jcw.acceptDFVisitor(jwb);
132 } catch (Exception e) {
133 throw new CpoException("Unable to build WHERE clause", e);
134 }
135
136 if (sqlText.indexOf(jcw.getName()) == -1) {
137 sqlText.append(" ");
138 sqlText.append(jwb.getWhereClause());
139 bindValues.addAll(jwb.getBindValues());
140 } else {
141 sqlText = replaceMarker(sqlText, jcw.getName(), jwb, bindValues);
142 }
143 }
144 }
145
146
147 if (orderBy != null) {
148 HashMap<String, StringBuilder> mapOrderBy = new HashMap<String, StringBuilder>();
149 try {
150 for (CpoOrderBy ob : orderBy) {
151 StringBuilder sb = mapOrderBy.get(ob.getMarker());
152 if (sb == null) {
153 sb = new StringBuilder(" ORDER BY ");
154 mapOrderBy.put(ob.getMarker(), sb);
155 } else {
156 sb.append(",");
157 }
158 sb.append(((JdbcCpoOrderBy) ob).toString(cpoClass));
159 }
160 } catch (CpoException ce) {
161 throw new CpoException("Error Processing OrderBy Attribute<" + ExceptionHelper.getLocalizedMessage(ce) + "> not Found. JDBC Expression=<" + sqlText.toString() + ">");
162 }
163
164 Set<Entry<String, StringBuilder>> entries = mapOrderBy.entrySet();
165 for (Entry<String, StringBuilder> entry : entries) {
166 if (sqlText.indexOf(entry.getKey()) == -1) {
167 sqlText.append(entry.getValue().toString());
168 } else {
169 sqlText = replaceMarker(sqlText, entry.getKey(), entry.getValue().toString());
170 }
171 }
172 }
173
174 if (nativeQueries != null) {
175 for (CpoNativeFunction cnq : nativeQueries) {
176 if (cnq.getMarker() == null || sqlText.indexOf(cnq.getMarker()) == -1) {
177 if (cnq.getExpression() != null && cnq.getExpression().length() > 0) {
178 sqlText.append(" ");
179 sqlText.append(cnq.getExpression());
180 }
181 } else {
182 sqlText = replaceMarker(sqlText, cnq.getMarker(), cnq.getExpression());
183 }
184 }
185 }
186
187
188 sqlText = replaceMarker(sqlText, WHERE_MARKER, "");
189 sqlText = replaceMarker(sqlText, ORDERBY_MARKER, "");
190
191 return sqlText.toString();
192 }
193
194 private StringBuilder replaceMarker(StringBuilder source, String marker, String replace) {
195 int attrOffset;
196 int fromIndex = 0;
197 int mLength = marker.length();
198 String replaceText = replace == null ? "" : replace;
199 int rLength = replaceText.length();
200
201
202 if (source != null && source.length() > 0) {
203 while ((attrOffset = source.indexOf(marker, fromIndex)) != -1) {
204 source.replace(attrOffset, attrOffset + mLength, replaceText);
205 fromIndex = attrOffset + rLength;
206 }
207 }
208
209
210 return source;
211 }
212
213 private <T> StringBuilder replaceMarker(StringBuilder source, String marker, JdbcWhereBuilder<T> jwb, List<BindAttribute> bindValues) {
214 int attrOffset;
215 int fromIndex = 0;
216 int mLength = marker.length();
217 String replace = jwb.getWhereClause();
218 int rLength = replace.length();
219 Collection<BindAttribute> jwbBindValues = jwb.getBindValues();
220
221
222 if (source != null && source.length() > 0) {
223 while ((attrOffset = source.indexOf(marker, fromIndex)) != -1) {
224 source.replace(attrOffset, attrOffset + mLength, replace);
225 fromIndex = attrOffset + rLength;
226 bindValues.addAll(countBindMarkers(source.substring(0, attrOffset)), jwbBindValues);
227 }
228 }
229
230
231 return source;
232 }
233
234 private int countBindMarkers(String source) {
235 StringReader reader;
236 int rc;
237 int qMarks = 0;
238 boolean inDoubleQuotes = false;
239 boolean inSingleQuotes = false;
240
241 if (source != null) {
242 reader = new StringReader(source);
243
244 try {
245 do {
246 rc = reader.read();
247 if (((char) rc) == '\'') {
248 inSingleQuotes = !inSingleQuotes;
249 } else if (((char) rc) == '"') {
250 inDoubleQuotes = !inDoubleQuotes;
251 } else if (!inSingleQuotes && !inDoubleQuotes && ((char) rc) == '?') {
252 qMarks++;
253 }
254 } while (rc != -1);
255 } catch (Exception e) {
256 logger.error("error counting bind markers");
257 }
258 }
259
260 return qMarks;
261 }
262
263
264
265
266 public PreparedStatement getPreparedStatement() {
267 return ps_;
268 }
269
270 protected void setPreparedStatement(PreparedStatement ps) {
271 ps_ = ps;
272 }
273
274
275
276
277
278
279 public void AddReleasible(CpoReleasible releasible) {
280 if (releasible != null) {
281 releasibles.add(releasible);
282 }
283 }
284
285
286
287
288
289 @Override
290 public void release() throws CpoException {
291 for (CpoReleasible releasible : releasibles) {
292 try {
293 releasible.release();
294 } catch (CpoException ce) {
295 localLogger.error("Error Releasing Prepared Statement Transform Object", ce);
296 throw ce;
297 }
298 }
299 }
300
301
302
303
304
305
306 protected List<BindAttribute> getBindValues(CpoFunction function, Object obj) throws CpoException {
307 List<BindAttribute> bindValues = new ArrayList<BindAttribute>();
308 List<CpoArgument> arguments = function.getArguments();
309 for (CpoArgument argument : arguments) {
310 if (argument == null) {
311 throw new CpoException("CpoArgument is null!");
312 }
313 bindValues.add(new BindAttribute((JdbcCpoAttribute) argument.getAttribute(), obj));
314 }
315 return bindValues;
316 }
317
318
319
320
321
322
323 protected void setBindValues(Collection<BindAttribute> bindValues) throws CpoException {
324
325 if (bindValues != null) {
326 int index = 1;
327
328
329
330 for (BindAttribute bindAttr : bindValues) {
331 Object bindObject = bindAttr.getBindObject();
332 JdbcCpoAttribute ja = bindAttr.getJdbcAttribute();
333
334
335
336 JavaSqlMethod<?> jsm = null;
337 jsm = JavaSqlMethods.getJavaSqlMethod(bindObject.getClass());
338
339 if (jsm != null) {
340 try {
341 if (ja == null) {
342 localLogger.debug(bindAttr.getName() + "=" + bindObject);
343 } else {
344 localLogger.debug(ja.getDataName() + "=" + bindObject);
345 }
346 jsm.getPsSetter().invoke(this.getPreparedStatement(), new Object[]{index++, bindObject});
347 } catch (IllegalAccessException iae) {
348 localLogger.error("Error Accessing Prepared Statement Setter: " + ExceptionHelper.getLocalizedMessage(iae));
349 throw new CpoException(iae);
350 } catch (InvocationTargetException ite) {
351 localLogger.error("Error Invoking Prepared Statement Setter: " + ExceptionHelper.getLocalizedMessage(ite));
352 throw new CpoException(ite.getCause());
353 }
354 } else {
355 CpoData cpoData = new PreparedStatementCpoData(this, ja, index++);
356 cpoData.invokeSetter(bindObject);
357 }
358 }
359 }
360
361 }
362 }