View Javadoc

1   /*
2    * $Id: TcpMessageDispatcher.java 19191 2010-08-25 21:05:23Z tcarlson $
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.tcp;
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.retry.RetryContext;
19  import org.mule.api.transformer.TransformerException;
20  import org.mule.transport.AbstractMessageDispatcher;
21  import org.mule.transport.NullPayload;
22  
23  import java.io.BufferedInputStream;
24  import java.io.BufferedOutputStream;
25  import java.io.DataInputStream;
26  import java.io.IOException;
27  import java.net.Socket;
28  import java.net.SocketTimeoutException;
29  
30  /**
31   * Send transformed Mule events over TCP.
32   */
33  public class TcpMessageDispatcher extends AbstractMessageDispatcher
34  {
35  
36      private final TcpConnector connector;
37  
38      public TcpMessageDispatcher(OutboundEndpoint endpoint)
39      {
40          super(endpoint);
41          this.connector = (TcpConnector) endpoint.getConnector();
42      }
43  
44      @Override
45      protected synchronized void doDispatch(MuleEvent event) throws Exception
46      {
47          Socket socket = connector.getSocket(event.getEndpoint());
48          try 
49          {
50              dispatchToSocket(socket, event);
51          }
52          finally 
53          {
54              connector.releaseSocket(socket, event.getEndpoint());
55          }
56      }
57  
58      @Override
59      protected synchronized MuleMessage doSend(MuleEvent event) throws Exception
60      {
61          Socket socket = connector.getSocket(event.getEndpoint());
62          dispatchToSocket(socket, event);
63  
64          try 
65          {
66              if (returnResponse(event))
67              {
68                  try
69                  {
70                      Object result = receiveFromSocket(socket, event.getTimeout(), endpoint);
71                      if (result == null)
72                      {
73                          return new DefaultMuleMessage(NullPayload.getInstance(), connector.getMuleContext());
74                      }
75                      
76                      if (result instanceof MuleMessage)
77                      {
78                          return (MuleMessage) result;
79                      }
80                      
81                      return createMuleMessage(result, endpoint.getEncoding());
82                  }
83                  catch (SocketTimeoutException e)
84                  {
85                      // we don't necessarily expect to receive a response here
86                      logger.info("Socket timed out normally while doing a synchronous receive on endpointUri: "
87                          + event.getEndpoint().getEndpointURI());
88                      return new DefaultMuleMessage(NullPayload.getInstance(), connector.getMuleContext());
89                  }
90              }
91              else
92              {
93                  return new DefaultMuleMessage(NullPayload.getInstance(), connector.getMuleContext());
94              }
95          }
96          finally
97          {
98              if (!returnResponse(event))
99              {
100                 connector.releaseSocket(socket, endpoint);
101             }
102         }
103         
104     }
105 
106     // Socket management (get and release) is handled outside this method
107     private void dispatchToSocket(Socket socket, MuleEvent event) throws Exception
108     {
109         Object payload = event.getMessage().getPayload();
110         write(socket, payload);
111     }
112 
113     private void write(Socket socket, Object data) throws IOException, TransformerException
114     {
115         BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
116         connector.getTcpProtocol().write(bos, data);
117         bos.flush();
118     }
119 
120     protected static Object receiveFromSocket(final Socket socket, int timeout, final ImmutableEndpoint endpoint)
121             throws IOException
122     {
123         final TcpConnector connector = (TcpConnector) endpoint.getConnector();
124         DataInputStream underlyingIs = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
125         TcpInputStream tis = new TcpInputStream(underlyingIs)
126         {
127             @Override
128             public void close() throws IOException
129             {
130                 try
131                 {
132                     connector.releaseSocket(socket, endpoint);
133                 }
134                 catch (IOException e)
135                 {
136                    throw e;
137                 }
138                 catch (Exception e)
139                 {
140                     IOException e2 = new IOException();
141                     e2.initCause(e);
142                     throw e2;
143                 }
144             }
145 
146         };
147 
148         if (timeout >= 0)
149         {
150             socket.setSoTimeout(timeout);
151         }
152 
153         try
154         {
155             return connector.getTcpProtocol().read(tis);
156         }
157         finally
158         {
159             if (!tis.isStreaming())
160             {
161                 tis.close();
162             }
163         }
164     }
165 
166     @Override
167     protected synchronized void doDispose()
168     {
169         try
170         {
171             doDisconnect();
172         }
173         catch (Exception e)
174         {
175             logger.error("Failed to shutdown the dispatcher.", e);
176         }
177     }
178 
179     @Override
180     protected void doConnect() throws Exception
181     {
182         // nothing, there is an optional validation in validateConnection()
183     }
184 
185     @Override
186     protected void doDisconnect() throws Exception
187     {
188         //nothing to do
189     }
190 
191     @Override
192     public RetryContext validateConnection(RetryContext retryContext)
193     {
194         Socket socket = null;
195         try
196         {
197             socket = connector.getSocket(endpoint);
198 
199             retryContext.setOk();
200         }
201         catch (Exception ex)
202         {
203             retryContext.setFailed(ex);
204         }
205         finally
206         {
207             if (socket != null)
208             {
209                 try
210                 {
211                     connector.releaseSocket(socket, endpoint);
212                 }
213                 catch (Exception e)
214                 {
215                     if (logger.isDebugEnabled())
216                     {
217                         logger.debug("Failed to release a socket " + socket, e);
218                     }
219                 }
220             }
221         }
222         
223         return retryContext;
224     }
225 }