View Javadoc

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