Coverage Report - org.mule.transport.jdbc.JdbcMessageDispatcher
 
Classes in this File Line Coverage Branch Coverage Complexity
JdbcMessageDispatcher
71%
71/100
52%
29/56
4.4
 
 1  
 /*
 2  
  * $Id: JdbcMessageDispatcher.java 12370 2008-07-17 13:11:17Z tcarlson $
 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.MuleEvent;
 15  
 import org.mule.api.MuleMessage;
 16  
 import org.mule.api.endpoint.ImmutableEndpoint;
 17  
 import org.mule.api.endpoint.OutboundEndpoint;
 18  
 import org.mule.api.transaction.Transaction;
 19  
 import org.mule.api.transport.MessageAdapter;
 20  
 import org.mule.transaction.TransactionCoordination;
 21  
 import org.mule.transport.AbstractMessageDispatcher;
 22  
 import org.mule.util.ArrayUtils;
 23  
 import org.mule.util.StringUtils;
 24  
 
 25  
 import java.sql.Connection;
 26  
 import java.util.ArrayList;
 27  
 import java.util.List;
 28  
 
 29  
 import org.apache.commons.logging.Log;
 30  
 import org.apache.commons.logging.LogFactory;
 31  
 
 32  
 /**
 33  
  * The Jdbc Message dispatcher is responsible for executing SQL queries against a
 34  
  * database.
 35  
  */
 36  
 public class JdbcMessageDispatcher extends AbstractMessageDispatcher
 37  
 {
 38  
 
 39  2
     protected static Log staticLogger = LogFactory.getLog(AbstractMessageDispatcher.class);
 40  
 
 41  
     protected JdbcConnector connector;
 42  
     protected static final String STORED_PROCEDURE_PREFIX = "{ ";
 43  
     protected static final String STORED_PROCEDURE_SUFFIX = " }";
 44  
 
 45  
     public JdbcMessageDispatcher(OutboundEndpoint endpoint)
 46  
     {
 47  18
         super(endpoint);
 48  18
         this.connector = (JdbcConnector) endpoint.getConnector();
 49  18
     }
 50  
 
 51  
     protected void doDispose()
 52  
     {
 53  
         // template method
 54  18
     }
 55  
     
 56  
     protected Object executeWriteStatement(MuleEvent event, String writeStmt) throws Exception
 57  
     {
 58  8
         List paramNames = new ArrayList();
 59  8
         writeStmt = connector.parseStatement(writeStmt, paramNames);
 60  
 
 61  8
         Object[] paramValues = connector.getParams(endpoint, paramNames, new DefaultMuleMessage(
 62  
             event.transformMessage()), this.endpoint.getEndpointURI().getAddress());
 63  
 
 64  8
         Transaction tx = TransactionCoordination.getInstance().getTransaction();
 65  8
         Connection con = null;
 66  
         
 67  8
         MuleMessage message = event.getMessage();
 68  
         
 69  
         try
 70  
         {
 71  8
             con = this.connector.getConnection();
 72  
             
 73  8
             if ("call".equalsIgnoreCase(writeStmt.substring(0, 4)))
 74  
             {
 75  0
                 writeStmt = STORED_PROCEDURE_PREFIX + writeStmt + STORED_PROCEDURE_SUFFIX;
 76  
             }
 77  
             
 78  8
             if (logger.isDebugEnabled())
 79  
             {
 80  0
                 logger.debug("SQL UPDATE: " + writeStmt + ", params = " + ArrayUtils.toString(paramValues));
 81  
             }
 82  8
             int nbRows = connector.getQueryRunner().update(con, writeStmt, paramValues);
 83  8
             if (nbRows != 1)
 84  
             {
 85  0
                 logger.warn("Row count for write should be 1 and not " + nbRows);
 86  
             }
 87  8
             if (tx == null)
 88  
             {
 89  8
                 JdbcUtils.commitAndClose(con);
 90  
             }
 91  8
             logger.debug("MuleEvent dispatched succesfuly");
 92  
         }
 93  0
         catch (Exception e)
 94  
         {
 95  0
             logger.debug("Error dispatching event: " + e.getMessage(), e);
 96  0
             if (tx == null)
 97  
             {
 98  0
                 JdbcUtils.rollbackAndClose(con);
 99  
             }
 100  0
             throw e;
 101  8
         }
 102  
         
 103  8
         return message;
 104  
     }
 105  
     
 106  
     protected String getStatement(ImmutableEndpoint endpoint)
 107  
     {
 108  18
         String writeStmt = endpoint.getEndpointURI().getAddress();
 109  
         String str;
 110  18
         if ((str = this.connector.getQuery(endpoint, writeStmt)) != null)
 111  
         { 
 112  18
             writeStmt = str;
 113  
         }
 114  18
         writeStmt = StringUtils.trimToEmpty(writeStmt);
 115  18
         if (StringUtils.isBlank(writeStmt))
 116  
         {
 117  0
             throw new IllegalArgumentException("Missing statement");
 118  
         }
 119  
         
 120  18
         return writeStmt;
 121  
     }
 122  
     
 123  
     protected boolean isWriteStatement(String writeStmt)
 124  
     {
 125  18
         if (!"insert".equalsIgnoreCase(writeStmt.substring(0, 6))
 126  
                         && !"update".equalsIgnoreCase(writeStmt.substring(0, 6))
 127  
                         && !"delete".equalsIgnoreCase(writeStmt.substring(0, 6))
 128  
                         && !"merge".equalsIgnoreCase(writeStmt.substring(0, 5))
 129  
                         && !"call".equalsIgnoreCase(writeStmt.substring(0, 4)))
 130  
         {
 131  10
             return false;
 132  
         }
 133  
         
 134  8
         return true;
 135  
     }
 136  
 
 137  
     protected void doDispatch(MuleEvent event) throws Exception
 138  
     {
 139  2
         if (logger.isDebugEnabled())
 140  
         {
 141  0
             logger.debug("Dispatch event: " + event);
 142  
         }
 143  
         
 144  2
         String writeStmt = getStatement(event.getEndpoint());
 145  
         
 146  2
         if (!isWriteStatement(writeStmt))
 147  
         {
 148  0
             throw new IllegalArgumentException(
 149  
                 "Write statement should be an insert / update / delete / merge sql statement, or a stored-procedure call");
 150  
         }
 151  
         
 152  2
         this.executeWriteStatement(event, writeStmt);
 153  
         
 154  2
     }
 155  
 
 156  
     protected MuleMessage doSend(MuleEvent event) throws Exception
 157  
     {
 158  16
         String statement = getStatement(event.getEndpoint());
 159  
         
 160  16
         if (isWriteStatement(statement))
 161  
         {
 162  6
             executeWriteStatement(event, statement);
 163  6
             return event.getMessage();
 164  
         }
 165  
         
 166  10
         return executeRequest(event.getTimeout(),event, connector, endpoint);
 167  
         
 168  
     }
 169  
 
 170  
     /**
 171  
      * This does work for both dispatcher and requester
 172  
      *
 173  
      * @param timeout
 174  
      * @param event
 175  
      * @param connector
 176  
      * @param endpoint
 177  
      * @return
 178  
      * @throws Exception
 179  
      */
 180  
     protected static MuleMessage executeRequest(long timeout, MuleEvent event,
 181  
                                                JdbcConnector connector, ImmutableEndpoint endpoint) throws Exception
 182  
     {
 183  24
         if (staticLogger.isDebugEnabled())
 184  
         {
 185  0
             staticLogger.debug("Trying to receive a message with a timeout of " + timeout);
 186  
         }
 187  
 
 188  24
         String[] stmts = connector.getReadAndAckStatements(endpoint);
 189  24
         String readStmt = stmts[0];
 190  24
         String ackStmt = stmts[1];
 191  24
         List readParams = new ArrayList();
 192  24
         List ackParams = new ArrayList();
 193  24
         readStmt = connector.parseStatement(readStmt, readParams);
 194  24
         ackStmt = connector.parseStatement(ackStmt, ackParams);
 195  
 
 196  24
         Connection con = null;
 197  24
         long t0 = System.currentTimeMillis();
 198  24
         Transaction tx  = TransactionCoordination.getInstance().getTransaction();
 199  
         try
 200  
         {
 201  24
             con = connector.getConnection();
 202  24
             if (timeout < 0)
 203  
             {
 204  0
                 timeout = Long.MAX_VALUE;
 205  
             }
 206  
             Object result;
 207  
             do
 208  
             {
 209  24
                 Object[] params = connector.getParams(endpoint, readParams,
 210  
                     event!=null ? event.getMessage() : null,
 211  
                     endpoint.getEndpointURI().getAddress());
 212  24
                 if (staticLogger.isDebugEnabled())
 213  
                 {
 214  0
                     staticLogger.debug("SQL QUERY: " + readStmt + ", params = " + ArrayUtils.toString(params));
 215  
                 }
 216  24
                 result = connector.getQueryRunner().query(con, readStmt, params, connector.getResultSetHandler());
 217  24
                 if (result != null)
 218  
                 {
 219  24
                     if (staticLogger.isDebugEnabled())
 220  
                     {
 221  0
                         staticLogger.debug("Received: " + result);
 222  
                     }
 223  
                     break;
 224  
                 }
 225  0
                 long sleep = Math.min(connector.getPollingFrequency(),
 226  
                                       timeout - (System.currentTimeMillis() - t0));
 227  0
                 if (sleep > 0)
 228  
                 {
 229  0
                     if (staticLogger.isDebugEnabled())
 230  
                     {
 231  0
                         staticLogger.debug("No results, sleeping for " + sleep);
 232  
                     }
 233  0
                     Thread.sleep(sleep);
 234  
                 }
 235  
                 else
 236  
                 {
 237  0
                     staticLogger.debug("Timeout");
 238  0
                     JdbcUtils.rollbackAndClose(con);
 239  0
                     return null;
 240  
                 }
 241  
             }
 242  0
             while (true);
 243  24
             if (ackStmt != null)
 244  
             {
 245  14
                 Object[] params = connector.getParams(endpoint, ackParams, result, ackStmt);
 246  14
                 if (staticLogger.isDebugEnabled())
 247  
                 {
 248  0
                     staticLogger.debug("SQL UPDATE: " + ackStmt + ", params = " + ArrayUtils.toString(params));
 249  
                 }
 250  14
                 int nbRows = connector.getQueryRunner().update(con, ackStmt, params);
 251  14
                 if (nbRows != 1)
 252  
                 {
 253  14
                     staticLogger.warn("Row count for ack should be 1 and not " + nbRows);
 254  
                 }
 255  
             }
 256  24
             MessageAdapter msgAdapter = connector.getMessageAdapter(result);
 257  24
             MuleMessage message = new DefaultMuleMessage(msgAdapter);
 258  24
             if (tx == null)
 259  
             {
 260  16
                 JdbcUtils.commitAndClose(con);
 261  
             }
 262  
             
 263  24
             return message;
 264  
         }
 265  0
         catch (Exception e)
 266  
         {
 267  0
             if (tx == null)
 268  
             {
 269  0
                 JdbcUtils.rollbackAndClose(con);
 270  
             }
 271  0
             throw e;
 272  
         }
 273  
 
 274  
     }
 275  
 
 276  
 
 277  
     protected void doConnect() throws Exception
 278  
     {
 279  
         // template method
 280  18
     }
 281  
 
 282  
     protected void doDisconnect() throws Exception
 283  
     {
 284  
         // template method
 285  18
     }
 286  
 
 287  
 }