1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.jdbc.core.simple;
18
19 import java.util.ArrayList;
20 import java.util.LinkedHashMap;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Set;
24 import javax.sql.DataSource;
25
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28
29 import org.springframework.dao.InvalidDataAccessApiUsageException;
30 import org.springframework.jdbc.core.CallableStatementCreator;
31 import org.springframework.jdbc.core.CallableStatementCreatorFactory;
32 import org.springframework.jdbc.core.JdbcTemplate;
33 import org.springframework.jdbc.core.RowMapper;
34 import org.springframework.jdbc.core.SqlParameter;
35 import org.springframework.jdbc.core.metadata.CallMetaDataContext;
36 import org.springframework.jdbc.core.namedparam.SqlParameterSource;
37 import org.springframework.util.Assert;
38 import org.springframework.util.StringUtils;
39
40
41
42
43
44
45
46
47
48
49 public abstract class AbstractJdbcCall {
50
51
52 protected final Log logger = LogFactory.getLog(getClass());
53
54
55 private final JdbcTemplate jdbcTemplate;
56
57
58 private final CallMetaDataContext callMetaDataContext = new CallMetaDataContext();
59
60
61 private final List<SqlParameter> declaredParameters = new ArrayList<SqlParameter>();
62
63
64 private final Map<String, RowMapper<?>> declaredRowMappers = new LinkedHashMap<String, RowMapper<?>>();
65
66
67
68
69
70 private boolean compiled = false;
71
72
73 private String callString;
74
75
76
77
78
79 private CallableStatementCreatorFactory callableStatementFactory;
80
81
82
83
84
85
86 protected AbstractJdbcCall(DataSource dataSource) {
87 this.jdbcTemplate = new JdbcTemplate(dataSource);
88 }
89
90
91
92
93
94 protected AbstractJdbcCall(JdbcTemplate jdbcTemplate) {
95 Assert.notNull(jdbcTemplate, "JdbcTemplate must not be null");
96 this.jdbcTemplate = jdbcTemplate;
97 }
98
99
100
101
102
103 public JdbcTemplate getJdbcTemplate() {
104 return this.jdbcTemplate;
105 }
106
107
108
109
110 public void setProcedureName(String procedureName) {
111 this.callMetaDataContext.setProcedureName(procedureName);
112 }
113
114
115
116
117 public String getProcedureName() {
118 return this.callMetaDataContext.getProcedureName();
119 }
120
121
122
123
124 public void setInParameterNames(Set<String> inParameterNames) {
125 this.callMetaDataContext.setLimitedInParameterNames(inParameterNames);
126 }
127
128
129
130
131 public Set<String> getInParameterNames() {
132 return this.callMetaDataContext.getLimitedInParameterNames();
133 }
134
135
136
137
138 public void setCatalogName(String catalogName) {
139 this.callMetaDataContext.setCatalogName(catalogName);
140 }
141
142
143
144
145 public String getCatalogName() {
146 return this.callMetaDataContext.getCatalogName();
147 }
148
149
150
151
152 public void setSchemaName(String schemaName) {
153 this.callMetaDataContext.setSchemaName(schemaName);
154 }
155
156
157
158
159 public String getSchemaName() {
160 return this.callMetaDataContext.getSchemaName();
161 }
162
163
164
165
166
167 public void setFunction(boolean function) {
168 this.callMetaDataContext.setFunction(function);
169 }
170
171
172
173
174 public boolean isFunction() {
175 return this.callMetaDataContext.isFunction();
176 }
177
178
179
180
181
182 public void setReturnValueRequired(boolean returnValueRequired) {
183 this.callMetaDataContext.setReturnValueRequired(returnValueRequired);
184 }
185
186
187
188
189 public boolean isReturnValueRequired() {
190 return this.callMetaDataContext.isReturnValueRequired();
191 }
192
193
194
195
196
197 public void setAccessCallParameterMetaData(boolean accessCallParameterMetaData) {
198 this.callMetaDataContext.setAccessCallParameterMetaData(accessCallParameterMetaData);
199 }
200
201
202
203
204 public String getCallString() {
205 return this.callString;
206 }
207
208
209
210
211 protected CallableStatementCreatorFactory getCallableStatementFactory() {
212 return this.callableStatementFactory;
213 }
214
215
216
217
218
219
220
221
222
223
224 public void addDeclaredParameter(SqlParameter parameter) {
225 Assert.notNull(parameter, "The supplied parameter must not be null");
226 if (!StringUtils.hasText(parameter.getName())) {
227 throw new InvalidDataAccessApiUsageException(
228 "You must specify a parameter name when declaring parameters for \"" + getProcedureName() + "\"");
229 }
230 this.declaredParameters.add(parameter);
231 if (logger.isDebugEnabled()) {
232 logger.debug("Added declared parameter for [" + getProcedureName() + "]: " + parameter.getName());
233 }
234 }
235
236
237
238
239
240
241 public void addDeclaredRowMapper(String parameterName, RowMapper<?> rowMapper) {
242 this.declaredRowMappers.put(parameterName, rowMapper);
243 if (logger.isDebugEnabled()) {
244 logger.debug("Added row mapper for [" + getProcedureName() + "]: " + parameterName);
245 }
246 }
247
248
249
250
251
252
253
254
255
256
257
258
259
260 public synchronized final void compile() throws InvalidDataAccessApiUsageException {
261 if (!isCompiled()) {
262 if (getProcedureName() == null) {
263 throw new InvalidDataAccessApiUsageException("Procedure or Function name is required");
264 }
265 try {
266 this.jdbcTemplate.afterPropertiesSet();
267 }
268 catch (IllegalArgumentException ex) {
269 throw new InvalidDataAccessApiUsageException(ex.getMessage());
270 }
271 compileInternal();
272 this.compiled = true;
273 if (logger.isDebugEnabled()) {
274 logger.debug("SqlCall for " + (isFunction() ? "function" : "procedure") +
275 " [" + getProcedureName() + "] compiled");
276 }
277 }
278 }
279
280
281
282
283
284
285 protected void compileInternal() {
286 this.callMetaDataContext.initializeMetaData(getJdbcTemplate().getDataSource());
287
288
289 for (Map.Entry<String, RowMapper<?>> entry : this.declaredRowMappers.entrySet()) {
290 SqlParameter resultSetParameter =
291 this.callMetaDataContext.createReturnResultSetParameter(entry.getKey(), entry.getValue());
292 this.declaredParameters.add(resultSetParameter);
293 }
294 this.callMetaDataContext.processParameters(this.declaredParameters);
295
296 this.callString = this.callMetaDataContext.createCallString();
297 if (logger.isDebugEnabled()) {
298 logger.debug("Compiled stored procedure. Call string is [" + this.callString + "]");
299 }
300
301 this.callableStatementFactory =
302 new CallableStatementCreatorFactory(getCallString(), this.callMetaDataContext.getCallParameters());
303 this.callableStatementFactory.setNativeJdbcExtractor(getJdbcTemplate().getNativeJdbcExtractor());
304
305 onCompileInternal();
306 }
307
308
309
310
311
312 protected void onCompileInternal() {
313 }
314
315
316
317
318
319 public boolean isCompiled() {
320 return this.compiled;
321 }
322
323
324
325
326
327
328 protected void checkCompiled() {
329 if (!isCompiled()) {
330 logger.debug("JdbcCall call not compiled before execution - invoking compile");
331 compile();
332 }
333 }
334
335
336
337
338
339
340
341
342
343
344
345 protected Map<String, Object> doExecute(SqlParameterSource parameterSource) {
346 checkCompiled();
347 Map<String, Object> params = matchInParameterValuesWithCallParameters(parameterSource);
348 return executeCallInternal(params);
349 }
350
351
352
353
354
355
356
357 protected Map<String, Object> doExecute(Object... args) {
358 checkCompiled();
359 Map<String, ?> params = matchInParameterValuesWithCallParameters(args);
360 return executeCallInternal(params);
361 }
362
363
364
365
366
367
368 protected Map<String, Object> doExecute(Map<String, ?> args) {
369 checkCompiled();
370 Map<String, ?> params = matchInParameterValuesWithCallParameters(args);
371 return executeCallInternal(params);
372 }
373
374
375
376
377 private Map<String, Object> executeCallInternal(Map<String, ?> args) {
378 CallableStatementCreator csc = getCallableStatementFactory().newCallableStatementCreator(args);
379 if (logger.isDebugEnabled()) {
380 logger.debug("The following parameters are used for call " + getCallString() + " with " + args);
381 int i = 1;
382 for (SqlParameter param : getCallParameters()) {
383 logger.debug(i + ": " + param.getName() + ", SQL type "+ param.getSqlType() + ", type name " +
384 param.getTypeName() + ", parameter class [" + param.getClass().getName() + "]");
385 i++;
386 }
387 }
388 return getJdbcTemplate().call(csc, getCallParameters());
389 }
390
391
392
393
394
395
396 protected String getScalarOutParameterName() {
397 return this.callMetaDataContext.getScalarOutParameterName();
398 }
399
400
401
402
403
404 protected List<SqlParameter> getCallParameters() {
405 return this.callMetaDataContext.getCallParameters();
406 }
407
408
409
410
411
412
413
414 protected Map<String, Object> matchInParameterValuesWithCallParameters(SqlParameterSource parameterSource) {
415 return this.callMetaDataContext.matchInParameterValuesWithCallParameters(parameterSource);
416 }
417
418
419
420
421
422
423
424 private Map<String, ?> matchInParameterValuesWithCallParameters(Object[] args) {
425 return this.callMetaDataContext.matchInParameterValuesWithCallParameters(args);
426 }
427
428
429
430
431
432
433
434 protected Map<String, ?> matchInParameterValuesWithCallParameters(Map<String, ?> args) {
435 return this.callMetaDataContext.matchInParameterValuesWithCallParameters(args);
436 }
437
438 }