Coverage Report - org.mule.transport.tcp.TcpConnector
 
Classes in this File Line Coverage Branch Coverage Complexity
TcpConnector
0%
0/150
0%
0/32
0
TcpConnector$1
0%
0/3
N/A
0
 
 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.tcp;
 8  
 
 9  
 import org.mule.api.MessagingException;
 10  
 import org.mule.api.MuleContext;
 11  
 import org.mule.api.MuleException;
 12  
 import org.mule.api.MuleMessage;
 13  
 import org.mule.api.endpoint.ImmutableEndpoint;
 14  
 import org.mule.api.lifecycle.InitialisationException;
 15  
 import org.mule.api.transport.Connector;
 16  
 import org.mule.api.transport.MessageDispatcherFactory;
 17  
 import org.mule.config.i18n.CoreMessages;
 18  
 import org.mule.model.streaming.CallbackOutputStream;
 19  
 import org.mule.transport.AbstractConnector;
 20  
 import org.mule.transport.ConfigurableKeyedObjectPool;
 21  
 import org.mule.transport.tcp.protocols.SafeProtocol;
 22  
 import org.mule.util.concurrent.ThreadNameHelper;
 23  
 import org.mule.util.monitor.ExpiryMonitor;
 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.SocketException;
 32  
 import java.net.URI;
 33  
 
 34  
 import org.apache.commons.pool.impl.GenericKeyedObjectPool;
 35  
 
 36  
 /**
 37  
  * <code>TcpConnector</code> can bind or sent to a given TCP port on a given host.
 38  
  * Other socket-based transports can be built on top of this class by providing the
 39  
  * appropriate socket factories and application level protocols as required (see
 40  
  * the constructor and the SSL transport for examples).
 41  
  */
 42  
 public class TcpConnector extends AbstractConnector
 43  
 {
 44  
     public static final String TCP = "tcp";
 45  
 
 46  
     /** Property can be set on the endpoint to configure how the socket is managed */
 47  
     public static final String KEEP_SEND_SOCKET_OPEN_PROPERTY = "keepSendSocketOpen";
 48  
     public static final int DEFAULT_SOCKET_TIMEOUT = INT_VALUE_NOT_SET;
 49  
     public static final int DEFAULT_SO_LINGER = INT_VALUE_NOT_SET;
 50  
     public static final int DEFAULT_BUFFER_SIZE = INT_VALUE_NOT_SET;
 51  
     public static final int DEFAULT_BACKLOG = INT_VALUE_NOT_SET;
 52  
     public static final int DEFAULT_WAIT_TIMEOUT = INT_VALUE_NOT_SET;
 53  
 
 54  
     // to clarify arg to configureSocket
 55  
     public static final boolean SERVER = false;
 56  
     public static final boolean CLIENT = true;
 57  
 
 58  0
     private int clientSoTimeout = DEFAULT_SOCKET_TIMEOUT;
 59  0
     private int serverSoTimeout = DEFAULT_SOCKET_TIMEOUT;
 60  0
     private int socketMaxWait = DEFAULT_WAIT_TIMEOUT;
 61  0
     private int sendBufferSize = DEFAULT_BUFFER_SIZE;
 62  0
     private int receiveBufferSize = DEFAULT_BUFFER_SIZE;
 63  0
     private int receiveBacklog = DEFAULT_BACKLOG;
 64  
     private boolean sendTcpNoDelay;
 65  0
     private Boolean reuseAddress = Boolean.TRUE; // this could be null for Java default
 66  0
     private int socketSoLinger = DEFAULT_SO_LINGER;
 67  
     private TcpProtocol tcpProtocol;
 68  
     private AbstractTcpSocketFactory socketFactory;
 69  
     private SimpleServerSocketFactory serverSocketFactory;
 70  0
     private GenericKeyedObjectPool socketsPool = new GenericKeyedObjectPool();
 71  0
     private int keepAliveTimeout = 0;
 72  
     private ExpiryMonitor keepAliveMonitor;
 73  
 
 74  
     /** 
 75  
      * If set, the socket is not closed after sending a message.  This attribute 
 76  
      * only applies when sending data over a socket (Client).
 77  
      */
 78  0
     private boolean keepSendSocketOpen = false;
 79  
 
 80  
     /**
 81  
      * Enables SO_KEEPALIVE behavior on open sockets. This automatically checks 
 82  
      * socket connections that are open but unused for long periods and closes 
 83  
      * them if the connection becomes unavailable.  This is a property on the 
 84  
      * socket itself and is used by a server socket to control whether 
 85  
      * connections to the server are kept alive before they are recycled.
 86  
      */
 87  0
     private boolean keepAlive = false;
 88  
 
 89  
     //TODO MULE-2300 remove once fixed
 90  
     private TcpSocketKey lastSocketKey;
 91  
 
 92  
     public TcpConnector(MuleContext context)
 93  
     {
 94  0
         super(context);
 95  0
         setSocketFactory(new TcpSocketFactory());
 96  0
         setServerSocketFactory(new TcpServerSocketFactory());
 97  0
         setTcpProtocol(new SafeProtocol());
 98  0
     }
 99  
 
 100  
     public void configureSocket(boolean client, Socket socket) throws SocketException
 101  
     {
 102  
         // There is some overhead in setting socket timeout and buffer size, so we're
 103  
         // careful here only to set if needed
 104  
 
 105  0
         if (newValue(getReceiveBufferSize(), socket.getReceiveBufferSize()))
 106  
         {
 107  0
             socket.setReceiveBufferSize(getReceiveBufferSize());
 108  
         }
 109  0
         if (newValue(getSendBufferSize(), socket.getSendBufferSize()))
 110  
         {
 111  0
             socket.setSendBufferSize(getSendBufferSize());
 112  
         }
 113  0
         if (client)
 114  
         {
 115  0
             if (newValue(getClientSoTimeout(), socket.getSoTimeout()))
 116  
             {
 117  0
                 socket.setSoTimeout(getClientSoTimeout());
 118  
             }
 119  
         }
 120  
         else
 121  
         {
 122  0
             if (newValue(getServerSoTimeout(), socket.getSoTimeout()))
 123  
             {
 124  0
                 socket.setSoTimeout(getServerSoTimeout());
 125  
             }
 126  
         }
 127  0
         if (newValue(getSocketSoLinger(), socket.getSoLinger()))
 128  
         {
 129  0
             socket.setSoLinger(true, getSocketSoLinger());
 130  
         }
 131  
         try
 132  
         {
 133  0
             socket.setTcpNoDelay(isSendTcpNoDelay());
 134  
         }
 135  0
         catch (SocketException e)
 136  
         {
 137  
             // MULE-2800 - Bug in Solaris
 138  0
         }
 139  0
         socket.setKeepAlive(isKeepAlive());
 140  0
     }
 141  
 
 142  
     private boolean newValue(int parameter, int socketValue)
 143  
     {
 144  0
         return parameter != Connector.INT_VALUE_NOT_SET && parameter != socketValue;
 145  
     }
 146  
 
 147  
     @Override
 148  
     protected void doInitialise() throws InitialisationException
 149  
     {
 150  0
         socketsPool.setFactory(getSocketFactory());
 151  0
         socketsPool.setTestOnBorrow(true);
 152  0
         socketsPool.setTestOnReturn(true);
 153  0
         socketsPool.setMaxActive(getDispatcherThreadingProfile().getMaxThreadsActive());
 154  0
         socketsPool.setMaxIdle(getDispatcherThreadingProfile().getMaxThreadsIdle());
 155  0
         socketsPool.setWhenExhaustedAction(GenericKeyedObjectPool.WHEN_EXHAUSTED_BLOCK);
 156  0
         socketsPool.setMaxWait(socketMaxWait);
 157  
 
 158  
         // Use connector's classloader so that other temporary classloaders
 159  
         // aren't used when things are started lazily or from elsewhere.
 160  0
         final String monitorName = String.format("%s%s.socket",
 161  
                                                  ThreadNameHelper.getPrefix(muleContext),
 162  
                                                  getName());
 163  0
         keepAliveMonitor = new ExpiryMonitor(monitorName, 1000, this.getClass().getClassLoader());
 164  0
     }
 165  
 
 166  
     @Override
 167  
     protected void doDispose()
 168  
     {
 169  0
         logger.debug("Closing TCP connector");
 170  
         try
 171  
         {
 172  0
             socketsPool.close();
 173  
         }
 174  0
         catch (Exception e)
 175  
         {
 176  0
             logger.warn("Failed to close dispatcher socket pool: " + e.getMessage());
 177  0
         }
 178  
         
 179  0
         keepAliveMonitor.dispose();
 180  0
     }
 181  
 
 182  
     /**
 183  
      * Lookup a socket in the list of dispatcher sockets but don't create a new
 184  
      * socket
 185  
      */
 186  
     protected Socket getSocket(ImmutableEndpoint endpoint) throws Exception
 187  
     {
 188  0
         TcpSocketKey socketKey = new TcpSocketKey(endpoint);
 189  0
         if (logger.isDebugEnabled())
 190  
         {
 191  0
             logger.debug("borrowing socket for " + socketKey + "/" + socketKey.hashCode());
 192  0
             if (null != lastSocketKey)
 193  
             {
 194  0
                 logger.debug("same as " + lastSocketKey.hashCode() + "? " + lastSocketKey.equals(socketKey));
 195  
             }
 196  
         }
 197  0
         Socket socket = (Socket) socketsPool.borrowObject(socketKey);
 198  0
         if (logger.isDebugEnabled())
 199  
         {
 200  0
             logger.debug("borrowed socket, "
 201  
                     + (socket.isClosed() ? "closed" : "open") 
 202  
                     + "; debt " + socketsPool.getNumActive());
 203  
         }
 204  0
         return socket;
 205  
     }
 206  
 
 207  
     void releaseSocket(Socket socket, ImmutableEndpoint endpoint) throws Exception
 208  
     {
 209  0
         TcpSocketKey socketKey = new TcpSocketKey(endpoint);
 210  0
         lastSocketKey = socketKey;
 211  0
         socketsPool.returnObject(socketKey, socket);
 212  0
         if (logger.isDebugEnabled())
 213  
         {
 214  0
             logger.debug("returning socket for " + socketKey.hashCode());
 215  0
             logger.debug("returned socket; debt " + socketsPool.getNumActive());
 216  
         }
 217  0
     }
 218  
 
 219  
     public OutputStream getOutputStream(final ImmutableEndpoint endpoint, MuleMessage message)
 220  
             throws MuleException
 221  
     {
 222  
         final Socket socket;
 223  
         try
 224  
         {
 225  0
             socket = getSocket(endpoint);
 226  
         }
 227  0
         catch (Exception e)
 228  
         {
 229  0
             throw new MessagingException(CoreMessages.failedToGetOutputStream(), message, e);
 230  0
         }
 231  0
         if (socket == null)
 232  
         {
 233  
             // This shouldn't happen
 234  0
             throw new IllegalStateException("could not get socket for endpoint: "
 235  
                     + endpoint.getEndpointURI().getAddress());
 236  
         }
 237  
         try
 238  
         {
 239  0
             return new CallbackOutputStream(
 240  
                     new DataOutputStream(new BufferedOutputStream(socket.getOutputStream())),
 241  
                     new CallbackOutputStream.Callback()
 242  0
                     {
 243  
                         public void onClose() throws Exception
 244  
                         {
 245  0
                             releaseSocket(socket, endpoint);
 246  0
                         }
 247  
                     });
 248  
         }
 249  0
         catch (IOException e)
 250  
         {
 251  0
             throw new MessagingException(CoreMessages.failedToGetOutputStream(), message, e);
 252  
         }
 253  
     }
 254  
 
 255  
     @Override
 256  
     protected void doConnect() throws Exception
 257  
     {
 258  
         // template method
 259  0
     }
 260  
 
 261  
     @Override
 262  
     protected void doDisconnect() throws Exception
 263  
     {
 264  0
         socketsPool.clear();
 265  0
     }
 266  
 
 267  
     @Override
 268  
     protected void doStart() throws MuleException
 269  
     {
 270  
         // template method
 271  0
     }
 272  
 
 273  
     @Override
 274  
     protected void doStop() throws MuleException
 275  
     {
 276  
         // template method
 277  0
     }
 278  
 
 279  
     public String getProtocol()
 280  
     {
 281  0
         return TCP;
 282  
     }
 283  
 
 284  
     // getters and setters ---------------------------------------------------------
 285  
 
 286  
     public boolean isKeepSendSocketOpen()
 287  
     {
 288  0
         return keepSendSocketOpen;
 289  
     }
 290  
 
 291  
     public void setKeepSendSocketOpen(boolean keepSendSocketOpen)
 292  
     {
 293  0
         this.keepSendSocketOpen = keepSendSocketOpen;
 294  0
     }
 295  
 
 296  
     /**
 297  
      * A shorthand property setting timeout for both SEND and RECEIVE sockets.
 298  
      *
 299  
      * @deprecated The time out should be set explicitly for each
 300  
      */
 301  
     @Deprecated
 302  
     public void setTimeout(int timeout)
 303  
     {
 304  0
         setClientSoTimeout(timeout);
 305  0
         setServerSoTimeout(timeout);
 306  0
     }
 307  
 
 308  
     public int getClientSoTimeout()
 309  
     {
 310  0
         return this.clientSoTimeout;
 311  
     }
 312  
 
 313  
     public void setClientSoTimeout(int timeout)
 314  
     {
 315  0
         this.clientSoTimeout = valueOrDefault(timeout, 0, DEFAULT_SOCKET_TIMEOUT);
 316  0
     }
 317  
 
 318  
     public int getServerSoTimeout()
 319  
     {
 320  0
         return serverSoTimeout;
 321  
     }
 322  
 
 323  
     public void setServerSoTimeout(int timeout)
 324  
     {
 325  0
         this.serverSoTimeout = valueOrDefault(timeout, 0, DEFAULT_SOCKET_TIMEOUT);
 326  0
     }
 327  
 
 328  
     public int getSocketMaxWait()
 329  
     {
 330  0
         return socketMaxWait;
 331  
     }
 332  
 
 333  
     public void setSocketMaxWait(int timeout)
 334  
     {
 335  0
         this.socketMaxWait = valueOrDefault(timeout, 0, DEFAULT_WAIT_TIMEOUT);
 336  0
     }
 337  
 
 338  
     /** @deprecated Should use {@link #getSendBufferSize()} or {@link #getReceiveBufferSize()} */
 339  
     @Deprecated
 340  
     public int getBufferSize()
 341  
     {
 342  0
         return sendBufferSize;
 343  
     }
 344  
 
 345  
     /** @deprecated Should use {@link #setSendBufferSize(int)} or {@link #setReceiveBufferSize(int)} */
 346  
     @Deprecated
 347  
     public void setBufferSize(int bufferSize)
 348  
     {
 349  0
         sendBufferSize = valueOrDefault(bufferSize, 1, DEFAULT_BUFFER_SIZE);
 350  0
     }
 351  
 
 352  
     public int getSendBufferSize()
 353  
     {
 354  0
         return sendBufferSize;
 355  
     }
 356  
 
 357  
     public void setSendBufferSize(int bufferSize)
 358  
     {
 359  0
         sendBufferSize = valueOrDefault(bufferSize, 1, DEFAULT_BUFFER_SIZE);
 360  0
     }
 361  
 
 362  
     public int getReceiveBufferSize()
 363  
     {
 364  0
         return receiveBufferSize;
 365  
     }
 366  
 
 367  
     public void setReceiveBufferSize(int bufferSize)
 368  
     {
 369  0
         receiveBufferSize = valueOrDefault(bufferSize, 1, DEFAULT_BUFFER_SIZE);
 370  0
     }
 371  
 
 372  
     public int getReceiveBacklog()
 373  
     {
 374  0
         return receiveBacklog;
 375  
     }
 376  
 
 377  
     public void setReceiveBacklog(int receiveBacklog)
 378  
     {
 379  0
         this.receiveBacklog = valueOrDefault(receiveBacklog, 0, DEFAULT_BACKLOG);
 380  0
     }
 381  
 
 382  
     public int getSocketSoLinger()
 383  
     {
 384  0
         return socketSoLinger;
 385  
     }
 386  
 
 387  
     public void setSocketSoLinger(int soLinger)
 388  
     {
 389  0
         this.socketSoLinger = valueOrDefault(soLinger, 0, INT_VALUE_NOT_SET);
 390  0
     }
 391  
 
 392  
     /**
 393  
      * @deprecated should use {@link #getReceiveBacklog()}
 394  
      */
 395  
     @Deprecated
 396  
     public int getBacklog()
 397  
     {
 398  0
         return receiveBacklog;
 399  
     }
 400  
 
 401  
     /**
 402  
      * @param backlog
 403  
      * @deprecated should use {@link #setReceiveBacklog(int)}
 404  
      */
 405  
     @Deprecated
 406  
     public void setBacklog(int backlog)
 407  
     {
 408  0
         this.receiveBacklog = backlog;
 409  0
     }
 410  
 
 411  
     public TcpProtocol getTcpProtocol()
 412  
     {
 413  0
         return tcpProtocol;
 414  
     }
 415  
 
 416  
     public void setTcpProtocol(TcpProtocol tcpProtocol)
 417  
     {
 418  0
         this.tcpProtocol = tcpProtocol;
 419  0
     }
 420  
 
 421  
     @Override
 422  
     public boolean isResponseEnabled()
 423  
     {
 424  0
         return true;
 425  
     }
 426  
 
 427  
     public boolean isKeepAlive()
 428  
     {
 429  0
         return keepAlive;
 430  
     }
 431  
 
 432  
     public void setKeepAlive(boolean keepAlive)
 433  
     {
 434  0
         this.keepAlive = keepAlive;
 435  0
     }
 436  
 
 437  
     public boolean isSendTcpNoDelay()
 438  
     {
 439  0
         return sendTcpNoDelay;
 440  
     }
 441  
 
 442  
     public void setSendTcpNoDelay(boolean sendTcpNoDelay)
 443  
     {
 444  0
         this.sendTcpNoDelay = sendTcpNoDelay;
 445  0
     }
 446  
 
 447  
     protected void setSocketFactory(AbstractTcpSocketFactory socketFactory)
 448  
     {
 449  0
         this.socketFactory = socketFactory;
 450  0
     }
 451  
 
 452  
     protected AbstractTcpSocketFactory getSocketFactory()
 453  
     {
 454  0
         return socketFactory;
 455  
     }
 456  
 
 457  
     public SimpleServerSocketFactory getServerSocketFactory()
 458  
     {
 459  0
         return serverSocketFactory;
 460  
     }
 461  
 
 462  
     public void setServerSocketFactory(SimpleServerSocketFactory serverSocketFactory)
 463  
     {
 464  0
         this.serverSocketFactory = serverSocketFactory;
 465  0
     }
 466  
 
 467  
     protected ServerSocket getServerSocket(URI uri) throws IOException
 468  
     {
 469  0
         return getServerSocketFactory().createServerSocket(uri, getReceiveBacklog(), isReuseAddress());
 470  
     }
 471  
 
 472  
     private static int valueOrDefault(int value, int threshhold, int deflt)
 473  
     {
 474  0
         if (value < threshhold)
 475  
         {
 476  0
             return deflt;
 477  
         }
 478  
         else
 479  
         {
 480  0
             return value;
 481  
         }
 482  
     }
 483  
 
 484  
     /**
 485  
      * @return true if the server socket sets SO_REUSEADDRESS before opening
 486  
      */
 487  
     public Boolean isReuseAddress()
 488  
     {
 489  0
         return reuseAddress;
 490  
     }
 491  
 
 492  
     /**
 493  
      * This allows closed sockets to be reused while they are still in TIME_WAIT state
 494  
      *
 495  
      * @param reuseAddress Whether the server socket sets SO_REUSEADDRESS before opening
 496  
      */
 497  
     public void setReuseAddress(Boolean reuseAddress)
 498  
     {
 499  0
         this.reuseAddress = reuseAddress;
 500  0
     }
 501  
 
 502  
     public ExpiryMonitor getKeepAliveMonitor()
 503  
     {
 504  0
         return keepAliveMonitor;
 505  
     }
 506  
     
 507  
     /**
 508  
      * @return keep alive timeout in Milliseconds
 509  
      */
 510  
     public int getKeepAliveTimeout()
 511  
     {
 512  0
         return keepAliveTimeout;
 513  
     }
 514  
     
 515  
     /**
 516  
      * Sets the keep alive timeout (in Milliseconds)
 517  
      */
 518  
     public void setKeepAliveTimeout(int keepAliveTimeout)
 519  
     {
 520  0
         this.keepAliveTimeout = keepAliveTimeout;
 521  0
     }
 522  
     
 523  
     @Override
 524  
     public void setDispatcherFactory(MessageDispatcherFactory dispatcherFactory)
 525  
     {
 526  0
         if (this.dispatcherFactory == null) {
 527  0
             super.setDispatcherFactory(dispatcherFactory);
 528  
         }
 529  0
     }
 530  
 
 531  
     public ConfigurableKeyedObjectPool getDispatchers()
 532  
     {
 533  0
         return dispatchers;
 534  
     }
 535  
 
 536  
     public int getSocketsPoolMaxActive()
 537  
     {
 538  0
         return socketsPool.getMaxActive();
 539  
     }
 540  
 
 541  
     public int getSocketsPoolMaxIdle()
 542  
     {
 543  0
         return socketsPool.getMaxIdle();
 544  
     }
 545  
 
 546  
     public int getSocketsPoolNumActive()
 547  
     {
 548  0
         return socketsPool.getNumActive();
 549  
     }
 550  
 
 551  
     public long getSocketsPoolMaxWait()
 552  
     {
 553  0
         return socketsPool.getMaxWait();
 554  
     }
 555  
 
 556  
 }