View Javadoc

1   /*
2    * $Id: SelectSqlStatementStrategy.java 19201 2010-08-26 03:07:16Z dirk.olmes $
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.sqlstrategy;
12  
13  import org.mule.DefaultMuleMessage;
14  import org.mule.api.MuleEvent;
15  import org.mule.api.MuleMessage;
16  import org.mule.api.endpoint.ImmutableEndpoint;
17  import org.mule.api.transaction.Transaction;
18  import org.mule.transaction.TransactionCoordination;
19  import org.mule.transport.jdbc.JdbcConnector;
20  import org.mule.transport.jdbc.JdbcUtils;
21  import org.mule.util.ArrayUtils;
22  
23  import java.sql.Connection;
24  import java.util.ArrayList;
25  import java.util.List;
26  import java.util.Map;
27  
28  import org.apache.log4j.Logger;
29  
30  /**
31   * Implements strategy for handling normal select statements + acks.  
32   */
33  public  class SelectSqlStatementStrategy implements SqlStatementStrategy
34  {
35      protected transient Logger logger = Logger.getLogger(getClass());
36      
37      public MuleMessage executeStatement(JdbcConnector connector, ImmutableEndpoint endpoint,
38          MuleEvent event, long timeout) throws Exception
39      {
40          logger.debug("Trying to receive a message with a timeout of " + timeout);
41          
42          String[] stmts = connector.getReadAndAckStatements(endpoint);
43          
44          //Unparsed SQL statements (with #[foo] parameters)
45          String readStmt = stmts[0];
46          String ackStmt = stmts[1];
47          
48          //Storage for params (format is #[foo])
49          List readParams = new ArrayList();
50          List ackParams = new ArrayList();
51          
52          //Prepared statement form (with ? placeholders instead of #[foo] params)
53          readStmt = connector.parseStatement(readStmt, readParams);
54          ackStmt = connector.parseStatement(ackStmt, ackParams);
55  
56          Connection con = null;
57          long t0 = System.currentTimeMillis();
58          Transaction tx  = TransactionCoordination.getInstance().getTransaction();
59          try
60          {
61              con = connector.getConnection();
62              
63              //This method is used in both JDBCMessageDispatcher and JDBCMessageRequester.  
64              //JDBCMessageRequester specifies a finite timeout.
65              if (timeout < 0)
66              {
67                  timeout = Long.MAX_VALUE;
68              }
69              Object result;
70              
71              //do-while loop.  execute query until there's a result or timeout exceeded
72              do
73              {
74                  //Get the actual param values from the message.
75                  Object[] params = connector.getParams(endpoint, readParams,
76                      event != null ? event.getMessage() : null,
77                      endpoint.getEndpointURI().getAddress());
78                  
79                  if (logger.isDebugEnabled())
80                  {
81                      logger.debug("SQL QUERY: " + readStmt + ", params = " + ArrayUtils.toString(params));
82                  }
83  
84                  //Perform actual query
85                  result = connector.getQueryRunnerFor(endpoint).query(con, readStmt, 
86                      connector.getResultSetHandler(), params);
87                  
88                  if (result != null)
89                  {
90                      if (logger.isDebugEnabled())
91                      {
92                          logger.debug("SQL query received a result: " + result);
93                      }
94                      else if (logger.isInfoEnabled())
95                      {
96                          logger.info("SQL query received a result");
97                      }
98                      break;
99                  }
100                 long sleep = Math.min(connector.getPollingFrequency(),
101                                       timeout - (System.currentTimeMillis() - t0));
102                 if (sleep > 0)
103                 {
104                     if (logger.isDebugEnabled())
105                     {
106                         logger.debug("No results, sleeping for " + sleep);
107                     }
108                     Thread.sleep(sleep);
109                 }
110                 else
111                 {
112                     logger.debug("Timeout");
113                     JdbcUtils.rollbackAndClose(con);
114                     return null;
115                 }
116             } while (true);
117             
118             //Execute ack statement
119             if (ackStmt != null)
120             {
121                 Object[] params = connector.getParams(endpoint, ackParams,
122                         new DefaultMuleMessage(result, (Map)null, connector.getMuleContext()), ackStmt);
123                 if (logger.isDebugEnabled())
124                 {
125                     logger.debug("SQL UPDATE: " + ackStmt + ", params = " + ArrayUtils.toString(params));
126                 }
127                 int nbRows = connector.getQueryRunnerFor(endpoint).update(con, ackStmt, params);
128                 if (nbRows != 1)
129                 {
130                     logger.warn("Row count for ack should be 1 and not " + nbRows);
131                 }
132             }
133             
134             // Package up result
135             MuleMessage message = null;
136             if (event != null)
137             {
138                 message = new DefaultMuleMessage(result, event.getMessage(), connector.getMuleContext());
139             }
140             else
141             {
142                 message = new DefaultMuleMessage(result, connector.getMuleContext());
143             }
144             
145             //Close or return connection if not in a transaction
146             if (tx == null)
147             {
148                 JdbcUtils.commitAndClose(con);
149             }
150             
151             return message;
152         }
153         catch (Exception e)
154         {
155             if (tx == null)
156             {
157                 JdbcUtils.rollbackAndClose(con);
158             }
159             throw e;
160         }
161     }
162 }