Coverage Report - org.mule.providers.tcp.TcpConnector
 
Classes in this File Line Coverage Branch Coverage Complexity
TcpConnector
73%
83/114
67%
8/12
1.3
TcpConnector$1
100%
3/3
N/A
1.3
 
 1  
 /*
 2  
  * $Id: TcpConnector.java 7963 2007-08-21 08:53:15Z 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.tcp;
 12  
 
 13  
 import org.mule.config.i18n.CoreMessages;
 14  
 import org.mule.impl.model.streaming.CallbackOutputStream;
 15  
 import org.mule.providers.AbstractConnector;
 16  
 import org.mule.providers.tcp.i18n.TcpMessages;
 17  
 import org.mule.providers.tcp.protocols.DefaultProtocol;
 18  
 import org.mule.umo.MessagingException;
 19  
 import org.mule.umo.UMOException;
 20  
 import org.mule.umo.UMOMessage;
 21  
 import org.mule.umo.endpoint.UMOImmutableEndpoint;
 22  
 import org.mule.umo.lifecycle.InitialisationException;
 23  
 import org.mule.util.ClassUtils;
 24  
 
 25  
 import java.io.BufferedOutputStream;
 26  
 import java.io.DataOutputStream;
 27  
 import java.io.IOException;
 28  
 import java.io.OutputStream;
 29  
 import java.net.ServerSocket;
 30  
 import java.net.Socket;
 31  
 import java.net.URI;
 32  
 
 33  
 import org.apache.commons.pool.impl.GenericKeyedObjectPool;
 34  
 
 35  
 /**
 36  
  * <code>TcpConnector</code> can bind or sent to a given TCP port on a given host.
 37  
  * Other socket-based transports can be built on top of this class by providing the
 38  
  * appropriate socket factories and application level protocols as required (see
 39  
  * the constructor and the SSL transport for examples).
 40  
  */
 41  
 public class TcpConnector extends AbstractConnector
 42  
 {
 43  
     /**
 44  
      * Property can be set on the endpoint to configure how the socket is managed
 45  
      */
 46  
     public static final String KEEP_SEND_SOCKET_OPEN_PROPERTY = "keepSendSocketOpen";
 47  
     public static final int DEFAULT_SOCKET_TIMEOUT = INT_VALUE_NOT_SET;
 48  
     public static final int DEFAULT_BUFFER_SIZE = INT_VALUE_NOT_SET;
 49  
     public static final int DEFAULT_BACKLOG = INT_VALUE_NOT_SET;
 50  
 
 51  64
     private int sendTimeout = DEFAULT_SOCKET_TIMEOUT;
 52  64
     private int receiveTimeout = DEFAULT_SOCKET_TIMEOUT;
 53  64
     private int sendBufferSize = DEFAULT_BUFFER_SIZE;
 54  64
     private int receiveBufferSize = DEFAULT_BUFFER_SIZE;
 55  64
     private int receiveBacklog = DEFAULT_BACKLOG;
 56  
     private boolean sendTcpNoDelay;
 57  64
     private boolean validateConnections = true;
 58  64
     private Boolean reuseAddress = null; // not set - Java default
 59  64
     private int socketLinger = INT_VALUE_NOT_SET;
 60  
     private String tcpProtocolClassName;
 61  
     private TcpProtocol tcpProtocol;
 62  64
     private boolean keepSendSocketOpen = false;
 63  64
     private boolean keepAlive = false;
 64  
     private PooledSocketFactory socketFactory;
 65  
     private SimpleServerSocketFactory serverSocketFactory;
 66  64
     private GenericKeyedObjectPool dispatcherSocketsPool = new GenericKeyedObjectPool();
 67  
 
 68  
     public TcpConnector()
 69  64
     {
 70  64
         setSocketFactory (new TcpSocketFactory());
 71  64
         setServerSocketFactory(new TcpServerSocketFactory());
 72  66
         setTcpProtocolClassName(DefaultProtocol.class.getName());
 73  64
     }
 74  
 
 75  
     protected void doInitialise() throws InitialisationException
 76  
     {
 77  60
         if (tcpProtocol == null)
 78  
         {
 79  
             try
 80  
             {
 81  60
                 tcpProtocol = (TcpProtocol) ClassUtils.instanciateClass(tcpProtocolClassName, null);
 82  
             }
 83  0
             catch (Exception e)
 84  
             {
 85  0
                 throw new InitialisationException(TcpMessages.failedToInitMessageReader(), e);
 86  60
             }
 87  
         }
 88  
 
 89  60
         dispatcherSocketsPool.setFactory(getSocketFactory());
 90  60
         dispatcherSocketsPool.setTestOnBorrow(true);
 91  60
         dispatcherSocketsPool.setTestOnReturn(true);
 92  
         //There should only be one pooled instance per socket (key)        
 93  60
         dispatcherSocketsPool.setMaxActive(1);
 94  60
     }
 95  
 
 96  
     protected void doDispose()
 97  
     {
 98  64
         logger.debug("Closing TCP connector");
 99  
         try
 100  
         {
 101  64
             dispatcherSocketsPool.close();
 102  
         }
 103  0
         catch (Exception e)
 104  
         {
 105  0
             logger.warn("Failed to close dispatcher socket pool: " + e.getMessage());
 106  64
         }
 107  64
     }
 108  
 
 109  
     /**
 110  
      * Lookup a socket in the list of dispatcher sockets but don't create a new
 111  
      * socket
 112  
      */
 113  
     protected Socket getSocket(UMOImmutableEndpoint endpoint) throws Exception
 114  
     {
 115  2501
         Socket socket = (Socket) dispatcherSocketsPool.borrowObject(endpoint);
 116  2501
         if (logger.isDebugEnabled())
 117  
         {
 118  0
             logger.debug("borrowing socket; debt " + dispatcherSocketsPool.getNumActive());
 119  
         }
 120  2501
         return socket;
 121  
     }
 122  
 
 123  
     void releaseSocket(Socket socket, UMOImmutableEndpoint endpoint) throws Exception
 124  
     {
 125  2501
         dispatcherSocketsPool.returnObject(endpoint, socket);
 126  2501
         if (logger.isDebugEnabled())
 127  
         {
 128  0
             logger.debug("returned socket; debt " + dispatcherSocketsPool.getNumActive());
 129  
         }
 130  2501
     }
 131  
 
 132  
     public OutputStream getOutputStream(final UMOImmutableEndpoint endpoint, UMOMessage message)
 133  
             throws UMOException
 134  
     {
 135  
         final Socket socket;
 136  
         try
 137  
         {
 138  10
             socket = getSocket(endpoint);
 139  
         }
 140  0
         catch (Exception e)
 141  
         {
 142  0
             throw new MessagingException(CoreMessages.failedToGetOutputStream(), message, e);
 143  10
         }
 144  10
         if (socket == null)
 145  
         {
 146  
             // This shouldn't happen
 147  0
             throw new IllegalStateException("could not get socket for endpoint: "
 148  
                                             + endpoint.getEndpointURI().getAddress());
 149  
         }
 150  
         try
 151  
         {
 152  10
             return new CallbackOutputStream(
 153  
                     new DataOutputStream(new BufferedOutputStream(socket.getOutputStream())),
 154  
                     new CallbackOutputStream.Callback()
 155  
                     {
 156  10
                         public void onClose() throws Exception
 157  
                         {
 158  10
                             releaseSocket(socket, endpoint);
 159  10
                         }
 160  
                     });
 161  
         }
 162  0
         catch (IOException e)
 163  
         {
 164  0
             throw new MessagingException(CoreMessages.failedToGetOutputStream(), message, e);
 165  
         }
 166  
     }
 167  
 
 168  
     protected void doConnect() throws Exception
 169  
     {
 170  
         // template method
 171  44
     }
 172  
 
 173  
     protected void doDisconnect() throws Exception
 174  
     {
 175  44
         dispatcherSocketsPool.clear();
 176  44
     }
 177  
 
 178  
     protected void doStart() throws UMOException
 179  
     {
 180  
         // template method
 181  44
     }
 182  
 
 183  
     protected void doStop() throws UMOException
 184  
     {
 185  
         // template method
 186  44
     }
 187  
 
 188  
     public String getProtocol()
 189  
     {
 190  2656
         return "tcp";
 191  
     }
 192  
 
 193  
     // getters and setters ---------------------------------------------------------
 194  
     
 195  
     public boolean isKeepSendSocketOpen()
 196  
     {
 197  2487
         return keepSendSocketOpen;
 198  
     }
 199  
 
 200  
     public void setKeepSendSocketOpen(boolean keepSendSocketOpen)
 201  
     {
 202  10
         this.keepSendSocketOpen = keepSendSocketOpen;
 203  10
     }
 204  
 
 205  
     /**
 206  
      * A shorthand property setting timeout for both SEND and RECEIVE sockets.
 207  
      * @deprecated The time out should be set explicitly for each
 208  
      */
 209  
     public void setTimeout(int timeout)
 210  
     {
 211  6
         setSendTimeout(timeout);
 212  6
         setReceiveTimeout(timeout);
 213  6
     }
 214  
 
 215  
     public int getSendTimeout()
 216  
     {
 217  24
         return this.sendTimeout;
 218  
     }
 219  
 
 220  
     public void setSendTimeout(int timeout)
 221  
     {
 222  10
         this.sendTimeout = valueOrDefault(timeout, 0, DEFAULT_SOCKET_TIMEOUT);
 223  10
     }
 224  
 
 225  
     public int getReceiveTimeout()
 226  
     {
 227  5244
         return receiveTimeout;
 228  
     }
 229  
 
 230  
     public void setReceiveTimeout(int timeout)
 231  
     {
 232  10
         this.receiveTimeout = valueOrDefault(timeout, 0, DEFAULT_SOCKET_TIMEOUT);
 233  10
     }
 234  
 
 235  
     /**
 236  
      * @deprecated Should use {@link #getSendBufferSize()} or {@link #getReceiveBufferSize()}
 237  
      */
 238  
     public int getBufferSize()
 239  
     {
 240  0
         return sendBufferSize;
 241  
     }
 242  
 
 243  
     /**
 244  
      * @deprecated Should use {@link #setSendBufferSize(int)} or {@link #setReceiveBufferSize(int)}
 245  
      */
 246  
     public void setBufferSize(int bufferSize)
 247  
     {
 248  0
         sendBufferSize = valueOrDefault(bufferSize, 1, DEFAULT_BUFFER_SIZE);
 249  0
     }
 250  
 
 251  
     public int getSendBufferSize()
 252  
     {
 253  5202
         return sendBufferSize;
 254  
     }
 255  
 
 256  
     public void setSendBufferSize(int bufferSize)
 257  
     {
 258  6
         sendBufferSize = valueOrDefault(bufferSize, 1, DEFAULT_BUFFER_SIZE);
 259  6
     }
 260  
 
 261  
     public int getReceiveBufferSize()
 262  
     {
 263  5180
         return receiveBufferSize;
 264  
     }
 265  
 
 266  
     public void setReceiveBufferSize(int bufferSize)
 267  
     {
 268  0
         receiveBufferSize = valueOrDefault(bufferSize, 1, DEFAULT_BUFFER_SIZE);
 269  0
     }
 270  
 
 271  
     public int getReceiveBacklog()
 272  
     {
 273  66
         return receiveBacklog;
 274  
     }
 275  
 
 276  
     public void setReceiveBacklog(int receiveBacklog)
 277  
     {
 278  0
         this.receiveBacklog = valueOrDefault(receiveBacklog, 0, DEFAULT_BACKLOG);
 279  0
     }
 280  
 
 281  
     public int getSendSocketLinger()
 282  
     {
 283  0
         return socketLinger;
 284  
     }
 285  
 
 286  
     public void setSendSocketLinger(int soLinger)
 287  
     {
 288  0
         this.socketLinger = valueOrDefault(soLinger, 0, INT_VALUE_NOT_SET);
 289  0
     }
 290  
 
 291  
     /**
 292  
      *
 293  
      * @return
 294  
      * @deprecated should use {@link #getReceiveBacklog()}
 295  
      */
 296  
     public int getBacklog()
 297  
     {
 298  0
         return receiveBacklog;
 299  
     }
 300  
 
 301  
     /**
 302  
      *
 303  
      * @param backlog
 304  
      * @deprecated should use {@link #setReceiveBacklog(int)}
 305  
      */
 306  
     public void setBacklog(int backlog)
 307  
     {
 308  0
         this.receiveBacklog = backlog;
 309  0
     }
 310  
 
 311  
     public TcpProtocol getTcpProtocol()
 312  
     {
 313  5175
         return tcpProtocol;
 314  
     }
 315  
 
 316  
     public void setTcpProtocol(TcpProtocol tcpProtocol)
 317  
     {
 318  0
         this.tcpProtocol = tcpProtocol;
 319  0
     }
 320  
 
 321  
     public String getTcpProtocolClassName()
 322  
     {
 323  0
         return tcpProtocolClassName;
 324  
     }
 325  
 
 326  
     public void setTcpProtocolClassName(String protocolClassName)
 327  
     {
 328  80
         this.tcpProtocolClassName = protocolClassName;
 329  80
     }
 330  
 
 331  
     public boolean isRemoteSyncEnabled()
 332  
     {
 333  102
         return true;
 334  
     }
 335  
 
 336  
     public boolean isKeepAlive()
 337  
     {
 338  5180
         return keepAlive;
 339  
     }
 340  
 
 341  
     public void setKeepAlive(boolean keepAlive)
 342  
     {
 343  0
         this.keepAlive = keepAlive;
 344  0
     }
 345  
 
 346  
     public boolean isSendTcpNoDelay()
 347  
     {
 348  5180
         return sendTcpNoDelay;
 349  
     }
 350  
 
 351  
     public void setSendTcpNoDelay(boolean sendTcpNoDelay)
 352  
     {
 353  0
         this.sendTcpNoDelay = sendTcpNoDelay;
 354  0
     }
 355  
     
 356  
     protected void setSocketFactory(PooledSocketFactory socketFactory)
 357  
     {
 358  64
         this.socketFactory = socketFactory;
 359  64
     }
 360  
 
 361  
     protected PooledSocketFactory getSocketFactory()
 362  
     {
 363  60
         return socketFactory;
 364  
     }
 365  
 
 366  
     public SimpleServerSocketFactory getServerSocketFactory()
 367  
     {
 368  66
         return serverSocketFactory;
 369  
     }
 370  
 
 371  
     public void setServerSocketFactory(SimpleServerSocketFactory serverSocketFactory)
 372  
     {
 373  64
         this.serverSocketFactory = serverSocketFactory;
 374  64
     }
 375  
 
 376  
     protected ServerSocket getServerSocket(URI uri) throws IOException
 377  
     {
 378  66
         return getServerSocketFactory().createServerSocket(uri, getReceiveBacklog(), isReuseAddress());
 379  
     }
 380  
     
 381  
     private static int valueOrDefault(int value, int threshhold, int deflt)
 382  
     {
 383  26
         if (value < threshhold)
 384  
         {
 385  6
             return deflt;
 386  
         }
 387  
         else 
 388  
         {
 389  20
             return value;    
 390  
         }
 391  
     }
 392  
 
 393  
     /**
 394  
      * Should the connection be checked before sending data?
 395  
      *
 396  
      * @return If true, the message adapter opens and closes the socket on intialisation.
 397  
      */
 398  
     public boolean isValidateConnections() {
 399  41
         return validateConnections;
 400  
     }
 401  
 
 402  
     /**
 403  
      * @see #isValidateConnections()
 404  
      * @param validateConnections If true, the message adapter opens and closes the socket on intialisation.
 405  
      */
 406  
     public void setValidateConnections(boolean validateConnections) {
 407  8
         this.validateConnections = validateConnections;
 408  8
     }
 409  
 
 410  
     /**
 411  
      * @return true if the server socket sets SO_REUSEADDRESS before opening
 412  
      */
 413  
     public Boolean isReuseAddress()
 414  
     {
 415  68
         return reuseAddress;
 416  
     }
 417  
 
 418  
     /**
 419  
      * This allows closed sockets to be reused while they are still in TIME_WAIT state
 420  
      *
 421  
      * @param reuseAddress Whether the server socket sets SO_REUSEADDRESS before opening
 422  
      */
 423  
     public void setReuseAddress(Boolean reuseAddress)
 424  
     {
 425  2
         this.reuseAddress = reuseAddress;
 426  2
     }
 427  
 
 428  
 }