View Javadoc

1   /*
2    * $Id: ConnectionWrapper.java 20322 2010-11-24 16:15:31Z epere4 $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
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   * Using for unification XAConnection and Connection
47   */
48  public class ConnectionWrapper implements Connection, XaTransaction.MuleXaObject
49  {
50      private final XAConnection xaConnection;
51      private Connection connection;
52  
53      /**
54       * This is the lock object that guards access to {@link #enlistedXAResource}.
55       */
56      private final Object enlistedXAResourceLock = new Object();
57      /**
58       * @GuardedBy {@link #enlistedXAResourceLock}
59       */
60      private XAResource enlistedXAResource;
61  
62      protected static final transient Log logger = LogFactory.getLog(ConnectionWrapper.class);
63      private volatile boolean reuseObject = false;
64  
65      public ConnectionWrapper(XAConnection xaCon) throws SQLException
66      {
67          this.xaConnection = xaCon;
68          this.connection = xaCon.getConnection();
69      }
70  
71      public int getHoldability() throws SQLException
72      {
73          return connection.getHoldability();
74      }
75  
76      public int getTransactionIsolation() throws SQLException
77      {
78          return connection.getTransactionIsolation();
79      }
80  
81      public void clearWarnings() throws SQLException
82      {
83          connection.clearWarnings();
84      }
85  
86      public void close() throws SQLException
87      {
88          connection.close();
89          try
90          {
91              xaConnection.close();
92          }
93          catch (SQLException e)
94          {
95              logger.info(
96                  "Exception while explicitely closing the xaConnection (some providers require this). "
97                                  + "The exception will be ignored and only logged: " + e.getMessage(), e);
98          }
99      }
100 
101     public void commit() throws SQLException
102     {
103         connection.commit();
104     }
105 
106     public void rollback() throws SQLException
107     {
108         connection.rollback();
109     }
110 
111     public boolean getAutoCommit() throws SQLException
112     {
113         return connection.getAutoCommit();
114     }
115 
116     public boolean isClosed() throws SQLException
117     {
118         return connection.isClosed();
119     }
120 
121     public boolean isReadOnly() throws SQLException
122     {
123         return connection.isReadOnly();
124     }
125 
126     public void setHoldability(int holdability) throws SQLException
127     {
128         connection.setHoldability(holdability);
129     }
130 
131     public void setTransactionIsolation(int level) throws SQLException
132     {
133         connection.setTransactionIsolation(level);
134     }
135 
136     public void setAutoCommit(boolean autoCommit) throws SQLException
137     {
138         connection.setAutoCommit(autoCommit);
139     }
140 
141     public void setReadOnly(boolean readOnly) throws SQLException
142     {
143         connection.setReadOnly(readOnly);
144     }
145 
146     public String getCatalog() throws SQLException
147     {
148         return connection.getCatalog();
149     }
150 
151     public void setCatalog(String catalog) throws SQLException
152     {
153         connection.setCatalog(catalog);
154     }
155 
156     public DatabaseMetaData getMetaData() throws SQLException
157     {
158         return connection.getMetaData();
159     }
160 
161     public SQLWarning getWarnings() throws SQLException
162     {
163         return connection.getWarnings();
164     }
165 
166     public Savepoint setSavepoint() throws SQLException
167     {
168         return connection.setSavepoint();
169     }
170 
171     public void releaseSavepoint(Savepoint savepoint) throws SQLException
172     {
173         connection.releaseSavepoint(savepoint);
174     }
175 
176     public void rollback(Savepoint savepoint) throws SQLException
177     {
178         connection.rollback();
179     }
180 
181     public Statement createStatement() throws SQLException
182     {
183         Statement st = connection.createStatement();
184         return (Statement) Proxy.newProxyInstance(Statement.class.getClassLoader(),
185                                                   new Class[]{Statement.class}, new StatementInvocationHandler(this, st));
186     }
187 
188     public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException
189     {
190         Statement st = connection.createStatement(resultSetType, resultSetConcurrency);
191         return (Statement) Proxy.newProxyInstance(Statement.class.getClassLoader(),
192                                                   new Class[]{Statement.class}, new StatementInvocationHandler(this, st));
193     }
194 
195     public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability)
196             throws SQLException
197     {
198         Statement st = connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
199         return (Statement) Proxy.newProxyInstance(Statement.class.getClassLoader(),
200                                                   new Class[]{Statement.class}, new StatementInvocationHandler(this, st));
201     }
202 
203     public Map getTypeMap() throws SQLException
204     {
205         return connection.getTypeMap();
206     }
207 
208     public void setTypeMap(Map<String, Class<?>> map) throws SQLException
209     {
210         connection.setTypeMap(map);
211     }
212 
213     public String nativeSQL(String sql) throws SQLException
214     {
215         return connection.nativeSQL(sql);
216     }
217 
218     public CallableStatement prepareCall(String sql) throws SQLException
219     {
220         CallableStatement cs = connection.prepareCall(sql);
221         return (CallableStatement) Proxy.newProxyInstance(CallableStatement.class.getClassLoader(),
222                                                           new Class[]{CallableStatement.class}, new StatementInvocationHandler(this, cs));
223     }
224 
225     public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency)
226             throws SQLException
227     {
228         CallableStatement cs = connection.prepareCall(sql, resultSetType, resultSetConcurrency);
229         return (CallableStatement) Proxy.newProxyInstance(CallableStatement.class.getClassLoader(),
230                                                           new Class[]{CallableStatement.class}, new StatementInvocationHandler(this, cs));
231     }
232 
233     public CallableStatement prepareCall(String sql,
234                                          int resultSetType,
235                                          int resultSetConcurrency,
236                                          int resultSetHoldability) throws SQLException
237     {
238         CallableStatement cs = connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
239         return (CallableStatement) Proxy.newProxyInstance(CallableStatement.class.getClassLoader(),
240                                                           new Class[]{CallableStatement.class}, new StatementInvocationHandler(this, cs));
241     }
242 
243     public PreparedStatement prepareStatement(String sql) throws SQLException
244     {
245         PreparedStatement ps = connection.prepareStatement(sql);
246         return (PreparedStatement) Proxy.newProxyInstance(PreparedStatement.class.getClassLoader(),
247                                                           new Class[]{PreparedStatement.class}, new StatementInvocationHandler(this, ps));
248     }
249 
250     public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException
251     {
252         PreparedStatement ps = connection.prepareStatement(sql, autoGeneratedKeys);
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 resultSetType, int resultSetConcurrency)
258             throws SQLException
259     {
260         PreparedStatement ps = connection.prepareStatement(sql, resultSetType, resultSetConcurrency);
261         return (PreparedStatement) Proxy.newProxyInstance(PreparedStatement.class.getClassLoader(),
262                                                           new Class[]{PreparedStatement.class}, new StatementInvocationHandler(this, ps));
263     }
264 
265     public PreparedStatement prepareStatement(String sql,
266                                               int resultSetType,
267                                               int resultSetConcurrency,
268                                               int resultSetHoldability) throws SQLException
269     {
270         PreparedStatement ps = connection.prepareStatement(sql, resultSetType, resultSetConcurrency,
271                                                            resultSetHoldability);
272         return (PreparedStatement) Proxy.newProxyInstance(PreparedStatement.class.getClassLoader(),
273                                                           new Class[]{PreparedStatement.class}, new StatementInvocationHandler(this, ps));
274     }
275 
276     public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException
277     {
278         PreparedStatement ps = connection.prepareStatement(sql, columnIndexes);
279         return (PreparedStatement) Proxy.newProxyInstance(PreparedStatement.class.getClassLoader(),
280                                                           new Class[]{PreparedStatement.class}, new StatementInvocationHandler(this, ps));
281     }
282 
283     public Savepoint setSavepoint(String name) throws SQLException
284     {
285         return connection.setSavepoint(name);
286     }
287 
288     public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException
289     {
290         PreparedStatement ps = connection.prepareStatement(sql, columnNames);
291         return (PreparedStatement) Proxy.newProxyInstance(PreparedStatement.class.getClassLoader(),
292                                                           new Class[]{PreparedStatement.class}, new StatementInvocationHandler(this, ps));
293     }
294 
295     public boolean enlist() throws TransactionException
296     {
297         try
298         {
299             connection.setAutoCommit(false);
300         }
301         catch (SQLException e)
302         {
303             throw new TransactionException(e);
304         }
305         
306         if (isEnlisted())
307         {
308             return false;
309         }
310         if (logger.isDebugEnabled())
311         {
312             logger.debug("Enlistment request: " + this);
313         }
314 
315         Transaction transaction = TransactionCoordination.getInstance().getTransaction();
316         if (transaction == null)
317         {
318             throw new IllegalTransactionStateException(CoreMessages.noMuleTransactionAvailable());
319         }
320         if (!(transaction instanceof XaTransaction))
321         {
322             throw new IllegalTransactionStateException(CoreMessages.notMuleXaTransaction(transaction));
323         }
324 
325         synchronized (enlistedXAResourceLock)
326         {
327             if (!isEnlisted())
328             {
329                 final XAResource xaResource = getXAResourceFromXATransaction();
330                 boolean wasAbleToEnlist = ((XaTransaction) transaction).enlistResource(xaResource);
331                 if (wasAbleToEnlist)
332                 {
333                     enlistedXAResource = xaResource;
334                 }
335             }
336         }
337         
338         return isEnlisted();
339     }
340 
341     protected XAResource getXAResourceFromXATransaction() throws TransactionException
342     {
343         try
344         {
345             return xaConnection.getXAResource();
346         }
347         catch (SQLException e)
348         {
349             throw new TransactionException(e);
350         }
351     }
352 
353     public boolean delist() throws Exception
354     {
355         if (!isEnlisted())
356         {
357             return false;
358         }
359         if (logger.isDebugEnabled())
360         {
361             logger.debug("Delistment request: " + this);
362         }
363 
364         Transaction transaction = TransactionCoordination.getInstance().getTransaction();
365         if (transaction == null)
366         {
367             throw new IllegalTransactionStateException(CoreMessages.noMuleTransactionAvailable());
368         }
369         if (!(transaction instanceof XaTransaction))
370         {
371             throw new IllegalTransactionStateException(CoreMessages.notMuleXaTransaction(transaction));
372         }
373 
374         synchronized (enlistedXAResourceLock)
375         {
376             if (isEnlisted())
377             {
378                 boolean wasAbleToDelist = ((XaTransaction) transaction).delistResource(enlistedXAResource,
379                     XAResource.TMSUCCESS);
380                 if (wasAbleToDelist)
381                 {
382                     enlistedXAResource = null;
383                 }
384             }
385             return !isEnlisted();
386         }
387     }
388 
389 
390     public boolean isEnlisted()
391     {
392         synchronized (enlistedXAResourceLock)
393         {
394             return enlistedXAResource != null;
395         }
396     }
397 
398     public boolean isReuseObject()
399     {
400         return reuseObject;
401     }
402 
403     public void setReuseObject(boolean reuseObject)
404     {
405         this.reuseObject = reuseObject;
406     }
407 
408     public Object getTargetObject()
409     {
410         return xaConnection;
411     }
412 
413     public Array createArrayOf(String typeName, Object[] elements) throws SQLException
414     {
415         return connection.createArrayOf(typeName, elements);
416     }
417 
418     public Blob createBlob() throws SQLException
419     {
420         return connection.createBlob();
421     }
422 
423     public Clob createClob() throws SQLException
424     {
425         return connection.createClob();
426     }
427 
428     public NClob createNClob() throws SQLException
429     {
430         return connection.createNClob();
431     }
432 
433     public SQLXML createSQLXML() throws SQLException
434     {
435         return connection.createSQLXML();
436     }
437 
438     public Struct createStruct(String typeName, Object[] attributes) throws SQLException
439     {
440         return connection.createStruct(typeName, attributes);
441     }
442 
443     public Properties getClientInfo() throws SQLException
444     {
445         return connection.getClientInfo();
446     }
447 
448     public String getClientInfo(String name) throws SQLException
449     {
450         return connection.getClientInfo(name);
451     }
452 
453     public boolean isValid(int timeout) throws SQLException
454     {
455         return connection.isValid(timeout);
456     }
457 
458     public void setClientInfo(Properties properties) throws SQLClientInfoException
459     {
460         connection.setClientInfo(properties);
461     }
462 
463     public void setClientInfo(String name, String value) throws SQLClientInfoException
464     {
465         connection.setClientInfo(name, value);
466     }
467 
468     public boolean isWrapperFor(Class<?> iface) throws SQLException
469     {
470         return connection.isWrapperFor(iface);
471     }
472 
473     public <T> T unwrap(Class<T> iface) throws SQLException
474     {
475         return connection.unwrap(iface);
476     }
477 }