View Javadoc

1   /*
2    * $Id: UniversalSender.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.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.getRegistry()
225                     .lookupEndpointFactory()
226                     .getOutboundEndpoint(builder);
227                 MuleEvent dispatchEvent = new DefaultMuleEvent(message, syncEndpoint, 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, endpoint, session);
256                 endpoint.process(dispatchEvent);
257             }
258         }
259         catch (Exception e)
260         {
261             if (e instanceof AxisFault)
262             {
263                 throw (AxisFault) e;
264             }
265             else
266             {
267                 throw new AxisFault(e.getMessage(), e);
268             }
269         }
270 
271     }
272 
273     protected OutboundEndpoint lookupEndpoint(String uri) throws MuleException
274     {
275         Service axis = muleContext.getRegistry().lookupService(AxisConnector.AXIS_SERVICE_COMPONENT_NAME);
276         EndpointURI endpoint = new MuleEndpointURI(uri, muleContext);
277 
278         OutboundEndpoint ep;
279 
280         if (axis != null)
281         {
282             synchronized (endpointsCache)
283             {
284                 ep = (OutboundEndpoint) endpointsCache.get(endpoint.getAddress());
285                 if (ep == null)
286                 {
287                     updateEndpointCache((OutboundRouterCollection) axis.getOutboundMessageProcessor());
288                     ep = (OutboundEndpoint) endpointsCache.get(endpoint.getAddress());
289                     if (ep == null)
290                     {
291                         logger.debug("Dispatch Endpoint uri: " + uri
292                                      + " not found on the cache. Creating the endpoint instead.");
293                         ep = muleContext.getRegistry().lookupEndpointFactory()
294                                 .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.getRegistry().lookupEndpointFactory()
310                     .getOutboundEndpoint(uri);
311         }
312         return ep;
313     }
314 
315     private void updateEndpointCache(OutboundRouterCollection router)
316     {
317         endpointsCache.clear();
318         for (Iterator iterator = router.getRoutes().iterator(); iterator.hasNext();)
319         {
320             OutboundRouter r = (OutboundRouter)iterator.next();
321             for (MessageProcessor mp : r.getRoutes())
322             {
323                 if (mp instanceof ImmutableEndpoint)
324                 {
325                     ImmutableEndpoint endpoint = (ImmutableEndpoint) mp;
326                     endpointsCache.put(endpoint.getEndpointURI().getAddress(), endpoint);
327                 }
328             }
329         }
330     }
331 }