View Javadoc

1   /*
2    * $Id: JdbcMessageReceiver.java 12181 2008-06-26 20:05:55Z dirk.olmes $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.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;
12  
13  import org.mule.DefaultMuleMessage;
14  import org.mule.api.MuleMessage;
15  import org.mule.api.endpoint.InboundEndpoint;
16  import org.mule.api.lifecycle.CreateException;
17  import org.mule.api.service.Service;
18  import org.mule.api.transaction.Transaction;
19  import org.mule.api.transport.Connector;
20  import org.mule.api.transport.MessageAdapter;
21  import org.mule.transaction.TransactionCoordination;
22  import org.mule.transaction.XaTransactionFactory;
23  import org.mule.transport.ConnectException;
24  import org.mule.transport.TransactedPollingMessageReceiver;
25  import org.mule.transport.jdbc.i18n.JdbcMessages;
26  import org.mule.util.ArrayUtils;
27  import org.mule.util.MapUtils;
28  
29  import java.sql.Connection;
30  import java.sql.SQLException;
31  import java.util.ArrayList;
32  import java.util.List;
33  
34  /** TODO */
35  public class JdbcMessageReceiver extends TransactedPollingMessageReceiver
36  {
37  
38      public static final String RECEIVE_MESSAGE_IN_TRANSCTION = "receiveMessageInTransaction";
39      public static final String RECEIVE_MESSAGES_IN_XA_TRANSCTION = "receiveMessagesInXaTransaction";
40      
41      protected JdbcConnector connector;
42      protected String readStmt;
43      protected String ackStmt;
44      protected List readParams;
45      protected List ackParams;
46      public boolean receiveMessagesInXaTransaction = false;
47      
48      public JdbcMessageReceiver(Connector connector,
49                                 Service service,
50                                 InboundEndpoint endpoint,
51                                 String readStmt,
52                                 String ackStmt) throws CreateException
53      {
54          super(connector, service, endpoint);
55          this.setFrequency(((JdbcConnector) connector).getPollingFrequency());
56  
57          boolean transactedEndpoint = endpoint.getTransactionConfig().isTransacted();
58          boolean xaTransactedEndpoint = (transactedEndpoint &&
59              endpoint.getTransactionConfig().getFactory() instanceof XaTransactionFactory);
60          
61          boolean receiveMessageInTransaction = MapUtils.getBooleanValue(endpoint.getProperties(),
62              RECEIVE_MESSAGE_IN_TRANSCTION, false);
63          this.setReceiveMessagesInTransaction(receiveMessageInTransaction && transactedEndpoint);
64          if (receiveMessageInTransaction && !transactedEndpoint)
65          {
66              logger.warn(JdbcMessages.forcePropertyNoTransaction(RECEIVE_MESSAGE_IN_TRANSCTION, "transaction"));
67              receiveMessageInTransaction = false;
68          }
69          
70          receiveMessagesInXaTransaction = MapUtils.getBooleanValue(endpoint.getProperties(),
71              RECEIVE_MESSAGES_IN_XA_TRANSCTION, false);
72          if (receiveMessagesInXaTransaction && !receiveMessageInTransaction)
73          {
74              logger.warn(JdbcMessages.forceProperty(RECEIVE_MESSAGES_IN_XA_TRANSCTION, RECEIVE_MESSAGE_IN_TRANSCTION));
75              receiveMessagesInXaTransaction = false;
76          }
77          else if (receiveMessagesInXaTransaction && isReceiveMessagesInTransaction() && !xaTransactedEndpoint)
78          {
79              logger.warn(JdbcMessages.forcePropertyNoTransaction(RECEIVE_MESSAGES_IN_XA_TRANSCTION, "XA transaction"));
80              receiveMessagesInXaTransaction = false;
81          }
82      
83          
84          this.connector = (JdbcConnector) connector;
85          this.setReceiveMessagesInTransaction(endpoint.getTransactionConfig().isTransacted()
86              && !this.connector.isTransactionPerMessage());
87          
88          this.readParams = new ArrayList();
89          this.readStmt = this.connector.parseStatement(readStmt, this.readParams);
90          this.ackParams = new ArrayList();
91          this.ackStmt = this.connector.parseStatement(ackStmt, this.ackParams);
92      }
93  
94      protected void doDispose()
95      {
96          // template method
97      }
98  
99      protected void doConnect() throws Exception
100     {
101         Connection con = null;
102         try
103         {
104             con = this.connector.getConnection();
105         }
106         catch (Exception e)
107         {
108             throw new ConnectException(e, this);
109         }
110         finally
111         {
112             JdbcUtils.close(con);
113         }
114     }
115 
116     protected void doDisconnect() throws ConnectException
117     {
118         // noop
119     }
120 
121     public void processMessage(Object message) throws Exception
122     {
123         Connection con = null;
124         Transaction tx = TransactionCoordination.getInstance().getTransaction();
125         try
126         {
127             con = this.connector.getConnection();
128             MessageAdapter msgAdapter = this.connector.getMessageAdapter(message);
129             MuleMessage umoMessage = new DefaultMuleMessage(msgAdapter);
130             if (this.ackStmt != null)
131             {
132                 Object[] ackParams = connector.getParams(endpoint, this.ackParams, umoMessage, this.endpoint.getEndpointURI().getAddress());
133                 if (logger.isDebugEnabled())
134                 {
135                     logger.debug("SQL UPDATE: " + ackStmt + ", params = " + ArrayUtils.toString(ackParams));
136                 }
137                 int nbRows = connector.getQueryRunner().update(con, this.ackStmt, ackParams);
138                 if (nbRows != 1)
139                 {
140                     logger.warn("Row count for ack should be 1 and not " + nbRows);
141                 }
142             }
143             routeMessage(umoMessage, tx, tx != null || endpoint.isSynchronous());
144 
145         }
146         catch (Exception ex)
147         {
148             if (tx != null)
149             {
150                 tx.setRollbackOnly();
151             }
152 
153             // rethrow
154             throw ex;
155         }
156         finally
157         {
158             if (endpoint.getMuleContext().getTransactionManager() != null || tx == null)
159             {
160                 // We are running in an XA transaction.
161                 // This call is required here for compatibility with strict XA
162                 // DataSources
163                 // implementations, as is the case for WebSphere AS and Weblogic.
164                 // Failure to do it here may result in a connection leak.
165                 // The close() call will NOT close the connection, neither will it
166                 // return it to the pool.
167                 // It will notify the XA driver's ConnectionEventListener that the XA
168                 // connection
169                 // is no longer used by the application and is ready for the 2PC
170                 // commit.
171                 JdbcUtils.close(con);
172             }
173         }
174     }
175 
176     public List getMessages() throws Exception
177     {
178         Connection con = null;
179         try
180         {
181             try
182             {
183                 con = this.connector.getConnection();
184             }
185             catch (SQLException e)
186             {
187                 throw new ConnectException(e, this);
188             }
189 
190             Object[] readParams = connector.getParams(endpoint, this.readParams, null, this.endpoint.getEndpointURI().getAddress());
191             if (logger.isDebugEnabled())
192             {
193                 logger.debug("SQL QUERY: " + readStmt + ", params = " + ArrayUtils.toString(readParams));
194             }
195             Object results = connector.getQueryRunner().query(con, this.readStmt, readParams,
196                     connector.getResultSetHandler());
197 
198             List resultList = (List) results;
199             if (resultList != null && resultList.size() > 1 && isReceiveMessagesInTransaction() && !receiveMessagesInXaTransaction)
200             {
201                 logger.warn(JdbcMessages.moreThanOneMessageInTransaction(RECEIVE_MESSAGE_IN_TRANSCTION, RECEIVE_MESSAGES_IN_XA_TRANSCTION));
202                 List singleResultList = new ArrayList(1);
203                 singleResultList.add(resultList);
204                 return singleResultList;
205             }
206             
207             return resultList;
208         }
209         finally
210         {
211             if (TransactionCoordination.getInstance().getTransaction() == null)
212             {
213                 JdbcUtils.close(con);
214             }
215         }
216     }
217 
218 }