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