1
2
3
4
5
6
7
8
9
10
11 package org.mule.transport.jdbc;
12
13 import org.mule.api.MuleException;
14 import org.mule.api.endpoint.ImmutableEndpoint;
15 import org.mule.api.endpoint.InboundEndpoint;
16 import org.mule.api.lifecycle.InitialisationException;
17 import org.mule.api.service.Service;
18 import org.mule.api.transaction.Transaction;
19 import org.mule.api.transaction.TransactionException;
20 import org.mule.api.transport.MessageReceiver;
21 import org.mule.config.ExceptionHelper;
22 import org.mule.config.i18n.MessageFactory;
23 import org.mule.transaction.TransactionCoordination;
24 import org.mule.transport.AbstractConnector;
25 import org.mule.util.expression.ExpressionEvaluatorManager;
26
27 import java.sql.Connection;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.regex.Matcher;
31 import java.util.regex.Pattern;
32
33 import javax.sql.DataSource;
34
35 import org.apache.commons.dbutils.QueryRunner;
36 import org.apache.commons.dbutils.ResultSetHandler;
37 import org.apache.commons.dbutils.handlers.MapListHandler;
38
39 public class JdbcConnector extends AbstractConnector
40 {
41 public static final String JDBC = "jdbc";
42
43
44
45 public static final String PROPERTY_POLLING_FREQUENCY = "pollingFrequency";
46 public static final long DEFAULT_POLLING_FREQUENCY = 1000;
47
48 private static final Pattern STATEMENT_ARGS = Pattern.compile("\\$\\{[^\\}]*\\}");
49
50
51 static
52 {
53 ExceptionHelper.registerExceptionReader(new SQLExceptionReader());
54 }
55
56 protected long pollingFrequency = 0;
57 protected Map queries;
58
59 private DataSource dataSource;
60 private ResultSetHandler resultSetHandler;
61 private QueryRunner queryRunner;
62 protected boolean transactionPerMessage = true;
63
64 protected void doInitialise() throws InitialisationException
65 {
66 createMultipleTransactedReceivers = false;
67
68 if (dataSource == null)
69 {
70 throw new InitialisationException(MessageFactory.createStaticMessage("Missing data source"), this);
71 }
72 if (resultSetHandler == null)
73 {
74 resultSetHandler = new MapListHandler();
75 }
76 if (queryRunner == null)
77 {
78 queryRunner = new QueryRunner();
79 }
80 }
81
82 public MessageReceiver createReceiver(Service service, InboundEndpoint endpoint) throws Exception
83 {
84 Map props = endpoint.getProperties();
85 if (props != null)
86 {
87 String tempPolling = (String) props.get(PROPERTY_POLLING_FREQUENCY);
88 if (tempPolling != null)
89 {
90 pollingFrequency = Long.parseLong(tempPolling);
91 }
92 }
93
94 if (pollingFrequency <= 0)
95 {
96 pollingFrequency = DEFAULT_POLLING_FREQUENCY;
97 }
98
99 String[] params = getReadAndAckStatements(endpoint);
100 return getServiceDescriptor().createMessageReceiver(this, service, endpoint, params);
101 }
102
103 public String[] getReadAndAckStatements(ImmutableEndpoint endpoint)
104 {
105 String str;
106
107
108 String readStmt;
109 if ((str = (String)endpoint.getProperty("sql")) != null)
110 {
111 readStmt = str;
112 }
113 else
114 {
115 readStmt = endpoint.getEndpointURI().getAddress();
116 }
117
118
119 String ackStmt;
120 if ((str = (String)endpoint.getProperty("ack")) != null)
121 {
122 ackStmt = str;
123 if ((str = getQuery(endpoint, ackStmt)) != null)
124 {
125 ackStmt = str;
126 }
127 ackStmt = ackStmt.trim();
128 }
129 else
130 {
131 ackStmt = readStmt + ".ack";
132 if ((str = getQuery(endpoint, ackStmt)) != null)
133 {
134 ackStmt = str.trim();
135 }
136 else
137 {
138 ackStmt = null;
139 }
140 }
141
142
143 if ((str = getQuery(endpoint, readStmt)) != null)
144 {
145 readStmt = str;
146 }
147 if (readStmt == null)
148 {
149 throw new IllegalArgumentException("Read statement should not be null");
150 }
151 else
152 {
153
154 readStmt = readStmt.trim();
155 }
156
157 if (!"select".equalsIgnoreCase(readStmt.substring(0, 6)) && !"call".equalsIgnoreCase(readStmt.substring(0, 4)))
158 {
159 throw new IllegalArgumentException("Read statement should be a select sql statement or a stored procedure");
160 }
161 if (ackStmt != null)
162 {
163 if (!"insert".equalsIgnoreCase(ackStmt.substring(0, 6))
164 && !"update".equalsIgnoreCase(ackStmt.substring(0, 6))
165 && !"delete".equalsIgnoreCase(ackStmt.substring(0, 6)))
166 {
167 throw new IllegalArgumentException(
168 "Ack statement should be an insert / update / delete sql statement");
169 }
170 }
171 return new String[]{readStmt, ackStmt};
172 }
173
174 public String getQuery(ImmutableEndpoint endpoint, String stmt)
175 {
176 Object query = null;
177 if (endpoint != null && endpoint.getProperties() != null)
178 {
179 Object queries = endpoint.getProperties().get("queries");
180 if (queries instanceof Map)
181 {
182 query = ((Map)queries).get(stmt);
183 }
184 }
185 if (query == null)
186 {
187 if (this.queries != null)
188 {
189 query = this.queries.get(stmt);
190 }
191 }
192 return query == null ? null : query.toString();
193 }
194
195 public Connection getConnection() throws Exception
196 {
197 Transaction tx = TransactionCoordination.getInstance().getTransaction();
198 if (tx != null)
199 {
200 if (tx.hasResource(dataSource))
201 {
202 logger.debug("Retrieving connection from current transaction");
203 return (Connection)tx.getResource(dataSource);
204 }
205 }
206 logger.debug("Retrieving new connection from data source");
207 Connection con = dataSource.getConnection();
208
209 if (tx != null)
210 {
211 logger.debug("Binding connection to current transaction");
212 try
213 {
214 tx.bindResource(dataSource, con);
215 }
216 catch (TransactionException e)
217 {
218 JdbcUtils.close(con);
219 throw new RuntimeException("Could not bind connection to current transaction", e);
220 }
221 }
222 return con;
223 }
224
225 public boolean isTransactionPerMessage()
226 {
227 return transactionPerMessage;
228 }
229
230 public void setTransactionPerMessage(boolean transactionPerMessage)
231 {
232 this.transactionPerMessage = transactionPerMessage;
233 if (!transactionPerMessage)
234 {
235 logger.warn("transactionPerMessage property is set to false so setting createMultipleTransactedReceivers " +
236 "to false also to prevent creation of multiple JdbcMessageReceivers");
237 setCreateMultipleTransactedReceivers(transactionPerMessage);
238 }
239 }
240
241
242
243
244
245
246
247
248
249 public String parseStatement(String stmt, List params)
250 {
251 if (stmt == null)
252 {
253 return stmt;
254 }
255 Matcher m = STATEMENT_ARGS.matcher(stmt);
256 StringBuffer sb = new StringBuffer(200);
257 while (m.find())
258 {
259 String key = m.group();
260 m.appendReplacement(sb, "?");
261 params.add(key);
262 }
263 m.appendTail(sb);
264 return sb.toString();
265 }
266
267 public Object[] getParams(ImmutableEndpoint endpoint, List paramNames, Object message, String query)
268 throws Exception
269 {
270
271 Object[] params = new Object[paramNames.size()];
272 for (int i = 0; i < paramNames.size(); i++)
273 {
274 String param = (String)paramNames.get(i);
275 String name = param.substring(2, param.length() - 1);
276 Object value = null;
277
278 boolean foundValue = false;
279
280 if (message != null && ExpressionEvaluatorManager.isValidExpression(name))
281 {
282 value = ExpressionEvaluatorManager.evaluate(name, message);
283 foundValue = value!=null;
284 }
285 if (!foundValue)
286 {
287 value = endpoint.getProperty(name);
288 }
289
290
291
292
293
294
295
296
297
298 params[i] = value;
299 }
300 return params;
301 }
302
303 protected void doDispose()
304 {
305
306 }
307
308 protected void doConnect() throws Exception
309 {
310
311 }
312
313 protected void doDisconnect() throws Exception
314 {
315
316 }
317
318 protected void doStart() throws MuleException
319 {
320
321 }
322
323 protected void doStop() throws MuleException
324 {
325
326 }
327
328
329
330
331
332 public String getProtocol()
333 {
334 return JDBC;
335 }
336
337 public DataSource getDataSource()
338 {
339 return dataSource;
340 }
341
342 public void setDataSource(DataSource dataSource)
343 {
344 this.dataSource = dataSource;
345 }
346
347 public ResultSetHandler getResultSetHandler()
348 {
349 return resultSetHandler;
350 }
351
352 public void setResultSetHandler(ResultSetHandler resultSetHandler)
353 {
354 this.resultSetHandler = resultSetHandler;
355 }
356
357 public QueryRunner getQueryRunner()
358 {
359 return queryRunner;
360 }
361
362 public void setQueryRunner(QueryRunner queryRunner)
363 {
364 this.queryRunner = queryRunner;
365 }
366
367
368
369
370 public long getPollingFrequency()
371 {
372 return pollingFrequency;
373 }
374
375
376
377
378 public void setPollingFrequency(long pollingFrequency)
379 {
380 this.pollingFrequency = pollingFrequency;
381 }
382
383
384
385
386 public Map getQueries()
387 {
388 return queries;
389 }
390
391
392
393
394 public void setQueries(Map queries)
395 {
396 this.queries = queries;
397 }
398 }