View Javadoc

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