View Javadoc
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.soap.axis.extensions;
8   
9   import org.mule.DefaultMuleEvent;
10  import org.mule.DefaultMuleMessage;
11  import org.mule.MessageExchangePattern;
12  import org.mule.RequestContext;
13  import org.mule.api.MuleContext;
14  import org.mule.api.MuleEvent;
15  import org.mule.api.MuleException;
16  import org.mule.api.MuleMessage;
17  import org.mule.api.MuleSession;
18  import org.mule.api.config.MuleProperties;
19  import org.mule.api.endpoint.EndpointBuilder;
20  import org.mule.api.endpoint.EndpointURI;
21  import org.mule.api.endpoint.ImmutableEndpoint;
22  import org.mule.api.endpoint.OutboundEndpoint;
23  import org.mule.api.processor.MessageProcessor;
24  import org.mule.api.routing.OutboundRouter;
25  import org.mule.api.routing.OutboundRouterCollection;
26  import org.mule.api.service.Service;
27  import org.mule.endpoint.EndpointURIEndpointBuilder;
28  import org.mule.endpoint.MuleEndpointURI;
29  import org.mule.module.cxf.SoapConstants;
30  import org.mule.session.DefaultMuleSession;
31  import org.mule.transport.http.HttpConstants;
32  import org.mule.transport.soap.axis.AxisConnector;
33  import org.mule.transport.soap.axis.extras.AxisCleanAndAddProperties;
34  
35  import java.io.File;
36  import java.io.FileInputStream;
37  import java.io.FileOutputStream;
38  import java.util.HashMap;
39  import java.util.Iterator;
40  import java.util.Map;
41  
42  import org.apache.axis.AxisFault;
43  import org.apache.axis.Message;
44  import org.apache.axis.MessageContext;
45  import org.apache.axis.client.Call;
46  import org.apache.axis.handlers.BasicHandler;
47  import org.apache.commons.io.output.ByteArrayOutputStream;
48  import org.apache.commons.logging.Log;
49  import org.apache.commons.logging.LogFactory;
50  
51  /**
52   * An Axis handler that will dispatch the SOAP event via a Mule endpoint
53   */
54  public class UniversalSender extends BasicHandler
55  {
56      /**
57       * Serial version
58       */
59      private static final long serialVersionUID = 7943380365092172940L;
60  
61      /**
62       * logger used by this class
63       */
64      protected transient Log logger = LogFactory.getLog(getClass());
65  
66      protected Map endpointsCache = new HashMap();
67  
68      protected MuleContext muleContext;
69  
70  
71      public void invoke(MessageContext msgContext) throws AxisFault
72      {
73          try
74          {
75              boolean sync = true;
76              Call call = (Call)msgContext.getProperty("call_object");
77  
78              if (call == null)
79              {
80                  throw new IllegalStateException(
81                      "The call_object property must be set on the message context to the client Call object");
82              }
83  
84              muleContext = (MuleContext)call.getProperty(MuleProperties.MULE_CONTEXT_PROPERTY);
85              if(muleContext==null)
86              {
87                  throw new IllegalArgumentException("Property org.mule.MuleContext not set on Axis MessageContext");
88              }
89  
90              // Get the event stored in call if a request call is made there will be no event
91              MuleEvent event = (MuleEvent)call.getProperty(MuleProperties.MULE_EVENT_PROPERTY);
92  
93              if (Boolean.TRUE.equals(call.getProperty("axis.one.way")))
94              {
95                  sync = false;
96              }
97  
98              // Get the dispatch endpoint
99              String uri = msgContext.getStrProp(MessageContext.TRANS_URL);
100             ImmutableEndpoint requestEndpoint = (ImmutableEndpoint)call
101                 .getProperty(MuleProperties.MULE_ENDPOINT_PROPERTY);
102 
103             OutboundEndpoint endpoint;
104 
105             // put username and password in URI if they are set on the current event
106             if (msgContext.getUsername() != null)
107             {
108                 String[] tempEndpoint = uri.split("//");
109                 String credentialString = msgContext.getUsername() + ":"
110                                           + msgContext.getPassword();
111                 uri = tempEndpoint[0] + "//" + credentialString + "@" + tempEndpoint[1];
112                 endpoint = lookupEndpoint(uri);
113             }
114             else
115             {
116                 endpoint = lookupEndpoint(uri);
117             }
118 
119             if (requestEndpoint.getConnector() instanceof AxisConnector)
120             {
121                 msgContext.setTypeMappingRegistry(((AxisConnector)requestEndpoint.getConnector())
122                     .getAxis().getTypeMappingRegistry());
123             }
124 
125             Map<String, Object> props = new HashMap<String, Object>();
126             Object payload;
127             int contentLength = 0;
128             String contentType = null;
129             if (msgContext.getRequestMessage().countAttachments() > 0)
130             {
131                 File temp = File.createTempFile("soap", ".tmp");
132                 temp.deleteOnExit(); // TODO cleanup files earlier (IOUtils has a
133                 // file tracker)
134                 FileOutputStream fos = new FileOutputStream(temp);
135                 msgContext.getRequestMessage().writeTo(fos);
136                 fos.close();
137                 contentLength = (int)temp.length();
138                 payload = new FileInputStream(temp);
139                 contentType = "multipart/related";
140             }
141             else
142             {
143                 ByteArrayOutputStream baos = new ByteArrayOutputStream(8192);
144                 msgContext.getRequestMessage().writeTo(baos);
145                 baos.close();
146                 payload = baos.toByteArray();
147             }
148 
149             // props.putAll(event.getProperties());
150             for (Iterator iterator = msgContext.getPropertyNames(); iterator.hasNext();)
151             {
152                 String name = (String)iterator.next();
153                 if (!name.equals("call_object") && !name.equals("wsdl.service"))
154                 {
155                     props.put(name, msgContext.getProperty(name));
156                 }
157             }
158 
159             // add all custom headers, filter out all mule headers (such as
160             // MULE_SESSION) except
161             // for MULE_USER header. Filter out other headers like "soapMethods" and
162             // MuleProperties.MULE_METHOD_PROPERTY and "soapAction"
163             // and also filter out any http related header
164             if ((RequestContext.getEvent() != null)
165                 && (RequestContext.getEvent().getMessage() != null))
166             {
167                 props = AxisCleanAndAddProperties.cleanAndAdd(RequestContext.getEventContext());
168             }
169 
170             // with jms and vm the default SOAPAction will result in the name of the endpoint, which we may not necessarily want. This should be set manually on the endpoint
171             String scheme = requestEndpoint.getEndpointURI().getScheme();
172             if (!("vm".equalsIgnoreCase(scheme) || "jms".equalsIgnoreCase(scheme)))
173             {
174                 if (call.useSOAPAction())
175                 {
176                     uri = call.getSOAPActionURI();
177                 }
178                 props.put(SoapConstants.SOAP_ACTION_PROPERTY_CAPS, uri);
179             }
180             if (contentLength > 0)
181             {
182                 props.put(HttpConstants.HEADER_CONTENT_LENGTH, Integer.toString(contentLength)); // necessary
183                 // for
184                 // supporting
185                 // httpclient
186             }
187 
188 
189             if (props.get(HttpConstants.HEADER_CONTENT_TYPE) == null)
190             {
191                 if (contentType == null)
192                 {
193                     contentType = "text/xml";
194                 }
195 
196                 props.put(HttpConstants.HEADER_CONTENT_TYPE, contentType);
197             }
198             MuleMessage message = new DefaultMuleMessage(payload, props, muleContext);
199             MuleSession session;
200 
201             if(event != null)
202             {
203                 session = event.getSession();
204             }
205             else
206             {
207                 session = new DefaultMuleSession(muleContext);
208             }
209 
210             logger.info("Making Axis soap request on: " + uri);
211             if (logger.isDebugEnabled())
212             {
213                 logger.debug("Soap request is:\n" + new String((payload instanceof byte[] ? (byte[])payload : payload.toString().getBytes())));
214             }
215 
216             if (sync)
217             {
218                 EndpointBuilder builder = new EndpointURIEndpointBuilder(endpoint);
219                 builder.setExchangePattern(MessageExchangePattern.REQUEST_RESPONSE);
220                 OutboundEndpoint syncEndpoint = muleContext.getEndpointFactory()
221                     .getOutboundEndpoint(builder);
222                 MuleEvent dispatchEvent = new DefaultMuleEvent(message, syncEndpoint, session);
223                 MuleMessage result = null;
224                 MuleEvent resultEvent = syncEndpoint.process(dispatchEvent);
225                 if (resultEvent != null)
226                 {
227                     result = resultEvent.getMessage();
228                 }
229 
230                 if (result != null)
231                 {
232                     byte[] response = result.getPayloadAsBytes();
233                     Message responseMessage = new Message(response);
234                     msgContext.setResponseMessage(responseMessage);
235 
236                 }
237                 else
238                 {
239                     logger
240                         .warn("No response message was returned from synchronous call to: " + uri);
241                 }
242                 // remove temp file created for streaming
243                 if (payload instanceof File)
244                 {
245                     ((File)payload).delete();
246                 }
247             }
248             else
249             {
250                 MuleEvent dispatchEvent = new DefaultMuleEvent(message, endpoint, session);
251                 endpoint.process(dispatchEvent);
252             }
253         }
254         catch (Exception e)
255         {
256             if (e instanceof AxisFault)
257             {
258                 throw (AxisFault) e;
259             }
260             else
261             {
262                 throw new AxisFault(e.getMessage(), e);
263             }
264         }
265 
266     }
267 
268     protected OutboundEndpoint lookupEndpoint(String uri) throws MuleException
269     {
270         Service axis = muleContext.getRegistry().lookupService(AxisConnector.AXIS_SERVICE_COMPONENT_NAME);
271         EndpointURI endpoint = new MuleEndpointURI(uri, muleContext);
272 
273         OutboundEndpoint ep;
274 
275         if (axis != null)
276         {
277             synchronized (endpointsCache)
278             {
279                 ep = (OutboundEndpoint) endpointsCache.get(endpoint.getAddress());
280                 if (ep == null)
281                 {
282                     updateEndpointCache((OutboundRouterCollection) axis.getOutboundMessageProcessor());
283                     ep = (OutboundEndpoint) endpointsCache.get(endpoint.getAddress());
284                     if (ep == null)
285                     {
286                         logger.debug("Dispatch Endpoint uri: " + uri
287                                      + " not found on the cache. Creating the endpoint instead.");
288                         ep = muleContext.getEndpointFactory().getOutboundEndpoint(uri);
289                     }
290                     else
291                     {
292                         logger.info("Found endpoint: " + uri + " on the Axis service component");
293                     }
294                 }
295                 else
296                 {
297                     logger.info("Found endpoint: " + uri + " on the Axis service component");
298                 }
299             }
300         }
301         else
302         {
303             ep = muleContext.getEndpointFactory().getOutboundEndpoint(uri);
304         }
305         return ep;
306     }
307 
308     private void updateEndpointCache(OutboundRouterCollection router)
309     {
310         endpointsCache.clear();
311         for (Iterator iterator = router.getRoutes().iterator(); iterator.hasNext();)
312         {
313             OutboundRouter r = (OutboundRouter)iterator.next();
314             for (MessageProcessor mp : r.getRoutes())
315             {
316                 if (mp instanceof ImmutableEndpoint)
317                 {
318                     ImmutableEndpoint endpoint = (ImmutableEndpoint) mp;
319                     endpointsCache.put(endpoint.getEndpointURI().getAddress(), endpoint);
320                 }
321             }
322         }
323     }
324 }