View Javadoc

1   /*
2    * $Id: JdbcMessageDispatcher.java 7976 2007-08-21 14:26:13Z 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.providers.jdbc;
12  
13  import org.mule.impl.MuleMessage;
14  import org.mule.providers.AbstractMessageDispatcher;
15  import org.mule.transaction.TransactionCoordination;
16  import org.mule.umo.UMOEvent;
17  import org.mule.umo.UMOMessage;
18  import org.mule.umo.UMOTransaction;
19  import org.mule.umo.endpoint.UMOImmutableEndpoint;
20  import org.mule.umo.provider.UMOMessageAdapter;
21  import org.mule.util.StringUtils;
22  
23  import java.sql.Connection;
24  import java.util.ArrayList;
25  import java.util.List;
26  
27  /**
28   * The Jdbc Message dispatcher is responsible for executing SQL queries against a
29   * database.
30   */
31  public class JdbcMessageDispatcher extends AbstractMessageDispatcher
32  {
33  
34      private JdbcConnector connector;
35  
36      public JdbcMessageDispatcher(UMOImmutableEndpoint endpoint)
37      {
38          super(endpoint);
39          this.connector = (JdbcConnector)endpoint.getConnector();
40      }
41  
42      /*
43       * (non-Javadoc)
44       * 
45       * @see org.mule.providers.AbstractMessageDispatcher#doDispose()
46       */
47      protected void doDispose()
48      {
49          // template method
50      }
51  
52      /*
53       * (non-Javadoc)
54       * 
55       * @see org.mule.providers.AbstractMessageDispatcher#doDispatch(org.mule.umo.UMOEvent)
56       */
57      protected void doDispatch(UMOEvent event) throws Exception
58      {
59          if (logger.isDebugEnabled())
60          {
61              logger.debug("Dispatch event: " + event);
62          }
63  
64          UMOImmutableEndpoint endpoint = event.getEndpoint();
65          String writeStmt = endpoint.getEndpointURI().getAddress();
66          String str;
67          if ((str = this.connector.getQuery(endpoint, writeStmt)) != null)
68          {
69              writeStmt = str;
70          }
71          writeStmt = StringUtils.trimToEmpty(writeStmt);
72          if (StringUtils.isBlank(writeStmt))
73          {
74              throw new IllegalArgumentException("Missing a write statement");
75          }
76          if (!"insert".equalsIgnoreCase(writeStmt.substring(0, 6))
77              && !"update".equalsIgnoreCase(writeStmt.substring(0, 6))
78              && !"delete".equalsIgnoreCase(writeStmt.substring(0, 6)))
79          {
80              throw new IllegalArgumentException(
81                  "Write statement should be an insert / update / delete sql statement");
82          }
83          List paramNames = new ArrayList();
84          writeStmt = connector.parseStatement(writeStmt, paramNames);
85  
86          Object[] paramValues = connector.getParams(endpoint, paramNames, new MuleMessage(
87              event.getTransformedMessage()));
88  
89          UMOTransaction tx = TransactionCoordination.getInstance().getTransaction();
90          Connection con = null;
91          try
92          {
93              con = this.connector.getConnection();
94  
95              int nbRows = connector.createQueryRunner().update(con, writeStmt, paramValues);
96              if (nbRows != 1)
97              {
98                  logger.warn("Row count for write should be 1 and not " + nbRows);
99              }
100             if (tx == null)
101             {
102                 JdbcUtils.commitAndClose(con);
103             }
104             logger.debug("Event dispatched succesfuly");
105         }
106         catch (Exception e)
107         {
108             logger.debug("Error dispatching event: " + e.getMessage(), e);
109             if (tx == null)
110             {
111                 JdbcUtils.rollbackAndClose(con);
112             }
113             throw e;
114         }
115     }
116 
117     /*
118      * (non-Javadoc)
119      * 
120      * @see org.mule.providers.AbstractMessageDispatcher#doSend(org.mule.umo.UMOEvent)
121      */
122     protected UMOMessage doSend(UMOEvent event) throws Exception
123     {
124         doDispatch(event);
125         return event.getMessage();
126     }
127 
128     /**
129      * Make a specific request to the underlying transport
130      * 
131      * @param timeout the maximum time the operation should block before returning.
132      *            The call should return immediately if there is data available. If
133      *            no data becomes available before the timeout elapses, null will be
134      *            returned
135      * @return the result of the request wrapped in a UMOMessage object. Null will be
136      *         returned if no data was avaialable
137      * @throws Exception if the call to the underlying protocal cuases an exception
138      */
139     protected UMOMessage doReceive(long timeout) throws Exception
140     {
141         if (logger.isDebugEnabled())
142         {
143             logger.debug("Trying to receive a message with a timeout of " + timeout);
144         }
145 
146         String[] stmts = this.connector.getReadAndAckStatements(endpoint);
147         String readStmt = stmts[0];
148         String ackStmt = stmts[1];
149         List readParams = new ArrayList();
150         List ackParams = new ArrayList();
151         readStmt = connector.parseStatement(readStmt, readParams);
152         ackStmt = connector.parseStatement(ackStmt, ackParams);
153 
154         Connection con = null;
155         long t0 = System.currentTimeMillis();
156         try
157         {
158             con = this.connector.getConnection();
159             if (timeout < 0)
160             {
161                 timeout = Long.MAX_VALUE;
162             }
163             Object result;
164             do
165             {
166                 result = connector.createQueryRunner().query(con, readStmt,
167                     connector.getParams(endpoint, readParams, null), connector.createResultSetHandler());
168                 if (result != null)
169                 {
170                     if (logger.isDebugEnabled())
171                     {
172                         logger.debug("Received: " + result);
173                     }
174                     break;
175                 }
176                 long sleep = Math.min(this.connector.getPollingFrequency(),
177                     timeout - (System.currentTimeMillis() - t0));
178                 if (sleep > 0)
179                 {
180                     if (logger.isDebugEnabled())
181                     {
182                         logger.debug("No results, sleeping for " + sleep);
183                     }
184                     Thread.sleep(sleep);
185                 }
186                 else
187                 {
188                     logger.debug("Timeout");
189                     return null;
190                 }
191             }
192             while (true);
193             if (ackStmt != null)
194             {
195                 int nbRows = connector.createQueryRunner().update(con, ackStmt,
196                     connector.getParams(endpoint, ackParams, result));
197                 if (nbRows != 1)
198                 {
199                     logger.warn("Row count for ack should be 1 and not " + nbRows);
200                 }
201             }
202             UMOMessageAdapter msgAdapter = this.connector.getMessageAdapter(result);
203             UMOMessage message = new MuleMessage(msgAdapter);
204             JdbcUtils.commitAndClose(con);
205             return message;
206         }
207         catch (Exception e)
208         {
209             JdbcUtils.rollbackAndClose(con);
210             throw e;
211         }
212     }
213 
214     protected void doConnect() throws Exception
215     {
216         // template method
217     }
218 
219     protected void doDisconnect() throws Exception
220     {
221         // template method
222     }
223 
224 }