View Javadoc

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