Ksoap2 - Android Build SOAP Request with Multiple Namespace definitions - java

I am building SOAP Request Message using KSoap2-android version 3.3.0
My second namespace for Element 'n1' not added even though i added it with
SoapEnvelope.setMapping()
<in1 xmlns:n1="http://event.api.company.com">
.....
I am expecting the Request Message (CORRECT) in this Format:
<v:Envelope xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns:d="http://www.w3.org/2001/XMLSchema" xmlns:c="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:v="http://schemas.xmlsoap.org/soap/envelope/">
<v:Header/>
<v:Body>
<updateStatus xmlns="http://service.api.company.com"
id="o0" c:root="1">
<in0>1604509</in0>
<in1 xmlns:n1="http://event.api.company.com">
<n1:actionDate>2014-09-02T05:18:20.156+0000</n1:actionDate>
<n1:ActionTypeDTO>
<n1:id>1</n1:id>
<n1:name>Other</n1:name>
<n1:description>Enter the description of the action taken.</n1:description>
</n1:ActionTypeDTO>
<n1:description>notes1</n1:description>
<n1:name>system</n1:name>
</in1>
<in2>NEW</in2>
</updateStatus>
</v:Body>
But i am getting This (WRONG) after Ksoap build the Message:
<v:Envelope xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns:d="http://www.w3.org/2001/XMLSchema" xmlns:c="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:v="http://schemas.xmlsoap.org/soap/envelope/">
<v:Header/>
<v:Body>
<updateStatus xmlns="http://service.api.company.com"
id="o0" c:root="1">
<in0>1604509</in0>
<in1>
<actionDate>2014-09-02T05:18:20.156+0000</actionDate>
<ActionTypeDTO>
<id>1</id>
<name>Other</name>
<description>Enter the description of the action taken.</description>
</ActionTypeDTO>
<description>notes1</description>
<name>system</name>
</in1>
<in2>NEW</in2>
</updateStatus>
</v:Body>
This is my Function using KSOAP2-Android API:
public void updateStatus(long in0, ActionDTO in1){
SoapSerializationEnvelope soapEnvelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
soapEnvelope.implicitTypes = true;
soapEnvelope.dotNet = true;
SoapObject soapReq = new SoapObject("http://service.api.company.com","updateEventStatus");
soapEnvelope.addMapping("http://event.api.company.com","in1",new ActionDTO().getClass());
soapReq.addProperty("in0",in0);
soapReq.addProperty("in1",in1);
soapEnvelope.setOutputSoapObject(soapReq);
HttpTransportSE httpTransport = new HttpTransportSE(url,timeOut);
httpTransport.call("http://service.api.company.com/updateEventStatus",
soapEnvelope);
}
See following was not added in the Soap request:
<in1 xmlns:n1="http://event.api.company.com">
<n1:actionDate>2014-09-02T05:18:20.156+0000</n1:actionDate>
.....
.......
.....
Can Anybody help me what i am doing wrong... soapEnvelope.addMapping() function
seems not working correctly. OR am i missing something setting or flag to tell KSOAP??
I removed some code to make it clean to understand, sorry for that....
Thanks in advance for the Help ...

some how figured out to solve the issue for now.
It might be Useful if somebody using 'Wsdl2Code' to generate Java Code as I am.
(WSDL2CODE.com engine will generate the classes and methods for connecting Soap Services From Android and iPhone!)
In the Wsdl2code generated DTO Classes change the following:
public void getPropertyInfo(int index,
#SuppressWarnings("rawtypes") Hashtable arg1, PropertyInfo info) {
switch (index) {
case 0:
**info.namespace = "http://event.api.company.com";**
info.type = PropertyInfo.STRING_CLASS;
info.name = "id";
break;
case 1:
**info.namespace = "http://event.api.company.com";**
info.type = PropertyInfo.STRING_CLASS;
info.name = "name";
break;
}
}
Then it will generate the SOAP Request as i mentioned in the Question (CORRECT).

Related

SOAP XML request for initializing an Object value in JAVA Class

I am having the below JAVA Class :
#WebService()
#SOAPBinding(style = Style.DOCUMENT, use = Use.LITERAL, parameterStyle = ParameterStyle.BARE)
public class Demo extends JaxWsWebService
{
#WebMethod(operationName = "createMethod")
#WebResult(targetNamespace = "xyz.com/")
#RequestWrapper(localName = "Testing", targetNamespace = "xyz.com/", className = "com.Test")
public void createMethod(Testing testingData) throws SOAPException {
System.out.println(" createMethod service --- xId = " + testingData.getXId() "); // xId is coming as NULL
System.out.println(" createMethod service --- name = " + testingData.getName() "); // name is coming as NULL
}
}
Now I am calling the above JAVA method using my SOAP XML Request which is below :
<x:Envelope xmlns:x="http://schemas.xmlsoap.org/soap/envelope/" xmlns:NS1="xyz.com/">
<x:Header/>
<x:Body>
<NS1:createMethod>
<NS1:Testing>
<xId>12345</xId>
<name>abcd</name>
</NS1:Testing>
</NS1:createMethod>
</x:Body>
</x:Envelope>
Now, when I am calling the SOAP request using the SOAP client, the call is successful and is going inside the JAVA method but the main issue is the "testingData" instance of "Testing" class is not getting initialized.
Due to this, I am getting the value of 'xId' and 'name' variable as NULL in my JAVA method. Any suggestions on this would be helpful it looks like I am making mistake in my SOAP request calling but unable to figure it out.
Please suggest. TIA
Got the place where I was going wrong :
<x:Envelope xmlns:x="http://schemas.xmlsoap.org/soap/envelope/" xmlns:NS1="xyz.com/">
<x:Header/>
<x:Body>
<NS1:createMethod>
<xId>12345</xId>
<name>abcd</name>
</NS1:createMethod>
</x:Body>
</x:Envelope>
In the XML request , I removed the <NS1:Testing> starting and ending </NS1:Testing> tags and finally it started working for me.

Transforming JSON body using WSO2 class mediator

Following is the log of my current json body. And I want to add new property to this body. "NewPropertyName": "value". Since the value is in a database I am using a class mediator to add this property.
[2015-05-18 05:47:08,730] INFO - LogMediator To: /a/create-project, MessageID: urn:uuid:b7b6efa6-5fff-49be-a94a-320cee1d4406, Direction: request, _______BODY_______ =
{
"token": "abc123",
"usertype":"ext",
"request": "create"
}
Class mediator's mediate method,
public boolean mediate(MessageContext mc) {
mc.setProperty("key", "vale retrived from db");
return true;
}
but this doesn't work as I expected. I couldn't find any guide to add property to json body using class mediator, please help.
To inject a property to the body you have to use following code snippet,
JsonUtil.newJsonPayload(
((Axis2MessageContext) context).getAxis2MessageContext(),
transformedJson, true, true);
inside a class mediator. Following is an example of mediate method.
/**
* Mediate overridden method to set the token property.
*/#Override
public boolean mediate(MessageContext context) {
try {
// Getting the json payload to string
String jsonPayloadToString = JsonUtil.jsonPayloadToString(((Axis2MessageContext) context)
.getAxis2MessageContext());
// Make a json object
JSONObject jsonBody = new JSONObject(jsonPayloadToString);
// Adding the name:nameParam.
jsonBody.put("name", getNameParam());
String transformedJson = jsonBody.toString();
// Setting the new json payload.
JsonUtil.newJsonPayload(
((Axis2MessageContext) context).getAxis2MessageContext(),
transformedJson, true, true);
System.out.println("Transformed JSON body:\n" + transformedJson);
} catch (Exception e) {
System.err.println("Error occurred: " + e);
return false;
}
return true;
}
You will need json and other libraries for this. This is fully explained in following blog post.
json-support-for-wso2-esb-class-mediator
mc.setProperty is used to create a new property as if you were using property mediator.
If you want to add a new element inside your message, in java, you can handle it as if it were a XML message (for exemple, to get the first element :
OMElement element = (OMElement) context.getEnvelope().getBody().getFirstOMChild(); )
Sample to add a new element with a javascript :
<script language="js"><![CDATA[
var payloadXML = mc.getPayloadXML();
payloadXML.appendChild(new XML(<NewPropertyName>value</NewPropertyName>));
mc.setPayloadXML(payloadXML);
]]></script>
Log the message in XML with <log level="full"> and you get :
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<jsonObject>
<token>abc123</token>
<usertype>ext</usertype>
<request>create</request>
<NewPropertyName>value</NewPropertyName>
</jsonObject>
</soapenv:Body>
</soapenv:Envelope>
Log the message in JSON with
<log>
<property name="JSON-Payload" expression="json-eval($.)"/>
</log>
and you get :
JSON-Payload = {"token":"abc123","usertype":"ext","request":"create","NewPropertyName":"value"}

Adding custom HTTP headers to Axis 1.4 web service responses

I'm trying to add custom HTTP headers to Axis 1.4 web servers.
I've created a handler which extends BasicHandler:
public class HttpHeaderHandler extends BasicHandler {
.
.
.
#Override
public void invoke(org.apache.axis.MessageContext arg0) throws AxisFault {
LOG.trace("invoke called");
Hashtable ht = (Hashtable)ctx.getProperty(HTTPConstants.RESPONSE_HEADERS);
if(ht == null) {
ht = new Hashtable();
}
ht.put("custom-header", "Hello");
ctx.setProperty(HTTPConstants.RESPONSE_HEADERS, ht);
}
.
.
.
}
I've added the following to server-config.wsdd:
.
.
.
<transport name="http">
<requestFlow>
<handler type="URLMapper" />
<handler type="java:org.apache.axis.handlers.http.HTTPAuthHandler" />
</requestFlow>
<responseFlow>
<handler type="java:com.my.package.HttpHeaderHandler" />
</responseFlow>
</transport>
.
.
.
I can see that the invoke method is being called as the logging is appearing in the log file but the custom header is not being added to the response.
Any suggestions appreciated.
I was able to do this on a org.apache.axis.Stub instance by doing the following:
private Stub setHeaders(Stub stub, Hashtable<String, String> headers){
stub._setProperty(HTTPConstants.REQUEST_HEADERS, headers);
return stub;
}
Note that it is REQUIRED that the value argument to _setProperty() be a java.util.Hashtable (it gets cast later on by Axis when the Stub is used)
I added apikey for request header thanks for #romeara answer here . And it works.
Axis 1.4 sending client request from java.
YourStub stub = new YourStub();
Hashtable<String, String> headers = new Hashtable<String, String>();
headers.put("apikey", "xxxxxxxxxxxxxxxxxxxx");
stub._setProperty(HTTPConstants.REQUEST_HEADERS, headers);
I remember using the stub files generated to add HTTP user and password, check this link and locate the code that says:
_call.setProperty(org.apache.axis.client.Call.SEND_TYPE_ATTR, Boolean.FALSE);
http://www.coderanch.com/t/225102/Web-Services/java/Axis-username-password-auth-stubs
That kind of modification works.
This is what we have done
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPException;
/**
* This method is to be used for secure SOAP calls.
* Method created as Axis 1.4 strips the security header which compiling the Java classes.
* #param username
* #param password
* #return SOAP Header
* #throws SOAPException
*/
public static SOAPHeaderElement createCustomSOAPHeader(String username, String password) throws SOAPException {
SOAPHeaderElement oHeaderElement;
SOAPElement oElement;
//Header
oHeaderElement = new SOAPHeaderElement("http://siebel.com/webservices", "Security");
oHeaderElement.setPrefix("web");
oHeaderElement.setMustUnderstand(false);
//Elements for the Header
oElement = oHeaderElement.addChildElement("UsernameToken");
oElement.addTextNode(username);
oElement = oHeaderElement.addChildElement("PasswordText");
oElement.addTextNode(password);
oElement = oHeaderElement.addChildElement("SessionType");
oElement.addTextNode("None");
return oHeaderElement;
}
Hope this helps.

ksoap2 nested items with similar namespace but different types

This is how the request envelope should look like:
<v:Envelope xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:d="http://www.w3.org/2001/XMLSchema" xmlns:c="http://schemas.xmlsoap.org/soap/encoding/" xmlns:v="http://schemas.xmlsoap.org/soap/envelope/">
<v:Header />
<v:Body>
<getLijst xmlns="http://OAM/OMZETAPPMETHODS.xsd">
<selectie i:type="n1:OAM_ArtstructselobjUser" xmlns:n1="http://OAM/OMZETAPPMETHODS.xsd">
<filiaal i:type="d:decimal">4</filiaal>
<artnivsel i:type="n1:OAM_ArtstructobjUser">
<asonummer i:type="d:decimal">1</asonummer>
<asotype i:type="d:string">P</asotype>
</artnivsel>
</selectie>
</getLijst>
</v:Body>
</v:Envelope>
And this is a part of my code:
String nameSpace = "http://OAM/OMZETAPPMETHODS.xsd";
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet = true;
envelope.setAddAdornments(false);
SoapObject request = new SoapObject(nameSpace, _soapMethod);
OAM_ArtstructselobjUser obj = new OAM_ArtstructselobjUser();
// .. This is where the properties are added, irrelevant
request.addProperty("selectie", obj);
OAM_ArtstructobjUser obj2 = new OAM_ArtstructobjUser();
// .. This is where the properties are added, irrelevant
request.addProperty("artnivsel", obj2);
envelope.setOutputSoapObject(request);
Marshal floatMarshal = new MarshalFloat();
floatMarshal.register(envelope);
envelope.addMapping(nameSpace, "OAM_ArtstructselobjUser", OAM_ArtstructselobjUser.class);
envelope.addMapping(nameSpace, "OAM_ArtstructobjUser", OAM_ArtstructobjUser.class);
So I want artnivsel to have a custom type, but inherits the namespace of selectie.
If I run the above code i get an 05-07 14:22:21.034: ERROR/AndroidRuntime(16417): Caused by: java.lang.RuntimeException: Unknown Property: asotype
If I change the nameSpace of the second addMapping to anything else, my code runs fine. But my envelope XML isn't correct. anymore.
Anyone who can give me a pointer, I'm not that experienced with ksoap2 or soap in particular.
Okay looks like updating to ksoap2.6.4 fixes this.
Just add avoidExceptionForUnknownProperty to true on the SoapSerializationEnvelope

WSSE (with digest) in WCF\.Net\C# - An easy way?

Disclaimer: .Net N00b
I've been beating my head against the wall for a couple of days now trying to get the security work with this external vendors web service to no avail. It turns out that they use WSSE digest security, which, in short, adds something like this to the SOAP header:
<wsse:UsernameToken wsu:Id="Example-1">
<wsse:Username> ... </wsse:Username>
<wsse:Password Type="..."> ... </wsse:Password>
<wsse:Nonce EncodingType="..."> ... </wsse:Nonce>
<wsu:Created> ... </wsu:Created>
</wsse:UsernameToken>
I started out by adding the service reference, and through many, many blog posts, stackoverflow questions fiddling with the app.config and the code. I just couldn't seem to get it right. Maybe it isn't easily possible? Maybe I just don't know Visual Studio 2010 and .Net that well, I'm not sure.
Here is what I stopped with in my app.config:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="ServiceHttpBinding" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="TransportWithMessageCredential" />
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://vendorurl"
binding="basicHttpBinding" bindingConfiguration="ServiceHttpBinding"
contract="ContractName"
name="ServiceHttpPort">
</endpoint>
</client>
</system.serviceModel>
And the C#:
var someService = new ServiceClient();
someService.ClientCredentials.UserName.UserName = "username";
someService.ClientCredentials.UserName.Password = "passwordgobbletygook/somemorebase64stuff=";
#region Begin Magic
var elements = someService.Endpoint.Binding.CreateBindingElements();
var securityBindingElement = elements.Find<SecurityBindingElement>();
securityBindingElement.IncludeTimestamp = false;
someService.Endpoint.Binding = new CustomBinding(elements);
#endregion
var response = someService.webMethod(param1, param2, param3, param4);
Console.WriteLine(response);
The funny thing is, in the vendors spec, I found that they encourage the use of WSSJ, so I tried it out (in java) and I GOT IT TO WORK IN 2 HOURS
Here is what that looks like:
public class Test implements CallbackHandler {
/**
* #param args
*/
public static void main( final String[] args ) throws Throwable {
SomeService_Service someService_Service = new SomeService_Service();
SomeService someService = someService_Service.getSomeServiceHttpPort();
BindingProvider bindingProvider = (BindingProvider)someService;
Map< String, Object > requestContext = bindingProvider.getRequestContext();
requestContext.put( BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "https://vendorurl" );
Client client = ClientProxy.getClient( someService );
Endpoint endpoint = client.getEndpoint();
Map< String, Object > outProps = new HashMap< String, Object >();
outProps.put( WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN );
outProps.put( WSHandlerConstants.USER, "username" );
outProps.put( WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_DIGEST );
outProps.put( WSHandlerConstants.PW_CALLBACK_REF, new Test() );
WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor( outProps );
endpoint.getOutInterceptors().add( wssOut );
System.out.println( someService.webMethod(param1, param2, param3, param4) );
}
public void handle( final Callback[] callbacks ) throws IOException, UnsupportedCallbackException {
WSPasswordCallback pc = (WSPasswordCallback)callbacks[ 0 ];
// set the password for our message.
pc.setPassword( "passwordgobbletygook/somemorebase64stuff=" );
}
}
Has anyone out there in stackoverflow land got this to work in .Net\C#? Is there something obvious I'm missing here?
We've run into this problem before when trying to connect a .NET based component to a JAVA based SOAP service. Our solution doesn't involve any XML construction and is IMHO a bit cleaner than anything else I've seen.
The downside is that you need to download and include an older optional .NET DLL to make it work. The upside is that the code is quite clean and fits naturally into WCF.
The basic implementation looks something like this:
using (OperationContextScope scope = new OperationContextScope(client.InnerChannel))
{
//Class from WSE 3.0
UsernameToken token = new UsernameToken("MY_USERNAME", "MY_PASSWORD", PasswordOption.SendHashed);
//Add Auth to SOAP Header
MessageHeader header
= MessageHeader.CreateHeader(
"Security",
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
token.GetXml(new XmlDocument())
);
OperationContext.Current.OutgoingMessageHeaders.Add(header);
//Build Request
OrgWS.OrganizationDetailsRequest request = new OrgWS.OrganizationDetailsRequest()
{
ID = 1
};
//Send Request
OrgWS.OrganizationDetail[] response = client.getOrganizationDetail(request);
//Do something with response
}
A full explanation can be found here: http://cxdeveloper.com/article/implementing-ws-security-digest-password-nonce-net-40-wcf
Andy's answer is spot on! Spent most of the say on this, there is a lot out there but this is the ONLY answer that worked for me. Perfect for adding nonce with passwordDigest in SOAP wsse headers. Agree with Nick V, this answer should get more recognition.
BasicHttpBinding myBinding = new BasicHttpBinding();
myBinding.Security.Mode = BasicHttpSecurityMode.Transport;
myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
EndpointAddress ea = new EndpointAddress("****");
WebServiceServiceClient cc = new WebServiceServiceClient(myBinding, ea);
cc.Open();
using (OperationContextScope scope = new OperationContextScope(cc.InnerChannel))
{
//Class from WSE 3.0
UsernameToken token = new UsernameToken("userid", "password", PasswordOption.SendHashed);
//Add Auth to SOAP Header
MessageHeader header
= MessageHeader.CreateHeader(
"Security",
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
token.GetXml(new XmlDocument())
);
OperationContext.Current.OutgoingMessageHeaders.Add(header);
try
{
//call SOAP methos
}
catch (Exception ex)
{
//catch any errors
}
}

Categories