View Javadoc

1   /*
2    * $Id: CxfMessageDispatcher.java 12248 2008-07-07 22:08:28Z dandiep $
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.cxf;
12  
13  import org.mule.DefaultMuleMessage;
14  import org.mule.api.MuleEvent;
15  import org.mule.api.MuleMessage;
16  import org.mule.api.config.MuleProperties;
17  import org.mule.api.endpoint.EndpointURI;
18  import org.mule.api.endpoint.OutboundEndpoint;
19  import org.mule.api.transformer.TransformerException;
20  import org.mule.transport.AbstractMessageDispatcher;
21  import org.mule.transport.soap.SoapConstants;
22  import org.mule.util.TemplateParser;
23  
24  import java.lang.reflect.Method;
25  import java.util.ArrayList;
26  import java.util.Arrays;
27  import java.util.HashMap;
28  import java.util.Iterator;
29  import java.util.List;
30  import java.util.Map;
31  import java.util.Set;
32  import java.util.regex.Pattern;
33  
34  import javax.activation.DataHandler;
35  import javax.xml.namespace.QName;
36  import javax.xml.ws.BindingProvider;
37  
38  import org.apache.cxf.endpoint.Client;
39  import org.apache.cxf.endpoint.ClientImpl;
40  import org.apache.cxf.service.model.BindingOperationInfo;
41  
42  /**
43   * The CxfMessageDispatcher is used for making Soap client requests to remote
44   * services.
45   */
46  public class CxfMessageDispatcher extends AbstractMessageDispatcher
47  {
48  
49      private static final String URI_REGEX = "cxf:\\[(.+?)\\]:(.+?)/\\[(.+?)\\]:(.+?)";
50      Pattern URI_PATTERN = Pattern.compile(URI_REGEX);
51  
52      protected final CxfConnector connector;
53      protected ClientWrapper wrapper;
54      private final TemplateParser soapActionTemplateParser = TemplateParser.createAntStyleParser();
55  
56      public CxfMessageDispatcher(OutboundEndpoint endpoint)
57      {
58          super(endpoint);
59          this.connector = (CxfConnector) endpoint.getConnector();
60      }
61  
62      /*
63      We need a way to associate an endpoint with a specific CXF service and operation, and the most sensible way to
64      accomplish that is to overload URI syntax:
65  
66      cxf:[service_URI]:service_localname/[ep_URI]:ep_localname
67  
68      And the map method to operation
69       */
70      protected void doConnect() throws Exception
71      {
72          wrapper = new ClientWrapper();
73          wrapper.setBus(connector.getCxfBus());
74          wrapper.setEndpoint(endpoint);
75          wrapper.initialize();
76      }
77  
78      protected void doDisconnect() throws Exception
79      {
80          wrapper = null;
81      }
82  
83      protected void doDispose()
84      {
85          // nothing to do
86      }
87  
88  
89      protected Object[] getArgs(MuleEvent event) throws TransformerException
90      {
91          Object payload = event.transformMessage();
92          Object[] args;
93  
94          if (payload instanceof Object[])
95          {
96              args = (Object[])payload;
97          }
98          else
99          {
100             args = new Object[]{payload};
101         }
102 
103         MuleMessage message = event.getMessage();
104         Set<?> attachmentNames = message.getAttachmentNames();
105         if (attachmentNames != null && !attachmentNames.isEmpty())
106         {
107             List<DataHandler> attachments = new ArrayList<DataHandler>();
108             for (Iterator<?> i = attachmentNames.iterator(); i.hasNext();)
109             {
110                 attachments.add(message.getAttachment((String)i.next()));
111             }
112             List<Object> temp = new ArrayList<Object>(Arrays.asList(args));
113             temp.add(attachments.toArray(new DataHandler[0]));
114             args = temp.toArray();
115         }
116 
117         if (args.length == 0)
118         {
119             return null;
120         }
121         return args;
122     }
123 
124     protected MuleMessage doSend(MuleEvent event) throws Exception
125     {
126         ((ClientImpl)wrapper.getClient()).setSynchronousTimeout(event.getTimeout());
127         if (!wrapper.isClientProxyAvailable())
128         {
129             return doSendWithClient(event);
130         }
131         else
132         {
133             return doSendWithProxy(event);
134         }
135     }
136 
137     protected MuleMessage doSendWithProxy(MuleEvent event) throws Exception
138     {
139         Method method = wrapper.getMethod(event);
140 
141         Map<String, Object> props = new HashMap<String, Object>();
142         props.put(MuleProperties.MULE_EVENT_PROPERTY, event); 
143         
144         // Set custom soap action if set on the event or endpoint
145         String soapAction = (String)event.getMessage().getProperty(SoapConstants.SOAP_ACTION_PROPERTY);
146         if (soapAction != null)
147         {
148             soapAction = parseSoapAction(soapAction, new QName(method.getName()), event);
149             props.put(org.apache.cxf.binding.soap.SoapConstants.SOAP_ACTION, soapAction);
150         }
151         
152         BindingProvider bp = wrapper.getClientProxy();
153         bp.getRequestContext().putAll(props);
154         
155         Object response = method.invoke(wrapper.getClientProxy(), (Object[]) getArgs(event));
156         
157         // TODO: handle holders
158         
159         return buildResponseMessage(event, new Object[] { response });
160     }
161 
162     protected MuleMessage doSendWithClient(MuleEvent event) throws Exception
163     {
164         BindingOperationInfo bop = wrapper.getOperation(event);
165         
166         Map<String, Object> props = new HashMap<String, Object>();
167         props.put(MuleProperties.MULE_EVENT_PROPERTY, event); 
168         
169         // Set custom soap action if set on the event or endpoint
170         String soapAction = (String)event.getMessage().getProperty(SoapConstants.SOAP_ACTION_PROPERTY);
171         if (soapAction != null)
172         {
173             soapAction = parseSoapAction(soapAction, bop.getName(), event);
174             props.put(org.apache.cxf.binding.soap.SoapConstants.SOAP_ACTION, soapAction);
175             event.getMessage().setProperty(SoapConstants.SOAP_ACTION_PROPERTY, soapAction);
176         }
177         
178         Map<String, Object> ctx = new HashMap<String, Object>();
179         ctx.put(Client.REQUEST_CONTEXT, props); 
180         ctx.put(Client.RESPONSE_CONTEXT, props); 
181         
182         // Set Custom Headers on the client
183         Object[] arr = event.getMessage().getPropertyNames().toArray();
184         String head;
185 
186         for (int i = 0; i < arr.length; i++)
187         {
188             head = (String) arr[i];
189             if ((head != null) && (!head.startsWith("MULE")))
190             {
191                 props.put((String) arr[i], event.getMessage().getProperty((String) arr[i]));
192             }
193         }
194         
195         Object[] response = wrapper.getClient().invoke(bop, getArgs(event), ctx);
196 
197         return buildResponseMessage(event, response);
198     }
199 
200     protected MuleMessage buildResponseMessage(MuleEvent event, Object[] response) 
201     {
202         MuleMessage result = null;
203         if (response != null && response.length <= 1)
204         {
205             if (response.length == 1)
206             {
207                 result = new DefaultMuleMessage(response[0], event.getMessage());
208             }
209         }
210         else
211         {
212             result = new DefaultMuleMessage(response, event.getMessage());
213         }
214 
215         return result;
216     }
217     protected void doDispatch(MuleEvent event) throws Exception
218     {
219         doSend(event);
220     }
221 
222     public String parseSoapAction(String soapAction, QName method, MuleEvent event)
223     {
224         EndpointURI endpointURI = event.getEndpoint().getEndpointURI();
225         Map<String, String> properties = new HashMap<String, String>();
226         MuleMessage msg = event.getMessage();
227         for (Iterator<?> iterator = msg.getPropertyNames().iterator(); iterator.hasNext();)
228         {
229             String propertyKey = (String)iterator.next();
230             properties.put(propertyKey, msg.getProperty(propertyKey).toString());
231         }
232         properties.put(MuleProperties.MULE_METHOD_PROPERTY, method.getLocalPart());
233         properties.put("methodNamespace", method.getNamespaceURI());
234         properties.put("address", endpointURI.getAddress());
235         properties.put("scheme", endpointURI.getScheme());
236         properties.put("host", endpointURI.getHost());
237         properties.put("port", String.valueOf(endpointURI.getPort()));
238         properties.put("path", endpointURI.getPath());
239         properties.put("hostInfo", endpointURI.getScheme()
240                                    + "://"
241                                    + endpointURI.getHost()
242                                    + (endpointURI.getPort() > -1
243                                                    ? ":" + String.valueOf(endpointURI.getPort()) : ""));
244         if (event.getService() != null)
245         {
246             properties.put("serviceName", event.getService().getName());
247         }
248 
249         soapAction = soapActionTemplateParser.parse(properties, soapAction);
250 
251         if (logger.isDebugEnabled())
252         {
253             logger.debug("SoapAction for this call is: " + soapAction);
254         }
255 
256         return soapAction;
257     }
258 }