Hi,

There are many complexities when trying to implement a SOAP client using
the dynamic client capability of Apache CXF. I was able to provide a
workaround for the error which occurred when passing parameters to a SOAP
operation with Apache CXF .

The workaround provided does not work with WSDLs which have complex types
as the request or response message type  i.e. the request/response message
parts of the WSDL can be primitive or complex, so 2 different approaches
should be followed to get/set the values of the primitive and complex types
respectively. When having complex types, the message part is iterated over
multiple times, which will take more processing time and reduce the
performance.

The approach I used is described below. By using this approach the
JaxWsDynamicClientFactory takes care of generating Java classes for complex
types :

Create a new instance of the Client using the JaxWsDynamicClientFactory by
passing the wsdl url. The url of the WSDL, operation name and the input
variables is provided by the user.





*JaxWsDynamicClientFactory factory =
JaxWsDynamicClientFactory.newInstance();URL wsdlURL = new
URL("http://localhost:9763/services/DivisionProcessService?wsdl
<http://10.100.4.192:9763/services/DivisionProcessService?wsdl>");String
operationName = "process";Client client =
factory.createClient(wsdlURL.toExternalForm());ClientImpl clientImpl =
(ClientImpl) client;*

Get the endpoint i.e. the URL where the web service can be accessed by a
client application using the cilent.

*Endpoint endpoint = clientImpl.getEndpoint();*

Get the target namespace of the WSDL by creating a ServiceInfo object which
walks over the CXF service model

*ServiceInfo serviceInfo = endpoint.getService().getServiceInfos().get(0);*
*String targetNameSpace = serviceInfo.getTargetNamespace();*

Get the binding name of the WSDL by creating a BindingInfo object which
gets the name of the binding.

*BindingInfo bindingInfo = serviceInfo.getBindings().iterator().next();*
*String bName = bindingInfo.getName().getLocalPart();*

Create a Qname by passing the namespace and the binding name as parameters
and get the binding which has the specified QName.

*QName bindingName = new QName(targetNameSpace, bName);*
*BindingInfo binding = serviceInfo.getBinding(bindingName);*

Get details about the soap operation which is to be invoked by creating a
QName with the namespace and the operation name.

*QName opName = new QName(targetNameSpace, operationName);*
*BindingOperationInfo boi = binding.getOperation(opName);*

Get the input/request message type
*BindingMessageInfo inputMessageInfo = boi.getInput();*
*List<MessagePartInfo> parts = inputMessageInfo.getMessageParts();*
*MessagePartInfo partInfo = parts.get(0);*

Get the  class type of the request/input message and dynamically create an
instance of it
*Class<?> partClass = partInfo.getTypeClass();*
*Object obj = partClass.newInstance();*

The input variables provided by the user is stored inside a  HashTable
which will hold the variable name and its value as a key-value pair

*Hashtable table = new Hashtable();*
*table.put("dividend", 40);*
*table.put("divisor", 10);*

Get the methods from the generated request class. This class will have
getter and setter methods for the variables taken as the input/request.

*Method [] methods = obj.getClass().getDeclaredMethods();*
*for(Method m : methods){*
* if(m.getName().contains("set")){*
* String methodName = m.getName(); *
* Class<?> paramType = m.getParameterTypes()[0];*
* String[] output = methodName.split("set");*
* String varName = output[1].toLowerCase(); *
* Object value = table.get(varName); *
* Method m1 = obj.getClass().getMethod(methodName, paramType); *
* m1.invoke(obj, value);*
* } else {*
* }*
*}*

Invoking the operation
*Object[] response = client.invoke(operationName, obj);*

Get the methods from the generated response class. This class will have getter
and setter methods for the variables given as the output.

*Method [] responseMethods = response[0].getClass().getDeclaredMethods();*
*for(Method rm : responseMethods){*
* if(rm.getName().contains("get")){*
* String responseMethod = rm.getName();*
* Object result =
response[0].getClass().getMethod(responseMethod).invoke(response[0]);*
* System.**out**.println("Response: " + result);*
* } else {*
* }*
*}*

Is this approach correct or is there any way to overcome these limitations
when using CXF ?

Any suggestions and feedback are highly appreciated.

Best Regards,

Natasha Wijesekare

On Thu, Mar 17, 2016 at 4:47 PM, Natasha Wijesekara <[email protected]>
wrote:

> Hi ,
>
> I tried passing the operation name with the namespace but it didn't work.
> I get the same exception as below.
>
> *java.lang.IllegalArgumentException: Part
> {http://wso2.org/wso2con/2011/sample/adder}payload
> <http://wso2.org/wso2con/2011/sample/adder%7Dpayload> should be of type
> org.wso2.wso2con._2011.sample.adder.AdderProcessRequest, not
> java.lang.Integer*
> * at
> org.apache.cxf.jaxb.io.DataWriterImpl.checkPart(DataWriterImpl.java:284)*
> * at org.apache.cxf.jaxb.io.DataWriterImpl.write(DataWriterImpl.java:212)*
> * at
> org.apache.cxf.interceptor.AbstractOutDatabindingInterceptor.writeParts(AbstractOutDatabindingInterceptor.java:122)*
> * at
> org.apache.cxf.interceptor.BareOutInterceptor.handleMessage(BareOutInterceptor.java:68)*
> * at
> org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:272)*
> * at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:572)*
> * at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:481)*
> * at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:382)*
> * at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:335)*
> * at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:355)*
> * at cxfClient_1.main(cxfClient_1.java:61)*
> * at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)*
> * at
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)*
> * at
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)*
> * at java.lang.reflect.Method.invoke(Method.java:606)*
> * at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)*
>
> Best Regards,
> Natasha Wijesekare
>
> On Thu, Mar 17, 2016 at 3:39 PM, Himasha Guruge <[email protected]> wrote:
>
>> Hi Natasha,
>>
>> Can you try passing the operation name with the namespace as well?
>>
>> Regards,
>> Himasha
>>
>> On Thu, Mar 17, 2016 at 2:16 PM, Natasha Wijesekara <[email protected]>
>> wrote:
>>
>>> Hi,
>>>
>>> I'm trying to invoke an external soap service operation which takes
>>> integers as the parameters.
>>>
>>> *Request Body of the Soap Service *:
>>>
>>> *<soapenv:Envelope
>>> xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/
>>> <http://schemas.xmlsoap.org/soap/envelope/>"
>>> xmlns:add="http://wso2.org/wso2con/2011/sample/adder
>>> <http://wso2.org/wso2con/2011/sample/adder>">*
>>> *   <soapenv:Header/>*
>>> *   <soapenv:Body>*
>>> *      <add:AdderProcessRequest>*
>>> *         <add:a>?</add:a>*
>>> *         <add:b>?</add:b>*
>>> *      </add:AdderProcessRequest>*
>>> *   </soapenv:Body>*
>>> *</soapenv:Envelope>*
>>>
>>> I have created a client to invoke the soap operation using
>>> JaxWsDynamicClientFactory.
>>> JaxWsDynamicClientFactory clientFactory =
>>> JaxWsDynamicClientFactory.newInstance();
>>>
>>> I have invoked the operation by passing the operation name and the
>>> parameters to the client.
>>> When multiple parameters of type *string* is passed, no error is given.
>>>
>>> In this request I need to pass 2 *integers* as the parameters as shown
>>> below :
>>> client.invoke("operationName", num1, num2);
>>> But when I do so I get the following error :
>>>
>>> *java.lang.IllegalArgumentException: Part
>>> {http://wso2.org/wso2con/2011/sample/adder}payload
>>> <http://wso2.org/wso2con/2011/sample/adder%7Dpayload> should be of type
>>> org.wso2.wso2con._2011.sample.adder.AdderProcessRequest, not
>>> java.lang.Integer*
>>> * at
>>> org.apache.cxf.jaxb.io.DataWriterImpl.checkPart(DataWriterImpl.java:284)*
>>> * at
>>> org.apache.cxf.jaxb.io.DataWriterImpl.write(DataWriterImpl.java:212)*
>>> * at
>>> org.apache.cxf.interceptor.AbstractOutDatabindingInterceptor.writeParts(AbstractOutDatabindingInterceptor.java:122)*
>>> * at
>>> org.apache.cxf.interceptor.BareOutInterceptor.handleMessage(BareOutInterceptor.java:68)*
>>> * at
>>> org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:272)*
>>> * at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:572)*
>>> * at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:481)*
>>> * at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:382)*
>>> * at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:335)*
>>> * at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:355)*
>>> * at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:341)*
>>>
>>>  Appreciate any help on this.
>>>
>>> Best Regards,
>>> *Natasha Wijesekare*
>>>
>>> *Software Engineering Intern, WSO2  Inc:  http://wso2.com
>>> <http://wso2.com/>*
>>> *email  : [email protected] <[email protected]>*
>>> *mobile: +94 771358651 <%2B94%20771358651>*
>>>
>>> _______________________________________________
>>> Dev mailing list
>>> [email protected]
>>> http://wso2.org/cgi-bin/mailman/listinfo/dev
>>>
>>>
>>
>>
>> --
>> Himasha Guruge
>> *Software Engineer*
>> WS*O2* *Inc.*
>> Mobile: +94 777459299
>> [email protected]
>>
>
>
>
> --
> *Natasha Wijesekare*
>
> *Software Engineering Intern, WSO2  Inc:  http://wso2.com
> <http://wso2.com/>*
> *email  : [email protected] <[email protected]>*
> *mobile: +94 771358651 <%2B94%20771358651>*
>



-- 
*Natasha Wijesekare*

*Software Engineering Intern, WSO2  Inc:  http://wso2.com
<http://wso2.com/>*
*email  : [email protected] <[email protected]>*
*mobile: +94 771358651 <%2B94%20771358651>*
_______________________________________________
Dev mailing list
[email protected]
http://wso2.org/cgi-bin/mailman/listinfo/dev

Reply via email to