1
2
3
4
5
6
7
8
9
10
11 package org.mule.transport.jdbc.xa;
12
13 import org.mule.api.transaction.Transaction;
14 import org.mule.api.transaction.TransactionException;
15 import org.mule.config.i18n.CoreMessages;
16 import org.mule.transaction.IllegalTransactionStateException;
17 import org.mule.transaction.TransactionCoordination;
18 import org.mule.transaction.XaTransaction;
19
20 import java.lang.reflect.Proxy;
21 import java.sql.Array;
22 import java.sql.Blob;
23 import java.sql.CallableStatement;
24 import java.sql.Clob;
25 import java.sql.Connection;
26 import java.sql.DatabaseMetaData;
27 import java.sql.NClob;
28 import java.sql.PreparedStatement;
29 import java.sql.SQLClientInfoException;
30 import java.sql.SQLException;
31 import java.sql.SQLWarning;
32 import java.sql.SQLXML;
33 import java.sql.Savepoint;
34 import java.sql.Statement;
35 import java.sql.Struct;
36 import java.util.Map;
37 import java.util.Properties;
38
39 import javax.sql.XAConnection;
40 import javax.transaction.xa.XAResource;
41
42 import org.apache.commons.logging.Log;
43 import org.apache.commons.logging.LogFactory;
44
45
46
47
48 public class ConnectionWrapper implements Connection, XaTransaction.MuleXaObject
49 {
50 private final XAConnection xaConnection;
51 private Connection connection;
52 private volatile boolean enlisted = false;
53 protected static final transient Log logger = LogFactory.getLog(ConnectionWrapper.class);
54 private volatile boolean reuseObject = false;
55
56 public ConnectionWrapper(XAConnection xaCon) throws SQLException
57 {
58 this.xaConnection = xaCon;
59 this.connection = xaCon.getConnection();
60 }
61
62 public int getHoldability() throws SQLException
63 {
64 return connection.getHoldability();
65 }
66
67 public int getTransactionIsolation() throws SQLException
68 {
69 return connection.getTransactionIsolation();
70 }
71
72 public void clearWarnings() throws SQLException
73 {
74 connection.clearWarnings();
75 }
76
77 public void close() throws SQLException
78 {
79 connection.close();
80 }
81
82 public void commit() throws SQLException
83 {
84 connection.commit();
85 }
86
87 public void rollback() throws SQLException
88 {
89 connection.rollback();
90 }
91
92 public boolean getAutoCommit() throws SQLException
93 {
94 return connection.getAutoCommit();
95 }
96
97 public boolean isClosed() throws SQLException
98 {
99 return connection.isClosed();
100 }
101
102 public boolean isReadOnly() throws SQLException
103 {
104 return connection.isReadOnly();
105 }
106
107 public void setHoldability(int holdability) throws SQLException
108 {
109 connection.setHoldability(holdability);
110 }
111
112 public void setTransactionIsolation(int level) throws SQLException
113 {
114 connection.setTransactionIsolation(level);
115 }
116
117 public void setAutoCommit(boolean autoCommit) throws SQLException
118 {
119 connection.setAutoCommit(autoCommit);
120 }
121
122 public void setReadOnly(boolean readOnly) throws SQLException
123 {
124 connection.setReadOnly(readOnly);
125 }
126
127 public String getCatalog() throws SQLException
128 {
129 return connection.getCatalog();
130 }
131
132 public void setCatalog(String catalog) throws SQLException
133 {
134 connection.setCatalog(catalog);
135 }
136
137 public DatabaseMetaData getMetaData() throws SQLException
138 {
139 return connection.getMetaData();
140 }
141
142 public SQLWarning getWarnings() throws SQLException
143 {
144 return connection.getWarnings();
145 }
146
147 public Savepoint setSavepoint() throws SQLException
148 {
149 return connection.setSavepoint();
150 }
151
152 public void releaseSavepoint(Savepoint savepoint) throws SQLException
153 {
154 connection.releaseSavepoint(savepoint);
155 }
156
157 public void rollback(Savepoint savepoint) throws SQLException
158 {
159 connection.rollback();
160 }
161
162 public Statement createStatement() throws SQLException
163 {
164 Statement st = connection.createStatement();
165 return (Statement) Proxy.newProxyInstance(Statement.class.getClassLoader(),
166 new Class[]{Statement.class}, new StatementInvocationHandler(this, st));
167 }
168
169 public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException
170 {
171 Statement st = connection.createStatement(resultSetType, resultSetConcurrency);
172 return (Statement) Proxy.newProxyInstance(Statement.class.getClassLoader(),
173 new Class[]{Statement.class}, new StatementInvocationHandler(this, st));
174 }
175
176 public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability)
177 throws SQLException
178 {
179 Statement st = connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
180 return (Statement) Proxy.newProxyInstance(Statement.class.getClassLoader(),
181 new Class[]{Statement.class}, new StatementInvocationHandler(this, st));
182 }
183
184 public Map getTypeMap() throws SQLException
185 {
186 return connection.getTypeMap();
187 }
188
189 public void setTypeMap(Map<String, Class<?>> map) throws SQLException
190 {
191 connection.setTypeMap(map);
192 }
193
194 public String nativeSQL(String sql) throws SQLException
195 {
196 return connection.nativeSQL(sql);
197 }
198
199 public CallableStatement prepareCall(String sql) throws SQLException
200 {
201 CallableStatement cs = connection.prepareCall(sql);
202 return (CallableStatement) Proxy.newProxyInstance(CallableStatement.class.getClassLoader(),
203 new Class[]{CallableStatement.class}, new StatementInvocationHandler(this, cs));
204 }
205
206 public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency)
207 throws SQLException
208 {
209 CallableStatement cs = connection.prepareCall(sql, resultSetType, resultSetConcurrency);
210 return (CallableStatement) Proxy.newProxyInstance(CallableStatement.class.getClassLoader(),
211 new Class[]{CallableStatement.class}, new StatementInvocationHandler(this, cs));
212 }
213
214 public CallableStatement prepareCall(String sql,
215 int resultSetType,
216 int resultSetConcurrency,
217 int resultSetHoldability) throws SQLException
218 {
219 CallableStatement cs = connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
220 return (CallableStatement) Proxy.newProxyInstance(CallableStatement.class.getClassLoader(),
221 new Class[]{CallableStatement.class}, new StatementInvocationHandler(this, cs));
222 }
223
224 public PreparedStatement prepareStatement(String sql) throws SQLException
225 {
226 PreparedStatement ps = connection.prepareStatement(sql);
227 return (PreparedStatement) Proxy.newProxyInstance(PreparedStatement.class.getClassLoader(),
228 new Class[]{PreparedStatement.class}, new StatementInvocationHandler(this, ps));
229 }
230
231 public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException
232 {
233 PreparedStatement ps = connection.prepareStatement(sql, autoGeneratedKeys);
234 return (PreparedStatement) Proxy.newProxyInstance(PreparedStatement.class.getClassLoader(),
235 new Class[]{PreparedStatement.class}, new StatementInvocationHandler(this, ps));
236 }
237
238 public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
239 throws SQLException
240 {
241 PreparedStatement ps = connection.prepareStatement(sql, resultSetType, resultSetConcurrency);
242 return (PreparedStatement) Proxy.newProxyInstance(PreparedStatement.class.getClassLoader(),
243 new Class[]{PreparedStatement.class}, new StatementInvocationHandler(this, ps));
244 }
245
246 public PreparedStatement prepareStatement(String sql,
247 int resultSetType,
248 int resultSetConcurrency,
249 int resultSetHoldability) throws SQLException
250 {
251 PreparedStatement ps = connection.prepareStatement(sql, resultSetType, resultSetConcurrency,
252 resultSetHoldability);
253 return (PreparedStatement) Proxy.newProxyInstance(PreparedStatement.class.getClassLoader(),
254 new Class[]{PreparedStatement.class}, new StatementInvocationHandler(this, ps));
255 }
256
257 public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException
258 {
259 PreparedStatement ps = connection.prepareStatement(sql, columnIndexes);
260 return (PreparedStatement) Proxy.newProxyInstance(PreparedStatement.class.getClassLoader(),
261 new Class[]{PreparedStatement.class}, new StatementInvocationHandler(this, ps));
262 }
263
264 public Savepoint setSavepoint(String name) throws SQLException
265 {
266 return connection.setSavepoint(name);
267 }
268
269 public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException
270 {
271 PreparedStatement ps = connection.prepareStatement(sql, columnNames);
272 return (PreparedStatement) Proxy.newProxyInstance(PreparedStatement.class.getClassLoader(),
273 new Class[]{PreparedStatement.class}, new StatementInvocationHandler(this, ps));
274 }
275
276 public boolean enlist() throws TransactionException
277 {
278 try
279 {
280 connection.setAutoCommit(false);
281 }
282 catch (SQLException e)
283 {
284 throw new TransactionException(e);
285 }
286
287 if (isEnlisted())
288 {
289 return false;
290 }
291 if (logger.isDebugEnabled())
292 {
293 logger.debug("Enlistment request: " + this);
294 }
295
296 Transaction transaction = TransactionCoordination.getInstance().getTransaction();
297 if (transaction == null)
298 {
299 throw new IllegalTransactionStateException(CoreMessages.noMuleTransactionAvailable());
300 }
301 if (!(transaction instanceof XaTransaction))
302 {
303 throw new IllegalTransactionStateException(CoreMessages.notMuleXaTransaction(transaction));
304 }
305 if (!isEnlisted())
306 {
307 final XAResource xaResource;
308 try
309 {
310 xaResource = xaConnection.getXAResource();
311 }
312 catch (SQLException e)
313 {
314 throw new TransactionException(e);
315 }
316
317 enlisted = ((XaTransaction) transaction).enlistResource(xaResource);
318 }
319
320 return enlisted;
321 }
322
323 public boolean delist() throws Exception
324 {
325 if (!isEnlisted())
326 {
327 return false;
328 }
329 if (logger.isDebugEnabled())
330 {
331 logger.debug("Delistment request: " + this);
332 }
333
334 Transaction transaction = TransactionCoordination.getInstance().getTransaction();
335 if (transaction == null)
336 {
337 throw new IllegalTransactionStateException(CoreMessages.noMuleTransactionAvailable());
338 }
339 if (!(transaction instanceof XaTransaction))
340 {
341 throw new IllegalTransactionStateException(CoreMessages.notMuleXaTransaction(transaction));
342 }
343 if (isEnlisted())
344 {
345 enlisted = !((XaTransaction) transaction).delistResource(xaConnection.getXAResource(), XAResource.TMSUCCESS);
346 }
347 return !isEnlisted();
348 }
349
350
351 public boolean isEnlisted()
352 {
353 return enlisted;
354 }
355
356 public void setEnlisted(boolean enlisted)
357 {
358 this.enlisted = enlisted;
359 }
360
361 public boolean isReuseObject()
362 {
363 return reuseObject;
364 }
365
366 public void setReuseObject(boolean reuseObject)
367 {
368 this.reuseObject = reuseObject;
369 }
370
371 public Object getTargetObject()
372 {
373 return xaConnection;
374 }
375
376 public Array createArrayOf(String typeName, Object[] elements) throws SQLException
377 {
378 return connection.createArrayOf(typeName, elements);
379 }
380
381 public Blob createBlob() throws SQLException
382 {
383 return connection.createBlob();
384 }
385
386 public Clob createClob() throws SQLException
387 {
388 return connection.createClob();
389 }
390
391 public NClob createNClob() throws SQLException
392 {
393 return connection.createNClob();
394 }
395
396 public SQLXML createSQLXML() throws SQLException
397 {
398 return connection.createSQLXML();
399 }
400
401 public Struct createStruct(String typeName, Object[] attributes) throws SQLException
402 {
403 return connection.createStruct(typeName, attributes);
404 }
405
406 public Properties getClientInfo() throws SQLException
407 {
408 return connection.getClientInfo();
409 }
410
411 public String getClientInfo(String name) throws SQLException
412 {
413 return connection.getClientInfo(name);
414 }
415
416 public boolean isValid(int timeout) throws SQLException
417 {
418 return connection.isValid(timeout);
419 }
420
421 public void setClientInfo(Properties properties) throws SQLClientInfoException
422 {
423 connection.setClientInfo(properties);
424 }
425
426 public void setClientInfo(String name, String value) throws SQLClientInfoException
427 {
428 connection.setClientInfo(name, value);
429 }
430
431 public boolean isWrapperFor(Class<?> iface) throws SQLException
432 {
433 return connection.isWrapperFor(iface);
434 }
435
436 public <T> T unwrap(Class<T> iface) throws SQLException
437 {
438 return connection.unwrap(iface);
439 }
440 }