1
2
3
4
5
6
7
8
9
10
11 package org.mule.providers.jdbc;
12
13 import org.mule.config.ExceptionHelper;
14 import org.mule.config.i18n.CoreMessages;
15 import org.mule.providers.AbstractConnector;
16 import org.mule.providers.jdbc.i18n.JdbcMessages;
17 import org.mule.transaction.TransactionCoordination;
18 import org.mule.umo.TransactionException;
19 import org.mule.umo.UMOComponent;
20 import org.mule.umo.UMOException;
21 import org.mule.umo.UMOTransaction;
22 import org.mule.umo.endpoint.UMOEndpoint;
23 import org.mule.umo.endpoint.UMOImmutableEndpoint;
24 import org.mule.umo.lifecycle.InitialisationException;
25 import org.mule.umo.provider.UMOMessageReceiver;
26 import org.mule.util.ClassUtils;
27 import org.mule.util.ExceptionUtils;
28 import org.mule.util.StringUtils;
29 import org.mule.util.properties.BeanPropertyExtractor;
30 import org.mule.util.properties.MapPropertyExtractor;
31 import org.mule.util.properties.MessagePropertyExtractor;
32 import org.mule.util.properties.PayloadPropertyExtractor;
33 import org.mule.util.properties.PropertyExtractor;
34
35 import java.sql.Connection;
36 import java.util.HashSet;
37 import java.util.Hashtable;
38 import java.util.Iterator;
39 import java.util.List;
40 import java.util.Map;
41 import java.util.Set;
42 import java.util.regex.Matcher;
43 import java.util.regex.Pattern;
44
45 import javax.naming.Context;
46 import javax.naming.InitialContext;
47 import javax.naming.NamingException;
48 import javax.sql.DataSource;
49
50 import org.apache.commons.dbutils.QueryRunner;
51 import org.apache.commons.dbutils.ResultSetHandler;
52
53 public class JdbcConnector extends AbstractConnector
54 {
55
56
57 public static final String PROPERTY_POLLING_FREQUENCY = "pollingFrequency";
58 public static final long DEFAULT_POLLING_FREQUENCY = 1000;
59
60 private static final String DEFAULT_QUERY_RUNNER = "org.apache.commons.dbutils.QueryRunner";
61 private static final String DEFAULT_RESULTSET_HANDLER = "org.apache.commons.dbutils.handlers.MapListHandler";
62
63 private static final Pattern STATEMENT_ARGS = Pattern.compile("\\$\\{[^\\}]*\\}");
64
65
66 static
67 {
68 ExceptionHelper.registerExceptionReader(new SQLExceptionReader());
69 }
70
71 protected long pollingFrequency = 0;
72 protected DataSource dataSource;
73 protected String dataSourceJndiName;
74 protected Context jndiContext;
75 protected String jndiInitialFactory;
76 protected String jndiProviderUrl;
77 protected Map providerProperties;
78 protected Map queries;
79 protected String resultSetHandler = DEFAULT_RESULTSET_HANDLER;
80 protected String queryRunner = DEFAULT_QUERY_RUNNER;
81 protected Set queryValueExtractors;
82 protected Set propertyExtractors;
83
84 protected void doInitialise() throws InitialisationException
85 {
86 try
87 {
88
89
90 if (dataSource == null)
91 {
92 initJndiContext();
93 createDataSource();
94 }
95
96 if (queryValueExtractors == null)
97 {
98
99 queryValueExtractors = new HashSet();
100 queryValueExtractors.add(MessagePropertyExtractor.class.getName());
101 queryValueExtractors.add(NowPropertyExtractor.class.getName());
102 queryValueExtractors.add(PayloadPropertyExtractor.class.getName());
103 queryValueExtractors.add(MapPropertyExtractor.class.getName());
104 queryValueExtractors.add(BeanPropertyExtractor.class.getName());
105
106 if (ClassUtils.isClassOnPath("org.mule.util.properties.Dom4jPropertyExtractor", getClass()))
107 {
108 queryValueExtractors.add("org.mule.util.properties.Dom4jPropertyExtractor");
109 }
110
111 if (ClassUtils.isClassOnPath("org.mule.util.properties.JDomPropertyExtractor", getClass()))
112 {
113 queryValueExtractors.add("org.mule.util.properties.JDomPropertyExtractor");
114 }
115 }
116
117 propertyExtractors = new HashSet();
118 for (Iterator iterator = queryValueExtractors.iterator(); iterator.hasNext();)
119 {
120 String s = (String)iterator.next();
121 propertyExtractors.add(ClassUtils.instanciateClass(s, ClassUtils.NO_ARGS));
122 }
123 }
124 catch (Exception e)
125 {
126 throw new InitialisationException(CoreMessages.failedToCreate("Jdbc Connector"), e, this);
127 }
128 }
129
130 protected void doDispose()
131 {
132
133 }
134
135 protected void doConnect() throws Exception
136 {
137
138 }
139
140 protected void doDisconnect() throws Exception
141 {
142
143 }
144
145 protected void doStart() throws UMOException
146 {
147
148 }
149
150 protected void doStop() throws UMOException
151 {
152
153 }
154
155
156
157
158
159
160 public String getProtocol()
161 {
162 return "jdbc";
163 }
164
165 public UMOMessageReceiver createReceiver(UMOComponent component, UMOEndpoint endpoint) throws Exception
166 {
167 Map props = endpoint.getProperties();
168 if (props != null)
169 {
170 String tempPolling = (String) props.get(PROPERTY_POLLING_FREQUENCY);
171 if (tempPolling != null)
172 {
173 pollingFrequency = Long.parseLong(tempPolling);
174 }
175 }
176
177 if (pollingFrequency <= 0)
178 {
179 pollingFrequency = DEFAULT_POLLING_FREQUENCY;
180 }
181
182 String[] params = getReadAndAckStatements(endpoint);
183 return getServiceDescriptor().createMessageReceiver(this, component, endpoint, params);
184 }
185
186 protected void initJndiContext() throws NamingException
187 {
188 if (this.jndiContext == null)
189 {
190 Hashtable props = new Hashtable();
191 if (this.jndiInitialFactory != null)
192 {
193 props.put(Context.INITIAL_CONTEXT_FACTORY, this.jndiInitialFactory);
194 }
195 if (this.jndiProviderUrl != null)
196 {
197 props.put(Context.PROVIDER_URL, jndiProviderUrl);
198 }
199 if (this.providerProperties != null)
200 {
201 props.putAll(this.providerProperties);
202 }
203 this.jndiContext = new InitialContext(props);
204 }
205
206 }
207
208 protected void createDataSource() throws InitialisationException, NamingException
209 {
210 Object temp = this.jndiContext.lookup(this.dataSourceJndiName);
211 if (temp instanceof DataSource)
212 {
213 dataSource = (DataSource)temp;
214 }
215 else
216 {
217 throw new InitialisationException(
218 JdbcMessages.jndiResourceNotFound(this.dataSourceJndiName), this);
219 }
220 }
221
222 public String[] getReadAndAckStatements(UMOImmutableEndpoint endpoint)
223 {
224 String str;
225
226 String readStmt;
227 if ((str = (String)endpoint.getProperty("sql")) != null)
228 {
229 readStmt = str;
230 }
231 else
232 {
233 readStmt = endpoint.getEndpointURI().getAddress();
234 }
235
236 String ackStmt;
237 if ((str = (String)endpoint.getProperty("ack")) != null)
238 {
239 ackStmt = str;
240 if ((str = getQuery(endpoint, ackStmt)) != null)
241 {
242 ackStmt = str;
243 }
244 }
245 else
246 {
247 ackStmt = readStmt + ".ack";
248 if ((str = getQuery(endpoint, ackStmt)) != null)
249 {
250 ackStmt = str;
251 }
252 else
253 {
254 ackStmt = null;
255 }
256 }
257
258 if ((str = getQuery(endpoint, readStmt)) != null)
259 {
260 readStmt = str;
261 }
262 if (readStmt == null)
263 {
264 throw new IllegalArgumentException("Read statement should not be null");
265 }
266 if (!"select".equalsIgnoreCase(readStmt.substring(0, 6)))
267 {
268 throw new IllegalArgumentException("Read statement should be a select sql statement");
269 }
270 if (ackStmt != null)
271 {
272 if (!"insert".equalsIgnoreCase(ackStmt.substring(0, 6))
273 && !"update".equalsIgnoreCase(ackStmt.substring(0, 6))
274 && !"delete".equalsIgnoreCase(ackStmt.substring(0, 6)))
275 {
276 throw new IllegalArgumentException(
277 "Ack statement should be an insert / update / delete sql statement");
278 }
279 }
280 return new String[]{readStmt, ackStmt};
281 }
282
283 public String getQuery(UMOImmutableEndpoint endpoint, String stmt)
284 {
285 Object query = null;
286 if (endpoint != null && endpoint.getProperties() != null)
287 {
288 Object queries = endpoint.getProperties().get("queries");
289 if (queries instanceof Map)
290 {
291 query = ((Map)queries).get(stmt);
292 }
293 }
294 if (query == null)
295 {
296 if (this.queries != null)
297 {
298 query = this.queries.get(stmt);
299 }
300 }
301 return query == null ? null : query.toString();
302 }
303
304
305
306
307 public DataSource getDataSource()
308 {
309 return dataSource;
310 }
311
312
313
314
315 public void setDataSource(DataSource dataSource)
316 {
317 this.dataSource = dataSource;
318 }
319
320
321
322
323 public long getPollingFrequency()
324 {
325 return pollingFrequency;
326 }
327
328
329
330
331 public void setPollingFrequency(long pollingFrequency)
332 {
333 this.pollingFrequency = pollingFrequency;
334 }
335
336
337
338
339 public Map getQueries()
340 {
341 return queries;
342 }
343
344
345
346
347 public void setQueries(Map queries)
348 {
349 this.queries = queries;
350 }
351
352
353
354
355 public String getDataSourceJndiName()
356 {
357 return dataSourceJndiName;
358 }
359
360
361
362
363 public void setDataSourceJndiName(String dataSourceJndiName)
364 {
365 this.dataSourceJndiName = dataSourceJndiName;
366 }
367
368
369
370
371 public Context getJndiContext()
372 {
373 return jndiContext;
374 }
375
376
377
378
379 public void setJndiContext(Context jndiContext)
380 {
381 this.jndiContext = jndiContext;
382 }
383
384
385
386
387 public String getJndiInitialFactory()
388 {
389 return jndiInitialFactory;
390 }
391
392
393
394
395 public void setJndiInitialFactory(String jndiInitialFactory)
396 {
397 this.jndiInitialFactory = jndiInitialFactory;
398 }
399
400
401
402
403 public String getJndiProviderUrl()
404 {
405 return jndiProviderUrl;
406 }
407
408
409
410
411 public void setJndiProviderUrl(String jndiProviderUrl)
412 {
413 this.jndiProviderUrl = jndiProviderUrl;
414 }
415
416
417
418
419 public Map getProviderProperties()
420 {
421 return providerProperties;
422 }
423
424
425
426
427 public void setProviderProperties(Map providerProperties)
428 {
429 this.providerProperties = providerProperties;
430 }
431
432 public Connection getConnection() throws Exception
433 {
434 UMOTransaction tx = TransactionCoordination.getInstance().getTransaction();
435 if (tx != null)
436 {
437 if (tx.hasResource(dataSource))
438 {
439 logger.debug("Retrieving connection from current transaction");
440 return (Connection)tx.getResource(dataSource);
441 }
442 }
443 logger.debug("Retrieving new connection from data source");
444 Connection con = dataSource.getConnection();
445
446 if (tx != null)
447 {
448 logger.debug("Binding connection to current transaction");
449 try
450 {
451 tx.bindResource(dataSource, con);
452 }
453 catch (TransactionException e)
454 {
455 throw new RuntimeException("Could not bind connection to current transaction", e);
456 }
457 }
458 return con;
459 }
460
461
462
463
464 public String getResultSetHandler()
465 {
466 return this.resultSetHandler;
467 }
468
469
470
471
472 public void setResultSetHandler(String resultSetHandler)
473 {
474 this.resultSetHandler = resultSetHandler;
475 }
476
477
478
479
480
481 protected ResultSetHandler createResultSetHandler()
482 {
483 try
484 {
485 return (ResultSetHandler) ClassUtils.instanciateClass(getResultSetHandler(),
486 ClassUtils.NO_ARGS);
487 }
488 catch (Exception e)
489 {
490 throw new IllegalArgumentException("Error creating instance of the resultSetHandler class :"
491 + getResultSetHandler() + System.getProperty("line.separator")
492 + ExceptionUtils.getFullStackTrace(e));
493 }
494 }
495
496 public Set getQueryValueExtractors()
497 {
498 return queryValueExtractors;
499 }
500
501 public void setQueryValueExtractors(Set queryValueExtractors)
502 {
503 this.queryValueExtractors = queryValueExtractors;
504 }
505
506
507
508
509 public String getQueryRunner()
510 {
511 return this.queryRunner;
512 }
513
514
515
516
517 public void setQueryRunner(String queryRunner)
518 {
519 this.queryRunner = queryRunner;
520 }
521
522
523
524
525
526 protected QueryRunner createQueryRunner()
527 {
528 try
529 {
530 return (QueryRunner) ClassUtils.instanciateClass(getQueryRunner(),
531 ClassUtils.NO_ARGS);
532 }
533 catch (Exception e)
534 {
535 throw new IllegalArgumentException("Error creating instance of the queryRunner class :"
536 + getQueryRunner() + System.getProperty("line.separator")
537 + ExceptionUtils.getFullStackTrace(e));
538 }
539 }
540
541
542
543
544
545
546
547
548
549 public String parseStatement(String stmt, List params)
550 {
551 if (stmt == null)
552 {
553 return stmt;
554 }
555 Matcher m = STATEMENT_ARGS.matcher(stmt);
556 StringBuffer sb = new StringBuffer(200);
557 while (m.find())
558 {
559 String key = m.group();
560 m.appendReplacement(sb, "?");
561 params.add(key);
562 }
563 m.appendTail(sb);
564 return sb.toString();
565 }
566
567 public Object[] getParams(UMOImmutableEndpoint endpoint, List paramNames, Object message)
568 throws Exception
569 {
570 Object[] params = new Object[paramNames.size()];
571 for (int i = 0; i < paramNames.size(); i++)
572 {
573 String param = (String)paramNames.get(i);
574 String name = param.substring(2, param.length() - 1);
575 Object value = null;
576
577 boolean foundValue = false;
578 if (message != null)
579 {
580 for (Iterator iterator = propertyExtractors.iterator(); iterator.hasNext();)
581 {
582 PropertyExtractor pe = (PropertyExtractor)iterator.next();
583 value = pe.getProperty(name, message);
584 if (value != null)
585 {
586 if (value.equals(StringUtils.EMPTY) && pe instanceof BeanPropertyExtractor)
587 {
588 value = null;
589 }
590 foundValue = true;
591 break;
592 }
593 }
594 }
595 if (!foundValue)
596 {
597 value = endpoint.getProperty(name);
598 }
599
600
601
602
603
604
605
606
607
608 params[i] = value;
609 }
610 return params;
611 }
612 }