1
2
3
4
5
6
7
8
9
10
11 package org.mule.transport.cxf;
12
13 import org.mule.api.MuleEvent;
14 import org.mule.api.config.MuleProperties;
15 import org.mule.api.endpoint.EndpointURI;
16 import org.mule.api.endpoint.ImmutableEndpoint;
17 import org.mule.api.lifecycle.CreateException;
18 import org.mule.api.transport.DispatchException;
19 import org.mule.transport.cxf.i18n.CxfMessages;
20 import org.mule.transport.cxf.support.MuleHeadersInInterceptor;
21 import org.mule.transport.cxf.support.MuleHeadersOutInterceptor;
22 import org.mule.transport.cxf.support.MuleProtocolHeadersOutInterceptor;
23 import org.mule.transport.cxf.support.OutputPayloadInterceptor;
24 import org.mule.transport.cxf.support.ProxyService;
25 import org.mule.transport.soap.i18n.SoapMessages;
26
27 import java.lang.reflect.Constructor;
28 import java.lang.reflect.Method;
29 import java.net.URL;
30 import java.util.HashMap;
31 import java.util.List;
32
33 import javax.xml.namespace.QName;
34 import javax.xml.ws.BindingProvider;
35 import javax.xml.ws.Service;
36 import javax.xml.ws.WebEndpoint;
37 import javax.xml.ws.WebServiceClient;
38
39 import org.apache.commons.lang.BooleanUtils;
40 import org.apache.cxf.Bus;
41 import org.apache.cxf.binding.Binding;
42 import org.apache.cxf.common.classloader.ClassLoaderUtils;
43 import org.apache.cxf.databinding.stax.StaxDataBinding;
44 import org.apache.cxf.databinding.stax.StaxDataBindingFeature;
45 import org.apache.cxf.endpoint.Client;
46 import org.apache.cxf.endpoint.ClientImpl;
47 import org.apache.cxf.endpoint.Endpoint;
48 import org.apache.cxf.endpoint.EndpointImpl;
49 import org.apache.cxf.feature.AbstractFeature;
50 import org.apache.cxf.frontend.ClientProxy;
51 import org.apache.cxf.frontend.ClientProxyFactoryBean;
52 import org.apache.cxf.frontend.MethodDispatcher;
53 import org.apache.cxf.interceptor.Interceptor;
54 import org.apache.cxf.interceptor.WrappedOutInterceptor;
55 import org.apache.cxf.message.Message;
56 import org.apache.cxf.phase.PhaseInterceptor;
57 import org.apache.cxf.resource.ResourceManager;
58 import org.apache.cxf.resource.URIResolver;
59 import org.apache.cxf.service.model.BindingOperationInfo;
60 import org.apache.cxf.service.model.EndpointInfo;
61 import org.apache.cxf.transport.ChainInitiationObserver;
62 import org.apache.cxf.transport.Destination;
63 import org.apache.cxf.transport.DestinationFactory;
64 import org.apache.cxf.transport.DestinationFactoryManager;
65 import org.apache.cxf.transport.MessageObserver;
66
67 public class ClientWrapper
68 {
69
70 protected ImmutableEndpoint endpoint;
71 protected Bus bus;
72 protected Client client;
73 protected String defaultMethodName;
74
75
76
77 protected BindingProvider clientProxy;
78 protected Method defaultMethod;
79
80 protected boolean proxy;
81
82 public Client getClient()
83 {
84 return client;
85 }
86
87 public BindingProvider getClientProxy()
88 {
89 return clientProxy;
90 }
91
92 @SuppressWarnings("unchecked")
93 public void initialize() throws Exception
94 {
95 String clientClass = (String) endpoint.getProperty(CxfConstants.CLIENT_CLASS);
96 proxy = BooleanUtils.toBoolean((String) endpoint.getProperty(CxfConstants.PROXY));
97
98 if (clientClass != null)
99 {
100 createClientFromClass(bus, clientClass);
101 }
102 else if (proxy)
103 {
104 createClientProxy(bus);
105 }
106 else
107 {
108 createClientFromLocalServer(bus);
109 }
110
111 addInterceptors(client.getInInterceptors(), (List<Interceptor>) endpoint.getProperty(CxfConstants.IN_INTERCEPTORS));
112 addInterceptors(client.getInFaultInterceptors(), (List<Interceptor>) endpoint.getProperty(CxfConstants.IN_FAULT_INTERCEPTORS));
113 addInterceptors(client.getOutInterceptors(), (List<Interceptor>) endpoint.getProperty(CxfConstants.OUT_INTERCEPTORS));
114 addInterceptors(client.getOutFaultInterceptors(), (List<Interceptor>) endpoint.getProperty(CxfConstants.OUT_FAULT_INTERCEPTORS));
115
116 if (proxy)
117 {
118 client.getOutInterceptors().add(new OutputPayloadInterceptor());
119 }
120
121 List<AbstractFeature> features = (List<AbstractFeature>) endpoint.getProperty(CxfConstants.OUT_FAULT_INTERCEPTORS);
122
123 if (features != null)
124 {
125 for (AbstractFeature f : features)
126 {
127 f.initialize(client, bus);
128 }
129 }
130
131 EndpointImpl ep = (EndpointImpl) client.getEndpoint();
132
133 Object mtomEnabled = endpoint.getProperty(CxfConstants.MTOM_ENABLED);
134 if (mtomEnabled != null)
135 {
136 HashMap<String, Object> props = new HashMap<String, Object>();
137 props.put(Message.MTOM_ENABLED, mtomEnabled);
138 ep.setProperties(props);
139 }
140
141 addMuleInterceptors();
142 }
143
144 @SuppressWarnings("unchecked")
145 private void addInterceptors(List<Interceptor> col, List<Interceptor> supplied)
146 {
147 if (supplied != null)
148 {
149 col.addAll(supplied);
150 }
151 }
152
153 protected Method findMethod(Class<?> clientCls) throws Exception
154 {
155 if (defaultMethod == null)
156 {
157 String op = (String) endpoint.getProperties().get(CxfConstants.OPERATION);
158 if (op == null)
159 {
160 op = (String) endpoint.getProperties().get(CxfConstants.OPERATION);
161 }
162
163 if (op != null)
164 {
165 return getMethodFromOperation(op);
166 }
167 }
168
169 return null;
170 }
171
172 protected BindingOperationInfo getOperation(String opName) throws Exception
173 {
174
175
176
177 Endpoint ep = client.getEndpoint();
178 QName q = new QName(ep.getService().getName().getNamespaceURI(), opName);
179 BindingOperationInfo bop = ep.getBinding().getBindingInfo().getOperation(q);
180 if (bop == null)
181 {
182 throw new Exception("No such operation: " + defaultMethod);
183 }
184
185 if (bop.isUnwrappedCapable())
186 {
187 bop = bop.getUnwrappedOperation();
188 }
189 return bop;
190 }
191
192 private Method getMethodFromOperation(String op) throws Exception
193 {
194 BindingOperationInfo bop = getOperation(op);
195 MethodDispatcher md = (MethodDispatcher) client.getEndpoint().getService().get(
196 MethodDispatcher.class.getName());
197 return md.getMethod(bop);
198 }
199
200 protected void createClientProxy(Bus bus) throws Exception
201 {
202
203 String wsdlLocation = (String) endpoint.getProperty(CxfConstants.WSDL_LOCATION);
204
205 ClientProxyFactoryBean cpf = new ClientProxyFactoryBean();
206 cpf.setServiceClass(ProxyService.class);
207 cpf.setDataBinding(new StaxDataBinding());
208 cpf.getFeatures().add(new StaxDataBindingFeature());
209 cpf.setAddress(endpoint.getEndpointURI().getAddress());
210
211 if (wsdlLocation != null)
212 {
213 cpf.setWsdlLocation(wsdlLocation);
214 }
215
216 this.client = ClientProxy.getClient(cpf.create());
217
218 Binding binding = this.client.getEndpoint().getBinding();
219
220 removeInterceptor(binding.getOutInterceptors(), WrappedOutInterceptor.class.getName());
221
222 proxy = true;
223 }
224
225 @SuppressWarnings("unchecked")
226 private void removeInterceptor(List<Interceptor> inInterceptors, String name) {
227
228 for (Interceptor<?> i : inInterceptors) {
229 if (i instanceof PhaseInterceptor) {
230 PhaseInterceptor<Message> p = (PhaseInterceptor<Message>)i;
231
232 if (p.getId().equals(name)) {
233 inInterceptors.remove(p);
234 return;
235 }
236 }
237 }
238 }
239
240 protected void createClientFromClass(Bus bus, String clientClassName) throws Exception
241 {
242
243 String wsdlLocation = (String) endpoint.getProperty(CxfConstants.WSDL_LOCATION);
244 Class<?> clientCls = ClassLoaderUtils.loadClass(clientClassName, getClass());
245
246 Service s = null;
247 if (wsdlLocation != null)
248 {
249 Constructor<?> cons = clientCls.getConstructor(URL.class, QName.class);
250 ResourceManager rr = bus.getExtension(ResourceManager.class);
251 URL url = rr.resolveResource(wsdlLocation, URL.class);
252
253 if (url == null)
254 {
255 URIResolver res = new URIResolver(wsdlLocation);
256
257 if (!res.isResolved())
258 {
259 throw new CreateException(CxfMessages.wsdlNotFound(wsdlLocation), this);
260 }
261 url = res.getURL();
262 }
263
264 WebServiceClient clientAnn = clientCls.getAnnotation(WebServiceClient.class);
265 QName svcName = new QName(clientAnn.targetNamespace(), clientAnn.name());
266
267 s = (Service) cons.newInstance(url, svcName);
268 }
269 else
270 {
271 s = (Service) clientCls.newInstance();
272 }
273 String port = (String) endpoint.getProperty(CxfConstants.CLIENT_PORT);
274
275 if (port == null)
276 {
277 throw new CreateException(CxfMessages.mustSpecifyPort(), this);
278 }
279
280 clientProxy = null;
281 if (port != null)
282 {
283 for (Method m : clientCls.getMethods())
284 {
285 WebEndpoint we = m.getAnnotation(WebEndpoint.class);
286
287 if (we != null && we.name().equals(port))
288 {
289 clientProxy = (BindingProvider) m.invoke(s, new Object[0]);
290 break;
291 }
292 }
293 }
294
295 if (clientProxy == null)
296 {
297 throw new CreateException(CxfMessages.portNotFound(port), this);
298 }
299
300 EndpointURI uri = endpoint.getEndpointURI();
301 if (uri.getUser() != null)
302 {
303 clientProxy.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, uri.getUser());
304 }
305
306 if (uri.getPassword() != null)
307 {
308 clientProxy.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, uri.getPassword());
309 }
310
311 clientProxy.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, uri.getAddress());
312
313 client = ClientProxy.getClient(clientProxy);
314
315 defaultMethod = findMethod(clientCls);
316 defaultMethodName = getDefaultMethodName();
317 }
318
319 private String getDefaultMethodName()
320 {
321 EndpointURI endpointUri = endpoint.getEndpointURI();
322 String m = (String) endpointUri.getParams().get(MuleProperties.MULE_METHOD_PROPERTY);
323
324 if (m == null)
325 {
326 m = (String) endpoint.getProperties().get(MuleProperties.MULE_METHOD_PROPERTY);
327 }
328
329 return m;
330 }
331
332 protected void createClientFromLocalServer(final Bus bus) throws Exception
333 {
334 String uri = endpoint.getEndpointURI().toString();
335 int idx = uri.indexOf('?');
336 if (idx != -1)
337 {
338 uri = uri.substring(0, idx);
339 }
340
341 EndpointInfo ei = new EndpointInfo();
342 ei.setAddress(uri);
343
344 DestinationFactoryManager dfm = bus.getExtension(DestinationFactoryManager.class);
345 DestinationFactory df = dfm.getDestinationFactoryForUri(uri);
346 if (df == null)
347 {
348 throw new Exception("Could not find a destination factory for uri " + uri);
349 }
350
351 Destination dest = df.getDestination(ei);
352 MessageObserver mo = dest.getMessageObserver();
353 if (mo instanceof ChainInitiationObserver)
354 {
355 ChainInitiationObserver cMo = (ChainInitiationObserver) mo;
356 Endpoint cxfEP = cMo.getEndpoint();
357
358 client = new ClientImpl(bus, cxfEP);
359 }
360 else
361 {
362 throw new Exception("Could not create client! No Server was found directly on the endpoint: "
363 + uri);
364 }
365 }
366
367 protected void addMuleInterceptors()
368 {
369 client.getInInterceptors().add(new MuleHeadersInInterceptor());
370 client.getInFaultInterceptors().add(new MuleHeadersInInterceptor());
371 client.getOutInterceptors().add(new MuleHeadersOutInterceptor());
372 client.getOutFaultInterceptors().add(new MuleHeadersOutInterceptor());
373 client.getOutInterceptors().add(new MuleProtocolHeadersOutInterceptor());
374 client.getOutFaultInterceptors().add(new MuleProtocolHeadersOutInterceptor());
375 }
376
377 protected String getMethodOrOperationName(MuleEvent event) throws DispatchException
378 {
379
380 String method = (String) event.getMessage().getProperty(MuleProperties.MULE_METHOD_PROPERTY);
381
382 if (method == null)
383 {
384 method = (String) event.getMessage().getProperty(CxfConstants.OPERATION);
385 }
386
387 if (method == null)
388 {
389 method = defaultMethodName;
390 }
391
392 if (method == null && proxy)
393 {
394 return "invoke";
395 }
396
397 if (method == null)
398 {
399 throw new DispatchException(SoapMessages.cannotInvokeCallWithoutOperation(), event.getMessage(),
400 event.getEndpoint());
401 }
402
403 return method;
404 }
405
406 public void setEndpoint(ImmutableEndpoint endpoint)
407 {
408 this.endpoint = endpoint;
409 }
410
411 public void setBus(Bus bus)
412 {
413 this.bus = bus;
414 }
415
416 public boolean isClientProxyAvailable()
417 {
418 return clientProxy != null;
419 }
420
421 public BindingOperationInfo getOperation(MuleEvent event) throws Exception
422 {
423 String opName = getMethodOrOperationName(event);
424
425 if (opName == null)
426 {
427 opName = defaultMethodName;
428 }
429
430 return getOperation(opName);
431 }
432
433 public Method getMethod(MuleEvent event) throws Exception
434 {
435 Method method = defaultMethod;
436 if (method == null)
437 {
438 String opName = (String) event.getMessage().getProperty(CxfConstants.OPERATION);
439 if (opName != null)
440 {
441 method = getMethodFromOperation(opName);
442 }
443
444 if (method == null)
445 {
446 opName = (String) endpoint.getProperty(CxfConstants.OPERATION);
447 if (opName != null)
448 {
449 method = getMethodFromOperation(opName);
450 }
451 }
452
453 if (method == null)
454 {
455 opName = defaultMethodName;
456 if (opName != null)
457 {
458 method = getMethodFromOperation(opName);
459 }
460 }
461 }
462
463 if (method == null)
464 {
465 throw new DispatchException(CxfMessages.noOperationWasFoundOrSpecified(), event.getMessage(),
466 endpoint);
467 }
468 return method;
469 }
470 }