View Javadoc

1   /*
2    * $Id: DefaultReplyToHandler.java 22808 2011-08-31 04:13:19Z mike.schilling $
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;
12  
13  import org.mule.DefaultMuleEvent;
14  import org.mule.DefaultMuleMessage;
15  import org.mule.api.MuleContext;
16  import org.mule.api.MuleEvent;
17  import org.mule.api.MuleException;
18  import org.mule.api.MuleMessage;
19  import org.mule.api.config.MuleProperties;
20  import org.mule.api.endpoint.EndpointBuilder;
21  import org.mule.api.endpoint.EndpointFactory;
22  import org.mule.api.endpoint.ImmutableEndpoint;
23  import org.mule.api.endpoint.OutboundEndpoint;
24  import org.mule.api.service.Service;
25  import org.mule.api.transport.Connector;
26  import org.mule.api.transport.DispatchException;
27  import org.mule.api.transport.ReplyToHandler;
28  import org.mule.config.i18n.CoreMessages;
29  import org.mule.management.stats.ServiceStatistics;
30  import org.mule.transport.service.TransportFactory;
31  import org.mule.util.ObjectNameHelper;
32  import org.mule.util.store.DeserializationPostInitialisable;
33  
34  import java.io.IOException;
35  import java.io.ObjectInputStream;
36  import java.io.ObjectOutputStream;
37  import java.io.Serializable;
38  import java.util.HashMap;
39  import java.util.List;
40  import java.util.Map;
41  
42  import org.apache.commons.logging.Log;
43  import org.apache.commons.logging.LogFactory;
44  
45  /**
46   * <code>DefaultReplyToHandler</code> is responsible for processing a message
47   * replyTo header.
48   */
49  
50  public class DefaultReplyToHandler implements ReplyToHandler, Serializable, DeserializationPostInitialisable
51  {
52      /**
53       * Serial version
54       */
55      private static final long serialVersionUID = 1L;
56  
57      /**
58       * logger used by this class
59       */
60      protected transient Log logger = LogFactory.getLog(getClass());
61  
62      private transient Map<String, ImmutableEndpoint> endpointCache = new HashMap<String, ImmutableEndpoint>();
63      protected transient MuleContext muleContext;
64      protected transient Connector connector;
65      private transient Map<String, Object> serializedData = null;
66  
67      public DefaultReplyToHandler(MuleContext muleContext)
68      {
69          this.muleContext = muleContext;
70      }
71  
72      public void processReplyTo(MuleEvent event, MuleMessage returnMessage, Object replyTo) throws MuleException
73      {
74          if (logger.isDebugEnabled())
75          {
76              logger.debug("sending reply to: " + replyTo);
77          }
78          String replyToEndpoint = replyTo.toString();
79  
80          // get the endpoint for this url
81          OutboundEndpoint endpoint = getEndpoint(event, replyToEndpoint);
82  
83          // make sure remove the replyTo property as not cause a a forever
84          // replyto loop
85          returnMessage.removeProperty(MuleProperties.MULE_REPLY_TO_PROPERTY);
86  
87          // MULE-4617. This is fixed with MULE-4620, but lets remove this property
88          // anyway as it should never be true from a replyTo dispatch
89          returnMessage.removeProperty(MuleProperties.MULE_REMOTE_SYNC_PROPERTY);
90  
91          // Create a new copy of the message so that response MessageProcessors don't end up screwing up the reply
92          returnMessage = new DefaultMuleMessage(returnMessage.getPayload(), returnMessage, muleContext);
93  
94          // Create the replyTo event asynchronous
95          MuleEvent replyToEvent = new DefaultMuleEvent(returnMessage, event);
96  
97          // carry over properties
98          List<String> responseProperties = endpoint.getResponseProperties();
99          for (String propertyName : responseProperties)
100         {
101             Object propertyValue = event.getMessage().getInboundProperty(propertyName);
102             if (propertyValue != null)
103             {
104                 replyToEvent.getMessage().setOutboundProperty(propertyName, propertyValue);
105             }
106         }
107 
108         // dispatch the event
109         try
110         {
111             if (event.getFlowConstruct() instanceof Service)
112             {
113                 ServiceStatistics stats = ((Service) event.getFlowConstruct()).getStatistics();
114                 if (stats.isEnabled())
115                 {
116                     stats.incSentReplyToEvent();
117                 }
118             }
119             endpoint.process(replyToEvent);
120             if (logger.isInfoEnabled())
121             {
122                 logger.info("reply to sent: " + endpoint);
123             }
124         }
125         catch (Exception e)
126         {
127             throw new DispatchException(CoreMessages.failedToDispatchToReplyto(endpoint),
128                 replyToEvent, endpoint, e);
129         }
130 
131     }
132 
133     protected synchronized OutboundEndpoint getEndpoint(MuleEvent event, String endpointUri) throws MuleException
134     {
135         OutboundEndpoint endpoint = (OutboundEndpoint) endpointCache.get(endpointUri);
136         if (endpoint == null)
137         {
138             EndpointFactory endpointFactory = muleContext.getEndpointFactory();
139             EndpointBuilder endpointBuilder = endpointFactory.getEndpointBuilder(endpointUri);
140             endpoint = endpointFactory.getOutboundEndpoint(endpointBuilder);
141             endpointCache.put(endpointUri, endpoint);
142         }
143         return endpoint;
144     }
145 
146     @SuppressWarnings({"unused", "unchecked"})
147     public void initAfterDeserialisation(MuleContext muleContext) throws MuleException
148     {
149         // this method can be called even on objects that were not serialized. In this case,
150         // the temporary holder for serialized data is not initialized and we can just return
151         if (serializedData == null)
152         {
153             return;
154         }
155         this.muleContext = muleContext;
156         logger = LogFactory.getLog(getClass());
157         endpointCache = new HashMap<String, ImmutableEndpoint>();
158         connector = findConnector();
159         serializedData = null;
160     }
161 
162     public Connector getConnector()
163     {
164         return connector;
165     }
166 
167     protected Connector findConnector()
168     {
169         String connectorName = (String) serializedData.get("connectorName");
170         String connectorType = (String) serializedData.get("connectorType");
171         Connector found =  null;
172 
173         if (connectorName != null)
174         {
175             found = muleContext.getRegistry().get(connectorName);
176         }
177         else if (connectorType != null)
178         {
179             found = new TransportFactory(muleContext).getDefaultConnectorByProtocol(connectorType);
180         }
181         return found;
182     }
183 
184     private void writeObject(ObjectOutputStream out) throws IOException
185     {
186         out.defaultWriteObject();
187 
188         String connectorName = null;
189         String connectorType = null;
190 
191         //Can be null if service call originates from MuleClient
192         if (serializedData != null)
193         {
194             connectorName = (String) serializedData.get("connectorName");
195             connectorType = (String) serializedData.get("connectorType");
196         }
197         else
198         {
199             if (connector != null)
200             {
201                 if (!ObjectNameHelper.isDefaultAutoGeneratedConnector(connector))
202                 {
203                     connectorName = connector.getName();
204                 }
205                 connectorType = connector.getProtocol();
206             }
207         }
208         out.writeObject(connectorName);
209         out.writeObject(connectorType);
210     }
211 
212     private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
213     {
214         in.defaultReadObject();
215         serializedData = new HashMap<String, Object>();
216 
217         serializedData.put("connectorName", in.readObject());
218         serializedData.put("connectorType", in.readObject());
219     }
220 }